Commit 756ddf0925

Jakub Konka <kubkon@jakubkonka.com>
2022-05-07 22:35:36
arm: fix CF flags spilling and implement genSetStack for reg with overflow flags
1 parent f57b059
Changed files (1)
src
arch
src/arch/arm/CodeGen.zig
@@ -898,16 +898,16 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
 fn spillCompareFlagsIfOccupied(self: *Self) !void {
     if (self.compare_flags_inst) |inst_to_save| {
         const mcv = self.getResolvedInstValue(inst_to_save);
-        switch (mcv) {
+        const new_mcv = switch (mcv) {
             .compare_flags_signed,
             .compare_flags_unsigned,
+            => try self.allocRegOrMem(inst_to_save, true),
             .register_c_flag,
             .register_v_flag,
-            => {},
+            => try self.allocRegOrMem(inst_to_save, false),
             else => unreachable, // mcv doesn't occupy the compare flags
-        }
+        };
 
-        const new_mcv = try self.allocRegOrMem(inst_to_save, true);
         try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
         log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
 
@@ -915,6 +915,15 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
         try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
 
         self.compare_flags_inst = null;
+
+        // TODO consolidate with register manager and spillInstruction
+        // this call should really belong in the register manager!
+        switch (mcv) {
+            .register_c_flag,
+            .register_v_flag,
+            => |reg| self.register_manager.freeReg(reg),
+            else => {},
+        }
     }
 }
 
@@ -1972,8 +1981,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
                     .register => |reg| reg,
                     else => try self.copyToTmpRegister(Type.usize, index_mcv),
                 };
-                const index_reg_lock = self.register_manager.lockRegAssumeUnused(index_reg);
-                defer self.register_manager.unlockReg(index_reg_lock);
+                const index_reg_lock = self.register_manager.lockReg(index_reg);
+                defer if (index_reg_lock) |lock| self.register_manager.unlockReg(lock);
 
                 const tag: Mir.Inst.Tag = switch (elem_size) {
                     1 => .ldrb,
@@ -3677,6 +3686,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
     const parent_compare_flags_inst = self.compare_flags_inst;
 
     try self.branch_stack.append(.{});
+    errdefer {
+        _ = self.branch_stack.pop();
+    }
 
     try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len);
     for (liveness_condbr.then_deaths) |operand| {
@@ -4285,8 +4297,36 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
         },
         .register_c_flag,
         .register_v_flag,
-        => {
-            return self.fail("TODO implement genSetStack {}", .{mcv});
+        => |reg| {
+            const reg_lock = self.register_manager.lockReg(reg);
+            defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg);
+
+            const wrapped_ty = ty.structFieldType(0);
+            try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg });
+
+            const overflow_bit_ty = ty.structFieldType(1);
+            const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
+            const cond_reg = try self.register_manager.allocReg(null);
+
+            // C flag: movcs reg, #1
+            // V flag: movvs reg, #1
+            _ = try self.addInst(.{
+                .tag = .mov,
+                .cond = switch (mcv) {
+                    .register_c_flag => .cs,
+                    .register_v_flag => .vs,
+                    else => unreachable,
+                },
+                .data = .{ .rr_op = .{
+                    .rd = cond_reg,
+                    .rn = .r0,
+                    .op = Instruction.Operand.fromU32(1).?,
+                } },
+            });
+
+            try self.genSetStack(overflow_bit_ty, stack_offset - overflow_bit_offset, .{
+                .register = cond_reg,
+            });
         },
         .memory,
         .stack_argument_offset,