| author | |
| committer | |
| log | 0fc79d602bf9b3a5c97cfc28b59193b005692cb2 |
| tree | 0fafad0932696ef5ab18032605f2197d35a16ac0 |
| parent | e863292fe2f280945d914e7e98fbc704b68f1004 |
2 files changed, 34 insertions(+), 36 deletions(-)
src/arch/arm/CodeGen.zig+34-27| ... | ... | @@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4300 | 4300 | ); |
| 4301 | 4301 | defer self.gpa.free(liveness.deaths); |
| 4302 | 4302 | |
| 4303 | // If the condition dies here in this switch instruction, process | |
| 4304 | // that death now instead of later as this has an effect on | |
| 4305 | // whether it needs to be spilled in the branches | |
| 4306 | if (self.liveness.operandDies(inst, 0)) { | |
| 4307 | const op_int = @enumToInt(pl_op.operand); | |
| 4308 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | |
| 4309 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 4310 | self.processDeath(op_index); | |
| 4311 | } | |
| 4312 | } | |
| 4313 | ||
| 4314 | 4303 | var extra_index: usize = switch_br.end; |
| 4315 | 4304 | var case_i: u32 = 0; |
| 4316 | 4305 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| ... | ... | @@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4320 | 4309 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 4321 | 4310 | extra_index = case.end + items.len + case_body.len; |
| 4322 | 4311 | |
| 4323 | var relocs = try self.gpa.alloc(u32, items.len); | |
| 4324 | defer self.gpa.free(relocs); | |
| 4325 | ||
| 4326 | if (items.len == 1) { | |
| 4312 | // For every item, we compare it to condition and branch into | |
| 4313 | // the prong if they are equal. After we compared to all | |
| 4314 | // items, we branch into the next prong (or if no other prongs | |
| 4315 | // exist out of the switch statement). | |
| 4316 | // | |
| 4317 | // cmp condition, item1 | |
| 4318 | // beq prong | |
| 4319 | // cmp condition, item2 | |
| 4320 | // beq prong | |
| 4321 | // cmp condition, item3 | |
| 4322 | // beq prong | |
| 4323 | // b out | |
| 4324 | // prong: ... | |
| 4325 | // ... | |
| 4326 | // out: ... | |
| 4327 | const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len); | |
| 4328 | defer self.gpa.free(branch_into_prong_relocs); | |
| 4329 | ||
| 4330 | for (items) |item, idx| { | |
| 4327 | 4331 | const condition = try self.resolveInst(pl_op.operand); |
| 4328 | const item = try self.resolveInst(items[0]); | |
| 4332 | const item_mcv = try self.resolveInst(item); | |
| 4329 | 4333 | |
| 4330 | 4334 | const operands: BinOpOperands = .{ .mcv = .{ |
| 4331 | 4335 | .lhs = condition, |
| 4332 | .rhs = item, | |
| 4336 | .rhs = item_mcv, | |
| 4333 | 4337 | } }; |
| 4334 | const cmp_result = try self.cmp(operands, condition_ty, .eq); | |
| 4335 | relocs[0] = try self.condBr(cmp_result); | |
| 4336 | } else { | |
| 4337 | return self.fail("TODO switch with multiple items", .{}); | |
| 4338 | const cmp_result = try self.cmp(operands, condition_ty, .neq); | |
| 4339 | branch_into_prong_relocs[idx] = try self.condBr(cmp_result); | |
| 4340 | } | |
| 4341 | ||
| 4342 | const branch_away_from_prong_reloc = try self.addInst(.{ | |
| 4343 | .tag = .b, | |
| 4344 | .data = .{ .inst = undefined }, // populated later through performReloc | |
| 4345 | }); | |
| 4346 | ||
| 4347 | for (branch_into_prong_relocs) |reloc| { | |
| 4348 | try self.performReloc(reloc); | |
| 4338 | 4349 | } |
| 4339 | 4350 | |
| 4340 | 4351 | // Capture the state of register and stack allocation state so that we can revert to it. |
| ... | ... | @@ -4369,9 +4380,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4369 | 4380 | self.next_stack_offset = parent_next_stack_offset; |
| 4370 | 4381 | self.register_manager.free_registers = parent_free_registers; |
| 4371 | 4382 | |
| 4372 | for (relocs) |reloc| { | |
| 4373 | try self.performReloc(reloc); | |
| 4374 | } | |
| 4383 | try self.performReloc(branch_away_from_prong_reloc); | |
| 4375 | 4384 | } |
| 4376 | 4385 | |
| 4377 | 4386 | if (switch_br.data.else_body_len > 0) { |
| ... | ... | @@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4414 | 4423 | // in airCondBr. |
| 4415 | 4424 | } |
| 4416 | 4425 | |
| 4417 | // We already took care of pl_op.operand earlier, so we're going | |
| 4418 | // to pass .none here | |
| 4419 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | |
| 4426 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); | |
| 4420 | 4427 | } |
| 4421 | 4428 | |
| 4422 | 4429 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
test/behavior/switch.zig-9| ... | ... | @@ -53,7 +53,6 @@ test "implicit comptime switch" { |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | test "switch on enum" { |
| 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 57 | 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 58 | 57 | |
| 59 | 58 | const fruit = Fruit.Orange; |
| ... | ... | @@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void { |
| 73 | 72 | } |
| 74 | 73 | |
| 75 | 74 | test "switch statement" { |
| 76 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 77 | 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 78 | 76 | |
| 79 | 77 | try nonConstSwitch(SwitchStatementFoo.C); |
| ... | ... | @@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D }; |
| 91 | 89 | |
| 92 | 90 | test "switch with multiple expressions" { |
| 93 | 91 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 94 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 95 | 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 96 | 93 | |
| 97 | 94 | const x = switch (returnsFive()) { |
| ... | ... | @@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool { |
| 120 | 117 | } |
| 121 | 118 | |
| 122 | 119 | test "switching on booleans" { |
| 123 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 124 | 120 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 125 | 121 | |
| 126 | 122 | try testSwitchOnBools(); |
| ... | ... | @@ -218,7 +214,6 @@ fn poll() void { |
| 218 | 214 | } |
| 219 | 215 | |
| 220 | 216 | test "switch on global mutable var isn't constant-folded" { |
| 221 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 222 | 217 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 223 | 218 | |
| 224 | 219 | while (state < 2) { |
| ... | ... | @@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void { |
| 278 | 273 | |
| 279 | 274 | test "switch handles all cases of number" { |
| 280 | 275 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 281 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 282 | 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 283 | 277 | |
| 284 | 278 | try testSwitchHandleAllCases(); |
| ... | ... | @@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" { |
| 370 | 364 | } |
| 371 | 365 | |
| 372 | 366 | test "switch all prongs unreachable" { |
| 373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 374 | 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 375 | 368 | |
| 376 | 369 | try testAllProngsUnreachable(); |
| ... | ... | @@ -582,7 +575,6 @@ test "switch on pointer type" { |
| 582 | 575 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 583 | 576 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 584 | 577 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 586 | 578 | |
| 587 | 579 | const S = struct { |
| 588 | 580 | const X = struct { |
| ... | ... | @@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" { |
| 674 | 666 | } |
| 675 | 667 | |
| 676 | 668 | test "enum value without tag name used as switch item" { |
| 677 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 678 | 669 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 679 | 670 | |
| 680 | 671 | const E = enum(u32) { |