Commit af3ecd04b4

Jakub Konka <kubkon@jakubkonka.com>
2022-05-10 09:04:39
x64: make genBinOp operate on MCValues directly
1 parent 252c5a2
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -1089,8 +1089,15 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
 
 fn airNot(self: *Self, inst: Air.Inst.Index) !void {
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
-        const operand = try self.resolveInst(ty_op.operand);
+
+    if (self.liveness.isUnused(inst)) {
+        return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
+    }
+
+    const operand_ty = self.air.typeOf(ty_op.operand);
+    const operand = try self.resolveInst(ty_op.operand);
+
+    const result: MCValue = result: {
         switch (operand) {
             .dead => unreachable,
             .unreach => unreachable,
@@ -1122,7 +1129,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
             },
             else => {},
         }
-        break :result try self.genBinOp(.not, inst, ty_op.operand, .bool_true);
+
+        const operand_lock: ?RegisterLock = switch (operand) {
+            .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+            else => null,
+        };
+        defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
+
+        const dst_mcv: MCValue = blk: {
+            if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) {
+                break :blk operand;
+            }
+            break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand);
+        };
+        const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
+            .register => |reg| self.register_manager.lockReg(reg),
+            else => null,
+        };
+        defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
+
+        try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = 1 });
+
+        break :result dst_mcv;
     };
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
@@ -1214,7 +1242,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
     }
 
     const tag = self.air.instructions.items(.tag)[inst];
-    const result = try self.genBinOp(tag, inst, bin_op.lhs, bin_op.rhs);
+    const lhs = try self.resolveInst(bin_op.lhs);
+    const rhs = try self.resolveInst(bin_op.rhs);
+    const lhs_ty = self.air.typeOf(bin_op.lhs);
+    const rhs_ty = self.air.typeOf(bin_op.rhs);
+
+    const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
+
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
@@ -1263,7 +1297,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 try self.spillCompareFlagsIfOccupied();
                 self.compare_flags_inst = inst;
 
-                const partial = try self.genBinOp(.add, inst, bin_op.lhs, bin_op.rhs);
+                const lhs = try self.resolveInst(bin_op.lhs);
+                const rhs = try self.resolveInst(bin_op.rhs);
+
+                const partial = try self.genBinOp(.add, null, lhs, rhs, ty, ty);
                 const result: MCValue = switch (int_info.signedness) {
                     .signed => .{ .register_overflow_signed = partial.register },
                     .unsigned => .{ .register_overflow_unsigned = partial.register },
@@ -1295,7 +1332,10 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 try self.spillCompareFlagsIfOccupied();
                 self.compare_flags_inst = inst;
 
-                const partial = try self.genBinOp(.sub, inst, bin_op.lhs, bin_op.rhs);
+                const lhs = try self.resolveInst(bin_op.lhs);
+                const rhs = try self.resolveInst(bin_op.rhs);
+
+                const partial = try self.genBinOp(.sub, null, lhs, rhs, ty, ty);
                 const result: MCValue = switch (int_info.signedness) {
                     .signed => .{ .register_overflow_signed = partial.register },
                     .unsigned => .{ .register_overflow_unsigned = partial.register },
@@ -1330,9 +1370,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                 try self.spillCompareFlagsIfOccupied();
 
+                const lhs = try self.resolveInst(bin_op.lhs);
+                const rhs = try self.resolveInst(bin_op.rhs);
+
                 if (math.isPowerOfTwo(int_info.bits)) {
                     self.compare_flags_inst = inst;
-                    const partial = try self.genBinOp(.mul, inst, bin_op.lhs, bin_op.rhs);
+                    const partial = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
                     break :result switch (int_info.signedness) {
                         .signed => MCValue{ .register_overflow_signed = partial.register },
                         .unsigned => MCValue{ .register_overflow_unsigned = partial.register },
@@ -1344,9 +1387,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 const dst_reg: Register = dst_reg: {
                     switch (int_info.signedness) {
                         .signed => {
-                            const lhs = try self.resolveInst(bin_op.lhs);
-                            const rhs = try self.resolveInst(bin_op.rhs);
-
                             const rhs_lock: ?RegisterLock = switch (rhs) {
                                 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
                                 else => null,
@@ -1375,7 +1415,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                             break :dst_reg dst_reg;
                         },
                         .unsigned => {
-                            const dst_mcv = try self.genBinOp(.mul, null, bin_op.lhs, bin_op.rhs);
+                            const dst_mcv = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
                             break :dst_reg dst_mcv.register;
                         },
                     }
@@ -3137,8 +3177,10 @@ fn genBinOp(
     self: *Self,
     tag: Air.Inst.Tag,
     maybe_inst: ?Air.Inst.Index,
-    op_lhs: Air.Inst.Ref,
-    op_rhs: Air.Inst.Ref,
+    lhs: MCValue,
+    rhs: MCValue,
+    lhs_ty: Type,
+    rhs_ty: Type,
 ) !MCValue {
     const is_commutative: bool = switch (tag) {
         .add,
@@ -3148,7 +3190,6 @@ fn genBinOp(
         .bool_and,
         .bit_and,
         .xor,
-        .not,
         => true,
 
         .sub,
@@ -3169,14 +3210,12 @@ fn genBinOp(
 
         else => unreachable,
     };
-    const dst_ty = self.air.typeOf(op_lhs);
-    const src_ty = self.air.typeOf(op_rhs);
 
-    if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {
-        return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
+    if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
+        return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
     }
-    if (dst_ty.abiSize(self.target.*) > 8) {
-        return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
+    if (lhs_ty.abiSize(self.target.*) > 8) {
+        return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
     }
 
     switch (tag) {
@@ -3191,24 +3230,21 @@ fn genBinOp(
                 self.register_manager.unlockReg(reg);
             };
 
-            const lhs = try self.resolveInst(op_lhs);
-            const rhs = try self.resolveInst(op_rhs);
-
-            const int_info = dst_ty.intInfo(self.target.*);
+            const int_info = lhs_ty.intInfo(self.target.*);
             try self.genIntMulDivOpMir(switch (int_info.signedness) {
                 .signed => .imul,
                 .unsigned => .mul,
-            }, dst_ty, int_info.signedness, lhs, rhs);
+            }, lhs_ty, int_info.signedness, lhs, rhs);
 
             return switch (int_info.signedness) {
                 .signed => MCValue{ .register = .rax },
-                .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) },
+                .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, lhs_ty.abiSize(self.target.*))) },
             };
         },
         .mod,
         .rem,
         => {
-            const int_info = dst_ty.intInfo(self.target.*);
+            const int_info = lhs_ty.intInfo(self.target.*);
             const track_inst_rdx: ?Air.Inst.Index = switch (tag) {
                 .mod => if (int_info.signedness == .unsigned) maybe_inst else null,
                 .rem => maybe_inst,
@@ -3223,27 +3259,24 @@ fn genBinOp(
                 self.register_manager.unlockReg(reg);
             };
 
-            const lhs = try self.resolveInst(op_lhs);
-            const rhs = try self.resolveInst(op_rhs);
-
             switch (int_info.signedness) {
                 .signed => {
                     switch (tag) {
                         .rem => {
-                            try self.genIntMulDivOpMir(.idiv, dst_ty, .signed, lhs, rhs);
+                            try self.genIntMulDivOpMir(.idiv, lhs_ty, .signed, lhs, rhs);
                             return MCValue{ .register = .rdx };
                         },
                         .mod => {
-                            const div_floor = try self.genInlineIntDivFloor(dst_ty, lhs, rhs);
-                            try self.genIntMulComplexOpMir(dst_ty, div_floor, rhs);
+                            const div_floor = try self.genInlineIntDivFloor(lhs_ty, lhs, rhs);
+                            try self.genIntMulComplexOpMir(lhs_ty, div_floor, rhs);
                             const div_floor_lock = self.register_manager.lockReg(div_floor.register);
                             defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
 
                             const result: MCValue = if (maybe_inst) |inst|
-                                try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs)
+                                try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs)
                             else
-                                MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };
-                            try self.genBinOpMir(.sub, dst_ty, result, div_floor);
+                                MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
+                            try self.genBinOpMir(.sub, lhs_ty, result, div_floor);
 
                             return result;
                         },
@@ -3251,7 +3284,7 @@ fn genBinOp(
                     }
                 },
                 .unsigned => {
-                    try self.genIntMulDivOpMir(.div, dst_ty, .unsigned, lhs, rhs);
+                    try self.genIntMulDivOpMir(.div, lhs_ty, .unsigned, lhs, rhs);
                     return MCValue{ .register = .rdx };
                 },
             }
@@ -3259,14 +3292,12 @@ fn genBinOp(
         else => {},
     }
 
-    const lhs = try self.resolveInst(op_lhs);
     const lhs_lock: ?RegisterLock = switch (lhs) {
         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
         else => null,
     };
     defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
 
-    const rhs = try self.resolveInst(op_rhs);
     const rhs_lock: ?RegisterLock = switch (rhs) {
         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
         else => null,
@@ -3276,16 +3307,17 @@ fn genBinOp(
     var flipped: bool = false;
     const dst_mcv: MCValue = blk: {
         if (maybe_inst) |inst| {
-            if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
+            const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+            if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
                 break :blk lhs;
             }
-            if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) {
+            if (is_commutative and self.reuseOperand(inst, bin_op.rhs, 1, rhs) and rhs.isRegister()) {
                 flipped = true;
                 break :blk rhs;
             }
-            break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);
+            break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
         }
-        break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };
+        break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
     };
     const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
         .register => |reg| self.register_manager.lockReg(reg),
@@ -3296,7 +3328,7 @@ fn genBinOp(
     const src_mcv: MCValue = blk: {
         const mcv = if (flipped) lhs else rhs;
         if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;
-        break :blk MCValue{ .register = try self.copyToTmpRegister(src_ty, mcv) };
+        break :blk MCValue{ .register = try self.copyToTmpRegister(rhs_ty, mcv) };
     };
     const src_mcv_lock: ?RegisterLock = switch (src_mcv) {
         .register => |reg| self.register_manager.lockReg(reg),
@@ -3307,11 +3339,11 @@ fn genBinOp(
     switch (tag) {
         .add,
         .addwrap,
-        => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv),
+        => try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),
 
         .sub,
         .subwrap,
-        => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv),
+        => try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),
 
         .ptr_add,
         .ptr_sub,
@@ -3321,22 +3353,20 @@ fn genBinOp(
                 .ptr_sub => .sub,
                 else => unreachable,
             };
-            const elem_size = dst_ty.elemType2().abiSize(self.target.*);
-            try self.genIntMulComplexOpMir(src_ty, src_mcv, .{ .immediate = elem_size });
-            try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv);
+            const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
+            try self.genIntMulComplexOpMir(rhs_ty, src_mcv, .{ .immediate = elem_size });
+            try self.genBinOpMir(mir_tag, lhs_ty, dst_mcv, src_mcv);
         },
 
         .bool_or,
         .bit_or,
-        => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
+        => try self.genBinOpMir(.@"or", lhs_ty, dst_mcv, src_mcv),
 
         .bool_and,
         .bit_and,
-        => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
+        => try self.genBinOpMir(.@"and", lhs_ty, dst_mcv, src_mcv),
 
-        .xor,
-        .not,
-        => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv),
+        .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv),
 
         else => unreachable,
     }