| ... | ... | @@ -4170,159 +4170,201 @@ fn analyzeSwitch( |
| 4170 | 4170 | |
| 4171 | 4171 | try sema.requireRuntimeBlock(block, src); |
| 4172 | 4172 | |
| 4173 | | // TODO when reworking AIR memory layout make multi cases get generated as cases, |
| 4174 | | // not as part of the "else" block. |
| 4175 | | return mod.fail(&block.base, src, "TODO rework runtime switch Sema", .{}); |
| 4176 | | //const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len); |
| 4177 | | |
| 4178 | | //var case_block = child_block.makeSubBlock(); |
| 4179 | | //case_block.runtime_loop = null; |
| 4180 | | //case_block.runtime_cond = operand.src; |
| 4181 | | //case_block.runtime_index += 1; |
| 4182 | | //defer case_block.instructions.deinit(gpa); |
| 4183 | | |
| 4184 | | //var extra_index: usize = special.end; |
| 4185 | | |
| 4186 | | //var scalar_i: usize = 0; |
| 4187 | | //while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 4188 | | // const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4189 | | // extra_index += 1; |
| 4190 | | // const body_len = sema.code.extra[extra_index]; |
| 4191 | | // extra_index += 1; |
| 4192 | | // const body = sema.code.extra[extra_index..][0..body_len]; |
| 4193 | | // extra_index += body_len; |
| 4173 | var cases_extra: std.ArrayListUnmanaged(u32) = .{}; |
| 4174 | defer cases_extra.deinit(gpa); |
| 4194 | 4175 | |
| 4195 | | // case_block.instructions.shrinkRetainingCapacity(0); |
| 4196 | | // const item = sema.resolveInst(item_ref); |
| 4197 | | // // We validate these above; these two calls are guaranteed to succeed. |
| 4198 | | // const item_val = sema.resolveConstValue(&case_block, .unneeded, item) catch unreachable; |
| 4176 | try cases_extra.ensureTotalCapacity(gpa, (scalar_cases_len + multi_cases_len) * |
| 4177 | @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2); |
| 4199 | 4178 | |
| 4200 | | // _ = try sema.analyzeBody(&case_block, body); |
| 4179 | var case_block = child_block.makeSubBlock(); |
| 4180 | case_block.runtime_loop = null; |
| 4181 | case_block.runtime_cond = operand_src; |
| 4182 | case_block.runtime_index += 1; |
| 4183 | defer case_block.instructions.deinit(gpa); |
| 4201 | 4184 | |
| 4202 | | // cases[scalar_i] = .{ |
| 4203 | | // .item = item_val, |
| 4204 | | // .body = .{ .instructions = try sema.arena.dupe(Air.Inst.Index, case_block.instructions.items) }, |
| 4205 | | // }; |
| 4206 | | //} |
| 4185 | var extra_index: usize = special.end; |
| 4207 | 4186 | |
| 4208 | | //var first_else_body: Body = undefined; |
| 4209 | | //var prev_condbr: ?*Inst.CondBr = null; |
| 4187 | var scalar_i: usize = 0; |
| 4188 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 4189 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4190 | extra_index += 1; |
| 4191 | const body_len = sema.code.extra[extra_index]; |
| 4192 | extra_index += 1; |
| 4193 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 4194 | extra_index += body_len; |
| 4210 | 4195 | |
| 4211 | | //var multi_i: usize = 0; |
| 4212 | | //while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 4213 | | // const items_len = sema.code.extra[extra_index]; |
| 4214 | | // extra_index += 1; |
| 4215 | | // const ranges_len = sema.code.extra[extra_index]; |
| 4216 | | // extra_index += 1; |
| 4217 | | // const body_len = sema.code.extra[extra_index]; |
| 4218 | | // extra_index += 1; |
| 4219 | | // const items = sema.code.refSlice(extra_index, items_len); |
| 4220 | | // extra_index += items_len; |
| 4221 | | |
| 4222 | | // case_block.instructions.shrinkRetainingCapacity(0); |
| 4223 | | |
| 4224 | | // var any_ok: ?Air.Inst.Index = null; |
| 4225 | | |
| 4226 | | // for (items) |item_ref| { |
| 4227 | | // const item = sema.resolveInst(item_ref); |
| 4228 | | // _ = try sema.resolveConstValue(&child_block, item.src, item); |
| 4229 | | |
| 4230 | | // const cmp_ok = try case_block.addBinOp(.cmp_eq, operand, item); |
| 4231 | | // if (any_ok) |some| { |
| 4232 | | // any_ok = try case_block.addBinOp(.bool_or, some, cmp_ok); |
| 4233 | | // } else { |
| 4234 | | // any_ok = cmp_ok; |
| 4235 | | // } |
| 4236 | | // } |
| 4237 | | |
| 4238 | | // var range_i: usize = 0; |
| 4239 | | // while (range_i < ranges_len) : (range_i += 1) { |
| 4240 | | // const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4241 | | // extra_index += 1; |
| 4242 | | // const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4243 | | // extra_index += 1; |
| 4244 | | |
| 4245 | | // const item_first = sema.resolveInst(first_ref); |
| 4246 | | // const item_last = sema.resolveInst(last_ref); |
| 4247 | | |
| 4248 | | // _ = try sema.resolveConstValue(&child_block, item_first.src, item_first); |
| 4249 | | // _ = try sema.resolveConstValue(&child_block, item_last.src, item_last); |
| 4250 | | |
| 4251 | | // // operand >= first and operand <= last |
| 4252 | | // const range_first_ok = try case_block.addBinOp( |
| 4253 | | // .cmp_gte, |
| 4254 | | // operand, |
| 4255 | | // item_first, |
| 4256 | | // ); |
| 4257 | | // const range_last_ok = try case_block.addBinOp( |
| 4258 | | // .cmp_lte, |
| 4259 | | // operand, |
| 4260 | | // item_last, |
| 4261 | | // ); |
| 4262 | | // const range_ok = try case_block.addBinOp( |
| 4263 | | // .bool_and, |
| 4264 | | // range_first_ok, |
| 4265 | | // range_last_ok, |
| 4266 | | // ); |
| 4267 | | // if (any_ok) |some| { |
| 4268 | | // any_ok = try case_block.addBinOp(.bool_or, some, range_ok); |
| 4269 | | // } else { |
| 4270 | | // any_ok = range_ok; |
| 4271 | | // } |
| 4272 | | // } |
| 4273 | | |
| 4274 | | // const new_condbr = try sema.arena.create(Inst.CondBr); |
| 4275 | | // new_condbr.* = .{ |
| 4276 | | // .base = .{ |
| 4277 | | // .tag = .condbr, |
| 4278 | | // .ty = Type.initTag(.noreturn), |
| 4279 | | // .src = src, |
| 4280 | | // }, |
| 4281 | | // .condition = any_ok.?, |
| 4282 | | // .then_body = undefined, |
| 4283 | | // .else_body = undefined, |
| 4284 | | // }; |
| 4285 | | // try case_block.instructions.append(gpa, &new_condbr.base); |
| 4286 | | |
| 4287 | | // const cond_body: Body = .{ |
| 4288 | | // .instructions = try sema.arena.dupe(Air.Inst.Index, case_block.instructions.items), |
| 4289 | | // }; |
| 4290 | | |
| 4291 | | // case_block.instructions.shrinkRetainingCapacity(0); |
| 4292 | | // const body = sema.code.extra[extra_index..][0..body_len]; |
| 4293 | | // extra_index += body_len; |
| 4294 | | // _ = try sema.analyzeBody(&case_block, body); |
| 4295 | | // new_condbr.then_body = .{ |
| 4296 | | // .instructions = try sema.arena.dupe(Air.Inst.Index, case_block.instructions.items), |
| 4297 | | // }; |
| 4298 | | // if (prev_condbr) |condbr| { |
| 4299 | | // condbr.else_body = cond_body; |
| 4300 | | // } else { |
| 4301 | | // first_else_body = cond_body; |
| 4302 | | // } |
| 4303 | | // prev_condbr = new_condbr; |
| 4304 | | //} |
| 4305 | | |
| 4306 | | //const final_else_body: Body = blk: { |
| 4307 | | // if (special.body.len != 0) { |
| 4308 | | // case_block.instructions.shrinkRetainingCapacity(0); |
| 4309 | | // _ = try sema.analyzeBody(&case_block, special.body); |
| 4310 | | // const else_body: Body = .{ |
| 4311 | | // .instructions = try sema.arena.dupe(Air.Inst.Index, case_block.instructions.items), |
| 4312 | | // }; |
| 4313 | | // if (prev_condbr) |condbr| { |
| 4314 | | // condbr.else_body = else_body; |
| 4315 | | // break :blk first_else_body; |
| 4316 | | // } else { |
| 4317 | | // break :blk else_body; |
| 4318 | | // } |
| 4319 | | // } else { |
| 4320 | | // break :blk .{ .instructions = &.{} }; |
| 4321 | | // } |
| 4322 | | //}; |
| 4323 | | |
| 4324 | | //_ = try child_block.addSwitchBr(src, operand, cases, final_else_body); |
| 4325 | | //return sema.analyzeBlockBody(block, src, &child_block, merges); |
| 4196 | case_block.instructions.shrinkRetainingCapacity(0); |
| 4197 | const item = sema.resolveInst(item_ref); |
| 4198 | // `item` is already guaranteed to be constant known. |
| 4199 | |
| 4200 | _ = try sema.analyzeBody(&case_block, body); |
| 4201 | |
| 4202 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 4203 | cases_extra.appendAssumeCapacity(1); // items_len |
| 4204 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 4205 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 4206 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 4207 | } |
| 4208 | |
| 4209 | var is_first = true; |
| 4210 | var prev_cond_br: Air.Inst.Index = undefined; |
| 4211 | var first_else_body: []const Air.Inst.Index = &.{}; |
| 4212 | defer gpa.free(first_else_body); |
| 4213 | var prev_then_body: []const Air.Inst.Index = &.{}; |
| 4214 | defer gpa.free(prev_then_body); |
| 4215 | |
| 4216 | var multi_i: usize = 0; |
| 4217 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 4218 | const items_len = sema.code.extra[extra_index]; |
| 4219 | extra_index += 1; |
| 4220 | const ranges_len = sema.code.extra[extra_index]; |
| 4221 | extra_index += 1; |
| 4222 | const body_len = sema.code.extra[extra_index]; |
| 4223 | extra_index += 1; |
| 4224 | const items = sema.code.refSlice(extra_index, items_len); |
| 4225 | extra_index += items_len; |
| 4226 | |
| 4227 | case_block.instructions.shrinkRetainingCapacity(0); |
| 4228 | |
| 4229 | var any_ok: Air.Inst.Ref = .none; |
| 4230 | |
| 4231 | // If there are any ranges, we have to put all the items into the |
| 4232 | // else prong. Otherwise, we can take advantage of multiple items |
| 4233 | // mapping to the same body. |
| 4234 | if (ranges_len == 0) { |
| 4235 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 4236 | extra_index += body_len; |
| 4237 | _ = try sema.analyzeBody(&case_block, body); |
| 4238 | |
| 4239 | try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + |
| 4240 | case_block.instructions.items.len); |
| 4241 | |
| 4242 | cases_extra.appendAssumeCapacity(1); // items_len |
| 4243 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 4244 | |
| 4245 | for (items) |item_ref| { |
| 4246 | const item = sema.resolveInst(item_ref); |
| 4247 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 4248 | } |
| 4249 | |
| 4250 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 4251 | } else { |
| 4252 | for (items) |item_ref| { |
| 4253 | const item = sema.resolveInst(item_ref); |
| 4254 | const cmp_ok = try case_block.addBinOp(.cmp_eq, operand, item); |
| 4255 | if (any_ok != .none) { |
| 4256 | any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); |
| 4257 | } else { |
| 4258 | any_ok = cmp_ok; |
| 4259 | } |
| 4260 | } |
| 4261 | |
| 4262 | var range_i: usize = 0; |
| 4263 | while (range_i < ranges_len) : (range_i += 1) { |
| 4264 | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4265 | extra_index += 1; |
| 4266 | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4267 | extra_index += 1; |
| 4268 | |
| 4269 | const item_first = sema.resolveInst(first_ref); |
| 4270 | const item_last = sema.resolveInst(last_ref); |
| 4271 | |
| 4272 | // operand >= first and operand <= last |
| 4273 | const range_first_ok = try case_block.addBinOp( |
| 4274 | .cmp_gte, |
| 4275 | operand, |
| 4276 | item_first, |
| 4277 | ); |
| 4278 | const range_last_ok = try case_block.addBinOp( |
| 4279 | .cmp_lte, |
| 4280 | operand, |
| 4281 | item_last, |
| 4282 | ); |
| 4283 | const range_ok = try case_block.addBinOp( |
| 4284 | .bool_and, |
| 4285 | range_first_ok, |
| 4286 | range_last_ok, |
| 4287 | ); |
| 4288 | if (any_ok != .none) { |
| 4289 | any_ok = try case_block.addBinOp(.bool_or, any_ok, range_ok); |
| 4290 | } else { |
| 4291 | any_ok = range_ok; |
| 4292 | } |
| 4293 | } |
| 4294 | |
| 4295 | const new_cond_br = try case_block.addInstAsIndex(.{ .tag = .cond_br, .data = .{ |
| 4296 | .pl_op = .{ |
| 4297 | .operand = any_ok, |
| 4298 | .payload = undefined, |
| 4299 | }, |
| 4300 | } }); |
| 4301 | var cond_body = case_block.instructions.toOwnedSlice(gpa); |
| 4302 | defer gpa.free(cond_body); |
| 4303 | |
| 4304 | case_block.instructions.shrinkRetainingCapacity(0); |
| 4305 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 4306 | extra_index += body_len; |
| 4307 | _ = try sema.analyzeBody(&case_block, body); |
| 4308 | |
| 4309 | if (is_first) { |
| 4310 | is_first = false; |
| 4311 | first_else_body = cond_body; |
| 4312 | cond_body = &.{}; |
| 4313 | } else { |
| 4314 | try sema.air_extra.ensureUnusedCapacity( |
| 4315 | gpa, |
| 4316 | @typeInfo(Air.CondBr).Struct.fields.len + prev_then_body.len + cond_body.len, |
| 4317 | ); |
| 4318 | |
| 4319 | sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = |
| 4320 | sema.addExtraAssumeCapacity(Air.CondBr{ |
| 4321 | .then_body_len = @intCast(u32, prev_then_body.len), |
| 4322 | .else_body_len = @intCast(u32, cond_body.len), |
| 4323 | }); |
| 4324 | sema.air_extra.appendSliceAssumeCapacity(prev_then_body); |
| 4325 | sema.air_extra.appendSliceAssumeCapacity(cond_body); |
| 4326 | } |
| 4327 | prev_then_body = case_block.instructions.toOwnedSlice(gpa); |
| 4328 | prev_cond_br = new_cond_br; |
| 4329 | } |
| 4330 | } |
| 4331 | |
| 4332 | var final_else_body: []const Air.Inst.Index = &.{}; |
| 4333 | if (special.body.len != 0) { |
| 4334 | case_block.instructions.shrinkRetainingCapacity(0); |
| 4335 | _ = try sema.analyzeBody(&case_block, special.body); |
| 4336 | |
| 4337 | if (is_first) { |
| 4338 | final_else_body = case_block.instructions.items; |
| 4339 | } else { |
| 4340 | try sema.air_extra.ensureUnusedCapacity(gpa, prev_then_body.len + |
| 4341 | @typeInfo(Air.CondBr).Struct.fields.len + case_block.instructions.items.len); |
| 4342 | |
| 4343 | sema.air_instructions.items(.data)[prev_cond_br].pl_op.payload = |
| 4344 | sema.addExtraAssumeCapacity(Air.CondBr{ |
| 4345 | .then_body_len = @intCast(u32, prev_then_body.len), |
| 4346 | .else_body_len = @intCast(u32, case_block.instructions.items.len), |
| 4347 | }); |
| 4348 | sema.air_extra.appendSliceAssumeCapacity(prev_then_body); |
| 4349 | sema.air_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 4350 | final_else_body = first_else_body; |
| 4351 | } |
| 4352 | } |
| 4353 | |
| 4354 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len + |
| 4355 | cases_extra.items.len); |
| 4356 | |
| 4357 | _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{ |
| 4358 | .operand = operand, |
| 4359 | .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{ |
| 4360 | .cases_len = @intCast(u32, scalar_cases_len + multi_cases_len), |
| 4361 | .else_body_len = @intCast(u32, final_else_body.len), |
| 4362 | }), |
| 4363 | } } }); |
| 4364 | sema.air_extra.appendSliceAssumeCapacity(cases_extra.items); |
| 4365 | sema.air_extra.appendSliceAssumeCapacity(final_else_body); |
| 4366 | |
| 4367 | return sema.analyzeBlockBody(block, src, &child_block, merges); |
| 4326 | 4368 | } |
| 4327 | 4369 | |
| 4328 | 4370 | fn resolveSwitchItemVal( |