authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-11-01 00:03:02-04:00
committergravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-11-01 05:28:03-04:00
logf0260555d6164642569af9e09f57458a938d5de1
treea50a306de8edb6cf7712c702508d9659b085ccdd
parenta0bf620fbfcdc9435c4a06842ab6270fb720c3e1

astgen.zig: simplify switchExpr and collect payload in one ArrayList instead of three


1 files changed, 100 insertions(+), 262 deletions(-)

src/AstGen.zig+100-262
......@@ -6029,16 +6029,15 @@ fn switchExpr(
60296029 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node);
60306030 const item_rl: ResultLoc = .{ .ty = cond_ty_inst };
60316031
6032 // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti.
6033 // This is the optional else prong body.
6034 var special_case_payload = ArrayListUnmanaged(u32){};
6035 defer special_case_payload.deinit(gpa);
6036 // This is all the scalar cases.
6037 var scalar_cases_payload = ArrayListUnmanaged(u32){};
6038 defer scalar_cases_payload.deinit(gpa);
6039 // Same deal, but this is only the `extra` data for the multi cases.
6040 var multi_cases_payload = ArrayListUnmanaged(u32){};
6041 defer multi_cases_payload.deinit(gpa);
6032 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
6033 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with
6034 // the special case index coming first, then scalar_case_len indexes, then multi_cases_len indexes
6035 var payloads = ArrayListUnmanaged(u32){};
6036 defer payloads.deinit(gpa);
6037 const scalar_case_table: u32 = @boolToInt(special_prong != .none);
6038 const multi_case_table = scalar_case_table + scalar_cases_len;
6039 const case_table_len = multi_case_table + multi_cases_len;
6040 try payloads.resize(gpa, case_table_len);
60426041
60436042 var block_scope = parent_gz.makeSubBlock(scope);
60446043 block_scope.setBreakResultLoc(rl);
......@@ -6069,13 +6068,6 @@ fn switchExpr(
60696068
60706069 var capture_val_scope: Scope.LocalVal = undefined;
60716070 const sub_scope = blk: {
6072 const capture_index = if (is_multi_case) ci: {
6073 multi_case_index += 1;
6074 break :ci multi_case_index - 1;
6075 } else ci: {
6076 scalar_case_index += 1;
6077 break :ci scalar_case_index - 1;
6078 };
60796071 const payload_token = case.payload_token orelse break :blk &case_scope.base;
60806072 const ident = if (token_tags[payload_token] == .asterisk)
60816073 payload_token + 1
......@@ -6109,6 +6101,7 @@ fn switchExpr(
61096101 0b10 => .switch_capture_multi,
61106102 0b11 => .switch_capture_multi_ref,
61116103 };
6104 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index;
61126105 break :capture try case_scope.add(.{
61136106 .tag = capture_tag,
61146107 .data = .{ .switch_capture = .{
......@@ -6129,10 +6122,11 @@ fn switchExpr(
61296122 break :blk &capture_val_scope.base;
61306123 };
61316124
6132 if (is_multi_case) {
6133 // items_len, ranges_len, body_len
6134 const header_index = multi_cases_payload.items.len;
6135 try multi_cases_payload.resize(gpa, multi_cases_payload.items.len + 3);
6125 const header_index = @intCast(u32, payloads.items.len);
6126 const body_len_index = if (is_multi_case) blk: {
6127 payloads.items[multi_case_table + multi_case_index] = header_index;
6128 multi_case_index += 1;
6129 try payloads.resize(gpa, header_index + 3); // items_len, ranges_len, body_len
61366130
61376131 // items
61386132 var items_len: u32 = 0;
......@@ -6141,7 +6135,7 @@ fn switchExpr(
61416135 items_len += 1;
61426136
61436137 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
6144 try multi_cases_payload.append(gpa, @enumToInt(item_inst));
6138 try payloads.append(gpa, @enumToInt(item_inst));
61456139 }
61466140
61476141 // ranges
......@@ -6152,57 +6146,43 @@ fn switchExpr(
61526146
61536147 const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs);
61546148 const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs);
6155 try multi_cases_payload.appendSlice(gpa, &[_]u32{
6149 try payloads.appendSlice(gpa, &[_]u32{
61566150 @enumToInt(first), @enumToInt(last),
61576151 });
61586152 }
61596153
6160 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6161 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6162 if (!parent_gz.refIsNoReturn(case_result)) {
6163 block_scope.break_count += 1;
6164 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6165 }
6166
6167 multi_cases_payload.items[header_index + 0] = items_len;
6168 multi_cases_payload.items[header_index + 1] = ranges_len;
6169 multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len);
6170 try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items);
6171 } else if (case_node == special_node) {
6172 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6173 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6174 if (!parent_gz.refIsNoReturn(case_result)) {
6175 block_scope.break_count += 1;
6176 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6177 }
6178 try special_case_payload.ensureUnusedCapacity(gpa, 1 + // body_len
6179 case_scope.instructions.items.len);
6180 special_case_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
6181 special_case_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
6182 } else {
6154 payloads.items[header_index] = items_len;
6155 payloads.items[header_index + 1] = ranges_len;
6156 break :blk header_index + 2;
6157 } else if (case_node == special_node) blk: {
6158 payloads.items[0] = header_index;
6159 try payloads.resize(gpa, header_index + 1); // body_len
6160 break :blk header_index;
6161 } else blk: {
6162 payloads.items[scalar_case_table + scalar_case_index] = header_index;
6163 scalar_case_index += 1;
6164 try payloads.resize(gpa, header_index + 2); // item, body_len
61836165 const item_node = case.ast.values[0];
61846166 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
6185 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6186 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6187 if (!parent_gz.refIsNoReturn(case_result)) {
6188 block_scope.break_count += 1;
6189 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
6190 }
6191 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + // item + body_len
6192 case_scope.instructions.items.len);
6193 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));
6194 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
6195 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
6167 payloads.items[header_index] = @enumToInt(item_inst);
6168 break :blk header_index + 1;
6169 };
6170
6171 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
6172 try checkUsed(parent_gz, &case_scope.base, sub_scope);
6173 if (!parent_gz.refIsNoReturn(case_result)) {
6174 block_scope.break_count += 1;
6175 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
61966176 }
6177 payloads.items[body_len_index] = @intCast(u32, case_scope.instructions.items.len);
6178 try payloads.appendSlice(gpa, case_scope.instructions.items);
61976179 }
61986180 // Now that the item expressions are generated we can add this.
61996181 try parent_gz.instructions.append(gpa, switch_block);
62006182
62016183 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
62026184 @boolToInt(multi_cases_len != 0) +
6203 special_case_payload.items.len +
6204 scalar_cases_payload.items.len +
6205 multi_cases_payload.items.len);
6185 payloads.items.len - case_table_len);
62066186
62076187 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
62086188 .operand = cond,
......@@ -6215,62 +6195,58 @@ fn switchExpr(
62156195 },
62166196 });
62176197
6218 const zir_datas = astgen.instructions.items(.data);
6219 const zir_tags = astgen.instructions.items(.tag);
6220
6221 zir_datas[switch_block].pl_node.payload_index = payload_index;
6222
62236198 if (multi_cases_len != 0) {
62246199 astgen.extra.appendAssumeCapacity(multi_cases_len);
62256200 }
62266201
6227 const strat = rl.strategy(&block_scope);
6228 switch (strat.tag) {
6229 .break_operand => {
6230 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
6231 // `elide_store_to_block_ptr_instructions` will either be true,
6232 // or all prongs are noreturn.
6233 if (!strat.elide_store_to_block_ptr_instructions) {
6234 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items);
6235 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
6236 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
6237 return indexToRef(switch_block);
6238 }
6202 const zir_datas = astgen.instructions.items(.data);
6203 const zir_tags = astgen.instructions.items(.tag);
62396204
6240 // There will necessarily be a store_to_block_ptr for
6241 // all prongs, except for prongs that ended with a noreturn instruction.
6242 // Elide all the `store_to_block_ptr` instructions.
6205 zir_datas[switch_block].pl_node.payload_index = payload_index;
62436206
6244 // The break instructions need to have their operands coerced if the
6245 // switch's result location is a `ty`. In this case we overwrite the
6246 // `store_to_block_ptr` instruction with an `as` instruction and repurpose
6247 // it as the break operand.
6207 const strat = rl.strategy(&block_scope);
6208 for (payloads.items[0..case_table_len]) |start_index, table_index| {
6209 var body_len_index = start_index;
6210 var end_index = start_index;
6211 if (table_index < scalar_case_table) {
6212 end_index += 1;
6213 } else if (table_index < multi_case_table) {
6214 body_len_index += 1;
6215 end_index += 2;
6216 } else {
6217 body_len_index += 2;
6218 const items_len = payloads.items[start_index];
6219 const ranges_len = payloads.items[start_index + 1];
6220 end_index += 3 + items_len + 2 * ranges_len;
6221 }
62486222
6249 var extra_index: usize = 0;
6250 if (special_prong != .none) special_prong: {
6251 const body_len_index = extra_index;
6252 const body_len = special_case_payload.items[extra_index];
6253 extra_index += 1;
6254 if (body_len < 2) {
6255 extra_index += body_len;
6256 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6257 break :special_prong;
6258 }
6259 extra_index += body_len - 2;
6260 const store_inst = special_case_payload.items[extra_index];
6223 const body_len = payloads.items[body_len_index];
6224 end_index += body_len;
6225
6226 switch (strat.tag) {
6227 .break_operand => blk: {
6228 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
6229 // `elide_store_to_block_ptr_instructions` will either be true,
6230 // or all prongs are noreturn.
6231 if (!strat.elide_store_to_block_ptr_instructions)
6232 break :blk;
6233
6234 // There will necessarily be a store_to_block_ptr for
6235 // all prongs, except for prongs that ended with a noreturn instruction.
6236 // Elide all the `store_to_block_ptr` instructions.
6237
6238 // The break instructions need to have their operands coerced if the
6239 // switch's result location is a `ty`. In this case we overwrite the
6240 // `store_to_block_ptr` instruction with an `as` instruction and repurpose
6241 // it as the break operand.
6242 if (body_len < 2)
6243 break :blk;
6244 const store_inst = payloads.items[end_index - 2];
62616245 if (zir_tags[store_inst] != .store_to_block_ptr or
62626246 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
6263 {
6264 extra_index += 2;
6265 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6266 break :special_prong;
6267 }
6268 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
6247 break :blk;
6248 const break_inst = payloads.items[end_index - 1];
62696249 if (block_scope.rl_ty_inst != .none) {
6270 extra_index += 1;
6271 const break_inst = special_case_payload.items[extra_index];
6272 extra_index += 1;
6273 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
62746250 zir_tags[store_inst] = .as;
62756251 zir_datas[store_inst].bin = .{
62766252 .lhs = block_scope.rl_ty_inst,
......@@ -6278,168 +6254,30 @@ fn switchExpr(
62786254 };
62796255 zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
62806256 } else {
6281 special_case_payload.items[body_len_index] -= 1;
6282 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6283 extra_index += 1;
6284 astgen.extra.appendAssumeCapacity(special_case_payload.items[extra_index]);
6285 extra_index += 1;
6286 }
6287 } else {
6288 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]);
6289 }
6290 extra_index = 0;
6291 var scalar_i: u32 = 0;
6292 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
6293 const start_index = extra_index;
6294 extra_index += 1;
6295 const body_len_index = extra_index;
6296 const body_len = scalar_cases_payload.items[extra_index];
6297 extra_index += 1;
6298 if (body_len < 2) {
6299 extra_index += body_len;
6300 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
6257 payloads.items[body_len_index] -= 1;
6258 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index .. end_index - 2]);
6259 astgen.extra.appendAssumeCapacity(break_inst);
63016260 continue;
63026261 }
6303 extra_index += body_len - 2;
6304 const store_inst = scalar_cases_payload.items[extra_index];
6305 if (zir_tags[store_inst] != .store_to_block_ptr or
6306 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
6307 {
6308 extra_index += 2;
6309 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
6310 continue;
6311 }
6312 if (block_scope.rl_ty_inst != .none) {
6313 extra_index += 1;
6314 const break_inst = scalar_cases_payload.items[extra_index];
6315 extra_index += 1;
6316 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
6317 zir_tags[store_inst] = .as;
6318 zir_datas[store_inst].bin = .{
6319 .lhs = block_scope.rl_ty_inst,
6320 .rhs = zir_datas[break_inst].@"break".operand,
6321 };
6322 zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
6323 } else {
6324 scalar_cases_payload.items[body_len_index] -= 1;
6325 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]);
6326 extra_index += 1;
6327 astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]);
6328 extra_index += 1;
6329 }
6330 }
6331 extra_index = 0;
6332 var multi_i: u32 = 0;
6333 while (multi_i < multi_cases_len) : (multi_i += 1) {
6334 const start_index = extra_index;
6335 const items_len = multi_cases_payload.items[extra_index];
6336 extra_index += 1;
6337 const ranges_len = multi_cases_payload.items[extra_index];
6338 extra_index += 1;
6339 const body_len_index = extra_index;
6340 const body_len = multi_cases_payload.items[extra_index];
6341 extra_index += 1;
6342 extra_index += items_len;
6343 extra_index += 2 * ranges_len;
6344 if (body_len < 2) {
6345 extra_index += body_len;
6346 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
6347 continue;
6348 }
6349 extra_index += body_len - 2;
6350 const store_inst = multi_cases_payload.items[extra_index];
6351 if (zir_tags[store_inst] != .store_to_block_ptr or
6352 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr)
6353 {
6354 extra_index += 2;
6355 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
6356 continue;
6357 }
6358 if (block_scope.rl_ty_inst != .none) {
6359 extra_index += 1;
6360 const break_inst = multi_cases_payload.items[extra_index];
6361 extra_index += 1;
6362 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
6363 zir_tags[store_inst] = .as;
6364 zir_datas[store_inst].bin = .{
6365 .lhs = block_scope.rl_ty_inst,
6366 .rhs = zir_datas[break_inst].@"break".operand,
6367 };
6368 zir_datas[break_inst].@"break".operand = indexToRef(store_inst);
6369 } else {
6370 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
6371 multi_cases_payload.items[body_len_index] -= 1;
6372 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]);
6373 extra_index += 1;
6374 astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]);
6375 extra_index += 1;
6376 }
6377 }
6378
6379 const block_ref = indexToRef(switch_block);
6380 switch (rl) {
6381 .ref => return block_ref,
6382 else => return rvalue(parent_gz, rl, block_ref, switch_node),
6383 }
6384 },
6385 .break_void => {
6386 assert(!strat.elide_store_to_block_ptr_instructions);
6387 astgen.extra.appendSliceAssumeCapacity(special_case_payload.items);
6388 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
6389 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
6390 // Modify all the terminating instruction tags to become `break` variants.
6391 var extra_index: usize = payload_index;
6392 extra_index += 2;
6393 extra_index += @boolToInt(multi_cases_len != 0);
6394 if (special_prong != .none) {
6395 const body_len = astgen.extra.items[extra_index];
6396 extra_index += 1;
6397 const body = astgen.extra.items[extra_index..][0..body_len];
6398 extra_index += body_len;
6399 const last = body[body.len - 1];
6400 if (zir_tags[last] == .@"break" and
6401 zir_datas[last].@"break".block_inst == switch_block)
6402 {
6403 zir_datas[last].@"break".operand = .void_value;
6404 }
6405 }
6406 var scalar_i: u32 = 0;
6407 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
6408 extra_index += 1;
6409 const body_len = astgen.extra.items[extra_index];
6410 extra_index += 1;
6411 const body = astgen.extra.items[extra_index..][0..body_len];
6412 extra_index += body_len;
6413 const last = body[body.len - 1];
6414 if (zir_tags[last] == .@"break" and
6415 zir_datas[last].@"break".block_inst == switch_block)
6416 {
6417 zir_datas[last].@"break".operand = .void_value;
6418 }
6419 }
6420 var multi_i: u32 = 0;
6421 while (multi_i < multi_cases_len) : (multi_i += 1) {
6422 const items_len = astgen.extra.items[extra_index];
6423 extra_index += 1;
6424 const ranges_len = astgen.extra.items[extra_index];
6425 extra_index += 1;
6426 const body_len = astgen.extra.items[extra_index];
6427 extra_index += 1;
6428 extra_index += items_len;
6429 extra_index += 2 * ranges_len;
6430 const body = astgen.extra.items[extra_index..][0..body_len];
6431 extra_index += body_len;
6432 const last = body[body.len - 1];
6433 if (zir_tags[last] == .@"break" and
6434 zir_datas[last].@"break".block_inst == switch_block)
6262 },
6263 .break_void => {
6264 assert(!strat.elide_store_to_block_ptr_instructions);
6265 const last_inst = payloads.items[end_index - 1];
6266 if (zir_tags[last_inst] == .@"break" and
6267 zir_datas[last_inst].@"break".block_inst == switch_block)
64356268 {
6436 zir_datas[last].@"break".operand = .void_value;
6269 zir_datas[last_inst].@"break".operand = .void_value;
64376270 }
6438 }
6271 },
6272 }
64396273
6440 return indexToRef(switch_block);
6441 },
6274 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]);
64426275 }
6276
6277 const block_ref = indexToRef(switch_block);
6278 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref)
6279 return rvalue(parent_gz, rl, block_ref, switch_node);
6280 return block_ref;
64436281}
64446282
64456283fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {