diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-07-27 20:24:33 +0200 |
|---|---|---|
| committer | Joachim Schmidt <joachim.schmidt557@outlook.com> | 2022-07-28 20:44:32 +0000 |
| commit | 0fc79d602bf9b3a5c97cfc28b59193b005692cb2 (patch) | |
| tree | 0fafad0932696ef5ab18032605f2197d35a16ac0 /src | |
| parent | e863292fe2f280945d914e7e98fbc704b68f1004 (diff) | |
| download | zig-0fc79d602bf9b3a5c97cfc28b59193b005692cb2.tar.gz zig-0fc79d602bf9b3a5c97cfc28b59193b005692cb2.zip | |
stage2 ARM: more support for switch statements
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 61 |
1 files changed, 34 insertions, 27 deletions
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 8bd589e7ba..93d98c41d3 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { ); defer self.gpa.free(liveness.deaths); - // If the condition dies here in this switch instruction, process - // that death now instead of later as this has an effect on - // whether it needs to be spilled in the branches - if (self.liveness.operandDies(inst, 0)) { - const op_int = @enumToInt(pl_op.operand); - if (op_int >= Air.Inst.Ref.typed_value_map.len) { - const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); - self.processDeath(op_index); - } - } - var extra_index: usize = switch_br.end; var case_i: u32 = 0; while (case_i < switch_br.data.cases_len) : (case_i += 1) { @@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + items.len + case_body.len; - var relocs = try self.gpa.alloc(u32, items.len); - defer self.gpa.free(relocs); - - if (items.len == 1) { + // For every item, we compare it to condition and branch into + // the prong if they are equal. After we compared to all + // items, we branch into the next prong (or if no other prongs + // exist out of the switch statement). + // + // cmp condition, item1 + // beq prong + // cmp condition, item2 + // beq prong + // cmp condition, item3 + // beq prong + // b out + // prong: ... + // ... + // out: ... + const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len); + defer self.gpa.free(branch_into_prong_relocs); + + for (items) |item, idx| { const condition = try self.resolveInst(pl_op.operand); - const item = try self.resolveInst(items[0]); + const item_mcv = try self.resolveInst(item); const operands: BinOpOperands = .{ .mcv = .{ .lhs = condition, - .rhs = item, + .rhs = item_mcv, } }; - const cmp_result = try self.cmp(operands, condition_ty, .eq); - relocs[0] = try self.condBr(cmp_result); - } else { - return self.fail("TODO switch with multiple items", .{}); + const cmp_result = try self.cmp(operands, condition_ty, .neq); + branch_into_prong_relocs[idx] = try self.condBr(cmp_result); + } + + const branch_away_from_prong_reloc = try self.addInst(.{ + .tag = .b, + .data = .{ .inst = undefined }, // populated later through performReloc + }); + + for (branch_into_prong_relocs) |reloc| { + try self.performReloc(reloc); } // 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 { self.next_stack_offset = parent_next_stack_offset; self.register_manager.free_registers = parent_free_registers; - for (relocs) |reloc| { - try self.performReloc(reloc); - } + try self.performReloc(branch_away_from_prong_reloc); } if (switch_br.data.else_body_len > 0) { @@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { // in airCondBr. } - // We already took care of pl_op.operand earlier, so we're going - // to pass .none here - return self.finishAir(inst, .unreach, .{ .none, .none, .none }); + return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); } fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
