Commit 7000395a7d

Jakub Konka <kubkon@jakubkonka.com>
2022-05-25 17:18:43
x64: use new condition codes enum for register with overflow mcv
1 parent 5fb7070
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -128,12 +128,8 @@ pub const MCValue = union(enum) {
     immediate: u64,
     /// The value is in a GP register.
     register: Register,
-    /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,
-    /// and the operation is an unsigned operation.
-    register_overflow_unsigned: Register,
-    /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,
-    /// and the operation is a signed operation.
-    register_overflow_signed: Register,
+    /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
+    register_overflow: struct { reg: Register, eflags: Condition },
     /// The value is in memory at a hard-coded address.
     /// If the type is a pointer, it means the pointer address is at this memory location.
     memory: u64,
@@ -183,8 +179,7 @@ pub const MCValue = union(enum) {
             .eflags,
             .ptr_stack_offset,
             .undef,
-            .register_overflow_unsigned,
-            .register_overflow_signed,
+            .register_overflow,
             => false,
 
             .register,
@@ -774,8 +769,8 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
         .register => |reg| {
             self.register_manager.freeReg(reg.to64());
         },
-        .register_overflow_signed, .register_overflow_unsigned => |reg| {
-            self.register_manager.freeReg(reg.to64());
+        .register_overflow => |ro| {
+            self.register_manager.freeReg(ro.reg.to64());
             self.eflags_inst = null;
         },
         .eflags => {
@@ -809,20 +804,22 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
         const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
         branch.inst_table.putAssumeCapacityNoClobber(inst, result);
 
+        // In some cases (such as bitcast), an operand
+        // may be the same MCValue as the result. If
+        // that operand died and was a register, it
+        // was freed by processDeath. We have to
+        // "re-allocate" the register.
         switch (result) {
-            .register,
-            .register_overflow_signed,
-            .register_overflow_unsigned,
-            => |reg| {
-                // In some cases (such as bitcast), an operand
-                // may be the same MCValue as the result. If
-                // that operand died and was a register, it
-                // was freed by processDeath. We have to
-                // "re-allocate" the register.
+            .register => |reg| {
                 if (self.register_manager.isRegFree(reg)) {
                     self.register_manager.getRegAssumeFree(reg, inst);
                 }
             },
+            .register_overflow => |ro| {
+                if (self.register_manager.isRegFree(ro.reg)) {
+                    self.register_manager.getRegAssumeFree(ro.reg, inst);
+                }
+            },
             else => {},
         }
     }
@@ -912,12 +909,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
     log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
     const reg_mcv = self.getResolvedInstValue(inst);
     switch (reg_mcv) {
-        .register,
-        .register_overflow_unsigned,
-        .register_overflow_signed,
-        => |other| {
+        .register => |other| {
             assert(reg.to64() == other.to64());
         },
+        .register_overflow => |ro| {
+            assert(reg.to64() == ro.reg.to64());
+        },
         else => {},
     }
     const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
@@ -929,9 +926,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
     if (self.eflags_inst) |inst_to_save| {
         const mcv = self.getResolvedInstValue(inst_to_save);
         const new_mcv = switch (mcv) {
-            .register_overflow_signed,
-            .register_overflow_unsigned,
-            => try self.allocRegOrMem(inst_to_save, false),
+            .register_overflow => try self.allocRegOrMem(inst_to_save, false),
             .eflags => try self.allocRegOrMem(inst_to_save, true),
             else => unreachable,
         };
@@ -947,9 +942,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
         // TODO consolidate with register manager and spillInstruction
         // this call should really belong in the register manager!
         switch (mcv) {
-            .register_overflow_signed,
-            .register_overflow_unsigned,
-            => |reg| self.register_manager.freeReg(reg),
+            .register_overflow => |ro| self.register_manager.freeReg(ro.reg),
             else => {},
         }
     }
@@ -1339,11 +1332,14 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
                     self.eflags_inst = inst;
 
-                    const result: MCValue = switch (int_info.signedness) {
-                        .signed => .{ .register_overflow_signed = partial.register },
-                        .unsigned => .{ .register_overflow_unsigned = partial.register },
+                    const cc: Condition = switch (int_info.signedness) {
+                        .unsigned => .c,
+                        .signed => .o,
                     };
-                    break :result result;
+                    break :result MCValue{ .register_overflow = .{
+                        .reg = partial.register,
+                        .eflags = cc,
+                    } };
                 }
 
                 self.eflags_inst = null;
@@ -1460,10 +1456,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     const rhs = try self.resolveInst(bin_op.rhs);
 
                     const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
-                    break :result switch (int_info.signedness) {
-                        .signed => MCValue{ .register_overflow_signed = partial.register },
-                        .unsigned => MCValue{ .register_overflow_unsigned = partial.register },
+                    const cc: Condition = switch (int_info.signedness) {
+                        .unsigned => .c,
+                        .signed => .o,
                     };
+                    break :result MCValue{ .register_overflow = .{
+                        .reg = partial.register,
+                        .eflags = cc,
+                    } };
                 }
 
                 try self.spillEflagsIfOccupied();
@@ -2486,8 +2486,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
         .unreach => unreachable,
         .dead => unreachable,
         .eflags => unreachable,
-        .register_overflow_unsigned => unreachable,
-        .register_overflow_signed => unreachable,
+        .register_overflow => unreachable,
         .immediate => |imm| {
             try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
         },
@@ -2610,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
         .unreach => unreachable,
         .dead => unreachable,
         .eflags => unreachable,
-        .register_overflow_unsigned => unreachable,
-        .register_overflow_signed => unreachable,
+        .register_overflow => unreachable,
         .immediate => |imm| {
             try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
         },
@@ -2997,31 +2995,24 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
 
                 break :result dst_mcv;
             },
-            .register_overflow_unsigned,
-            .register_overflow_signed,
-            => |reg| {
+            .register_overflow => |ro| {
                 switch (index) {
                     0 => {
                         // Get wrapped value for overflow operation.
-                        break :result MCValue{ .register = reg };
+                        break :result MCValue{ .register = ro.reg };
                     },
                     1 => {
                         // Get overflow bit.
-                        const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
+                        const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg);
                         defer self.register_manager.unlockReg(reg_lock);
 
                         const dst_reg = try self.register_manager.allocReg(inst, gp);
-                        const cc: Condition = switch (mcv) {
-                            .register_overflow_unsigned => .c,
-                            .register_overflow_signed => .o,
-                            else => unreachable,
-                        };
                         _ = try self.addInst(.{
                             .tag = .cond_set_byte,
                             .ops = Mir.Inst.Ops.encode(.{
                                 .reg1 = dst_reg.to8(),
                             }),
-                            .data = .{ .cc = cc },
+                            .data = .{ .cc = ro.eflags },
                         });
                         break :result MCValue{ .register = dst_reg.to8() };
                     },
@@ -3449,15 +3440,13 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
         .undef => unreachable,
         .dead, .unreach, .immediate => unreachable,
         .eflags => unreachable,
-        .register_overflow_unsigned => unreachable,
-        .register_overflow_signed => unreachable,
+        .register_overflow => unreachable,
         .register => |dst_reg| {
             switch (src_mcv) {
                 .none => unreachable,
                 .undef => unreachable,
                 .dead, .unreach => unreachable,
-                .register_overflow_unsigned => unreachable,
-                .register_overflow_signed => unreachable,
+                .register_overflow => unreachable,
                 .ptr_stack_offset => {
                     const dst_reg_lock = self.register_manager.lockReg(dst_reg);
                     defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
@@ -3564,8 +3553,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
                 .none => unreachable,
                 .undef => unreachable,
                 .dead, .unreach => unreachable,
-                .register_overflow_unsigned => unreachable,
-                .register_overflow_signed => unreachable,
+                .register_overflow => unreachable,
                 .register => |src_reg| {
                     _ = try self.addInst(.{
                         .tag = mir_tag,
@@ -3640,16 +3628,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
         .dead, .unreach, .immediate => unreachable,
         .eflags => unreachable,
         .ptr_stack_offset => unreachable,
-        .register_overflow_unsigned => unreachable,
-        .register_overflow_signed => unreachable,
+        .register_overflow => unreachable,
         .register => |dst_reg| {
             switch (src_mcv) {
                 .none => unreachable,
                 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
                 .dead, .unreach => unreachable,
                 .ptr_stack_offset => unreachable,
-                .register_overflow_unsigned => unreachable,
-                .register_overflow_signed => unreachable,
+                .register_overflow => unreachable,
                 .register => |src_reg| {
                     // register, register
                     _ = try self.addInst(.{
@@ -3708,8 +3694,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
                 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),
                 .dead, .unreach => unreachable,
                 .ptr_stack_offset => unreachable,
-                .register_overflow_unsigned => unreachable,
-                .register_overflow_signed => unreachable,
+                .register_overflow => unreachable,
                 .register => |src_reg| {
                     // copy dst to a register
                     const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
@@ -3915,8 +3900,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
             .got_load => unreachable,
             .direct_load => unreachable,
             .eflags => unreachable,
-            .register_overflow_signed => unreachable,
-            .register_overflow_unsigned => unreachable,
+            .register_overflow => unreachable,
         }
     }
 
@@ -5291,9 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
                 .{ .dest_stack_base = .rsp },
             );
         },
-        .register_overflow_unsigned,
-        .register_overflow_signed,
-        => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
+        .register_overflow => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
         .eflags => {
             const reg = try self.copyToTmpRegister(ty, mcv);
             return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
@@ -5429,29 +5411,22 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
                 ),
             }
         },
-        .register_overflow_unsigned,
-        .register_overflow_signed,
-        => |reg| {
-            const reg_lock = self.register_manager.lockReg(reg);
+        .register_overflow => |ro| {
+            const reg_lock = self.register_manager.lockReg(ro.reg);
             defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
 
             const wrapped_ty = ty.structFieldType(0);
-            try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{});
+            try self.genSetStack(wrapped_ty, stack_offset, .{ .register = ro.reg }, .{});
 
             const overflow_bit_ty = ty.structFieldType(1);
             const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
             const tmp_reg = try self.register_manager.allocReg(null, gp);
-            const cc: Condition = switch (mcv) {
-                .register_overflow_unsigned => .c,
-                .register_overflow_signed => .o,
-                else => unreachable,
-            };
             _ = try self.addInst(.{
                 .tag = .cond_set_byte,
                 .ops = Mir.Inst.Ops.encode(.{
                     .reg1 = tmp_reg.to8(),
                 }),
-                .data = .{ .cc = cc },
+                .data = .{ .cc = ro.eflags },
             });
 
             return self.genSetStack(
@@ -5956,9 +5931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
     const abi_size = @intCast(u32, ty.abiSize(self.target.*));
     switch (mcv) {
         .dead => unreachable,
-        .register_overflow_unsigned,
-        .register_overflow_signed,
-        => unreachable,
+        .register_overflow => unreachable,
         .ptr_stack_offset => |off| {
             if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
                 return self.fail("stack offset too large", .{});