Commit 1b7ec44924

Jakub Konka <kubkon@jakubkonka.com>
2022-02-16 15:00:32
x64: separate ptr_add and ptr_sub from normal bin ops
1 parent 3383064
Changed files (1)
src
arch
src/arch/x86_64/CodeGen.zig
@@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
 
         switch (air_tags[inst]) {
             // zig fmt: off
-            .add, .ptr_add   => try self.airAdd(inst),
+            .add             => try self.airAdd(inst),
             .addwrap         => try self.airAddWrap(inst),
             .add_sat         => try self.airAddSat(inst),
-            .sub, .ptr_sub   => try self.airSub(inst),
+            .sub             => try self.airSub(inst),
             .subwrap         => try self.airSubWrap(inst),
             .sub_sat         => try self.airSubSat(inst),
             .mul             => try self.airMul(inst),
@@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .shl_sat         => try self.airShlSat(inst),
             .min             => try self.airMin(inst),
             .max             => try self.airMax(inst),
+            .ptr_add         => try self.airPtrAdd(inst),
+            .ptr_sub         => try self.airPtrSub(inst),
             .slice           => try self.airSlice(inst),
 
             .sqrt,
@@ -1068,6 +1070,70 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
+fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
+    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+    if (self.liveness.isUnused(inst)) {
+        return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
+    }
+
+    const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
+    var dst_mcv = mcvs.dst;
+    const src_mcv = mcvs.src;
+
+    // TODO clean this up
+    // TODO take into account alignment
+    const dst_ty = self.air.typeOfIndex(inst);
+    const elem_size = dst_ty.elemType2().abiSize(self.target.*);
+    const dst_reg = blk: {
+        switch (dst_mcv) {
+            .register => |reg| break :blk reg,
+            else => {
+                src_mcv.freezeIfRegister(&self.register_manager);
+                defer src_mcv.freezeIfRegister(&self.register_manager);
+                const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
+                break :blk reg;
+            },
+        }
+    };
+    try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
+    dst_mcv = .{ .register = dst_reg };
+    try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv);
+
+    return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
+}
+
+fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
+    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+    if (self.liveness.isUnused(inst)) {
+        return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
+    }
+
+    const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
+    var dst_mcv = mcvs.dst;
+    const src_mcv = mcvs.src;
+
+    // TODO clean this up
+    // TODO take into account alignment
+    const dst_ty = self.air.typeOfIndex(inst);
+    const elem_size = dst_ty.elemType2().abiSize(self.target.*);
+    const dst_reg = blk: {
+        switch (dst_mcv) {
+            .register => |reg| break :blk reg,
+            else => {
+                src_mcv.freezeIfRegister(&self.register_manager);
+                defer src_mcv.freezeIfRegister(&self.register_manager);
+                const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
+                break :blk reg;
+            },
+        }
+    };
+    try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
+    dst_mcv = .{ .register = dst_reg };
+    try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv);
+
+    return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
+}
+
 fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
     const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -2148,18 +2214,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
 }
 
-/// Perform "binary" operators, excluding comparisons.
-/// Currently, the following ops are supported:
-/// ADD, SUB, XOR, OR, AND
-fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
-    // We'll handle these ops in two steps.
-    // 1) Prepare an output location (register or memory)
-    //    This location will be the location of the operand that dies (if one exists)
-    //    or just a temporary register (if one doesn't exist)
-    // 2) Perform the op with the other argument
-    // 3) Sometimes, the output location is memory but the op doesn't support it.
-    //    In this case, copy that location to a register, then perform the op to that register instead.
-    //
+const BinMathOpMCValuePair = struct {
+    dst: MCValue,
+    src: MCValue,
+};
+
+fn mcvsForBinMathOp(
+    self: *Self,
+    inst: Air.Inst.Index,
+    op_lhs: Air.Inst.Ref,
+    op_rhs: Air.Inst.Ref,
+) !BinMathOpMCValuePair {
     // TODO: make this algorithm less bad
     const lhs = try self.resolveInst(op_lhs);
     const rhs = try self.resolveInst(op_rhs);
@@ -2218,35 +2283,26 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
                 dst_mcv.freezeIfRegister(&self.register_manager);
                 defer dst_mcv.unfreezeIfRegister(&self.register_manager);
 
-                const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv);
-                src_mcv = MCValue{ .register = tmp_reg };
+                src_mcv = try self.copyToNewRegister(inst, Type.u64, src_mcv);
             }
         },
         else => {},
     }
 
-    // Now for step 2, we assing an MIR instruction
-    const air_tags = self.air.instructions.items(.tag);
-    switch (air_tags[inst]) {
-        .ptr_add => {
-            // TODO clean this up
-            // TODO take into account alignment
-            const elem_size = dst_ty.elemType2().abiSize(self.target.*);
-            const dst_reg = blk: {
-                switch (dst_mcv) {
-                    .register => |reg| break :blk reg,
-                    else => {
-                        src_mcv.freezeIfRegister(&self.register_manager);
-                        defer src_mcv.freezeIfRegister(&self.register_manager);
-                        const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
-                        break :blk reg;
-                    },
-                }
-            };
-            try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
-            dst_mcv = MCValue{ .register = dst_reg };
-            try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv);
-        },
+    return BinMathOpMCValuePair{ .dst = dst_mcv, .src = src_mcv };
+}
+
+/// Perform "binary" operators, excluding comparisons.
+/// Currently, the following ops are supported:
+/// ADD, SUB, XOR, OR, AND
+fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
+    const dst_ty = self.air.typeOfIndex(inst);
+    const mcvs = try self.mcvsForBinMathOp(inst, op_lhs, op_rhs);
+    const dst_mcv = mcvs.dst;
+    const src_mcv = mcvs.src;
+    log.warn("dst_mcv = {}, src_mcv = {}", .{ dst_mcv, src_mcv });
+    const tag = self.air.instructions.items(.tag)[inst];
+    switch (tag) {
         .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
         .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
         .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
@@ -2255,7 +2311,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
         .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
         else => unreachable,
     }
-
     return dst_mcv;
 }