Commit ed4be06883

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-08-21 13:43:09
stage2 ARM: extract add+sub from binOp
This commit also lays the groundwork for further extractions from binOp.
1 parent 86dd123
Changed files (1)
src
arch
src/arch/arm/CodeGen.zig
@@ -1401,19 +1401,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
 
 fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
     const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-    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: MCValue = if (self.liveness.isUnused(inst))
-        .dead
-    else
-        try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
-            .lhs = bin_op.lhs,
-            .rhs = bin_op.rhs,
-            .inst = inst,
-        });
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+        const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
+        const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
+        const lhs = try self.resolveInst(bin_op.lhs);
+        const rhs = try self.resolveInst(bin_op.rhs);
+
+        switch (tag) {
+            .add,
+            .sub,
+            => break :result try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            else => break :result try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
+                .lhs = bin_op.lhs,
+                .rhs = bin_op.rhs,
+                .inst = inst,
+            }),
+        }
+    };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
@@ -1459,8 +1466,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
     const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
     const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
-        const lhs = try self.resolveInst(extra.lhs);
-        const rhs = try self.resolveInst(extra.rhs);
+        const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
+        const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
         const lhs_ty = self.air.typeOf(extra.lhs);
         const rhs_ty = self.air.typeOf(extra.rhs);
 
@@ -1485,7 +1492,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
                         .sub_with_overflow => .sub,
                         else => unreachable,
                     };
-                    const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
+                    const dest = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null);
                     const dest_reg = dest.register;
                     const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
                     defer self.register_manager.unlockReg(dest_reg_lock);
@@ -1511,6 +1518,9 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                     break :result MCValue{ .stack_offset = stack_offset };
                 } else if (int_info.bits == 32) {
+                    const lhs = try self.resolveInst(extra.lhs);
+                    const rhs = try self.resolveInst(extra.rhs);
+
                     // Only say yes if the operation is
                     // commutative, i.e. we can swap both of the
                     // operands
@@ -2600,26 +2610,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
                 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };
             },
             else => {
-                const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
-                    .immediate = struct_field_offset,
-                });
-                const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
-                defer self.register_manager.unlockReg(offset_reg_lock);
-
-                const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv);
-                const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
-                defer self.register_manager.unlockReg(addr_reg_lock);
+                const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
+                const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = struct_field_offset } };
 
-                const dest = try self.binOp(
-                    .add,
-                    .{ .register = addr_reg },
-                    .{ .register = offset_reg },
-                    Type.usize,
-                    Type.usize,
-                    null,
-                );
-
-                break :result dest;
+                break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
             },
         }
     };
@@ -2708,6 +2702,25 @@ const ReadArg = struct {
                 .mcv => |mcv| mcv,
             };
         }
+
+        fn resolveToImmediate(bind: Bind, function: *Self) InnerError!?u32 {
+            switch (bind) {
+                .inst => |inst| {
+                    // TODO resolve independently of inst_table
+                    const mcv = try function.resolveInst(inst);
+                    switch (mcv) {
+                        .immediate => |imm| return imm,
+                        else => return null,
+                    }
+                },
+                .mcv => |mcv| {
+                    switch (mcv) {
+                        .immediate => |imm| return imm,
+                        else => return null,
+                    }
+                },
+            }
+        }
     };
 };
 
@@ -3057,6 +3070,136 @@ fn binOpImmediate(
     return MCValue{ .register = dest_reg };
 }
 
+/// TODO
+fn binOpRegisterNew(
+    self: *Self,
+    mir_tag: Mir.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) !MCValue {
+    var lhs_reg: Register = undefined;
+    var rhs_reg: Register = undefined;
+    var dest_reg: Register = undefined;
+
+    const read_args = [_]ReadArg{
+        .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
+        .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
+    };
+    const write_args = [_]WriteArg{
+        .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
+    };
+    try self.allocRegs(
+        &read_args,
+        &write_args,
+        if (maybe_inst) |inst| .{
+            .corresponding_inst = inst,
+            .operand_mapping = &.{ 0, 1 },
+        } else null,
+    );
+
+    const mir_data: Mir.Inst.Data = switch (mir_tag) {
+        .add,
+        .adds,
+        .sub,
+        .subs,
+        .@"and",
+        .orr,
+        .eor,
+        => .{ .rr_op = .{
+            .rd = dest_reg,
+            .rn = lhs_reg,
+            .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
+        } },
+        .lsl,
+        .asr,
+        .lsr,
+        => .{ .rr_shift = .{
+            .rd = dest_reg,
+            .rm = lhs_reg,
+            .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
+        } },
+        .mul,
+        .smulbb,
+        => .{ .rrr = .{
+            .rd = dest_reg,
+            .rn = lhs_reg,
+            .rm = rhs_reg,
+        } },
+        else => unreachable,
+    };
+
+    _ = try self.addInst(.{
+        .tag = mir_tag,
+        .data = mir_data,
+    });
+
+    return MCValue{ .register = dest_reg };
+}
+
+/// TODO
+fn binOpImmediateNew(
+    self: *Self,
+    mir_tag: Mir.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_immediate: u32,
+    lhs_ty: Type,
+    lhs_and_rhs_swapped: bool,
+    maybe_inst: ?Air.Inst.Index,
+) !MCValue {
+    var lhs_reg: Register = undefined;
+    var dest_reg: Register = undefined;
+
+    const read_args = [_]ReadArg{
+        .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
+    };
+    const write_args = [_]WriteArg{
+        .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
+    };
+    const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0};
+    try self.allocRegs(
+        &read_args,
+        &write_args,
+        if (maybe_inst) |inst| .{
+            .corresponding_inst = inst,
+            .operand_mapping = operand_mapping,
+        } else null,
+    );
+
+    const mir_data: Mir.Inst.Data = switch (mir_tag) {
+        .add,
+        .adds,
+        .sub,
+        .subs,
+        .@"and",
+        .orr,
+        .eor,
+        => .{ .rr_op = .{
+            .rd = dest_reg,
+            .rn = lhs_reg,
+            .op = Instruction.Operand.fromU32(rhs_immediate).?,
+        } },
+        .lsl,
+        .asr,
+        .lsr,
+        => .{ .rr_shift = .{
+            .rd = dest_reg,
+            .rm = lhs_reg,
+            .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_immediate)),
+        } },
+        else => unreachable,
+    };
+
+    _ = try self.addInst(.{
+        .tag = mir_tag,
+        .data = mir_data,
+    });
+
+    return MCValue{ .register = dest_reg };
+}
+
 const BinOpMetadata = struct {
     inst: Air.Inst.Index,
     lhs: Air.Inst.Ref,
@@ -3085,53 +3228,6 @@ fn binOp(
     metadata: ?BinOpMetadata,
 ) InnerError!MCValue {
     switch (tag) {
-        .add,
-        .sub,
-        => {
-            switch (lhs_ty.zigTypeTag()) {
-                .Float => return self.fail("TODO ARM binary operations on floats", .{}),
-                .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
-                .Int => {
-                    const mod = self.bin_file.options.module.?;
-                    assert(lhs_ty.eql(rhs_ty, mod));
-                    const int_info = lhs_ty.intInfo(self.target.*);
-                    if (int_info.bits <= 32) {
-                        // Only say yes if the operation is
-                        // commutative, i.e. we can swap both of the
-                        // operands
-                        const lhs_immediate_ok = switch (tag) {
-                            .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
-                            .sub => false,
-                            else => unreachable,
-                        };
-                        const rhs_immediate_ok = switch (tag) {
-                            .add,
-                            .sub,
-                            => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
-                            else => unreachable,
-                        };
-
-                        const mir_tag: Mir.Inst.Tag = switch (tag) {
-                            .add => .add,
-                            .sub => .sub,
-                            else => unreachable,
-                        };
-
-                        if (rhs_immediate_ok) {
-                            return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
-                        } else if (lhs_immediate_ok) {
-                            // swap lhs and rhs
-                            return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
-                        } else {
-                            return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
-                        }
-                    } else {
-                        return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
-                    }
-                },
-                else => unreachable,
-            }
-        },
         .mul => {
             switch (lhs_ty.zigTypeTag()) {
                 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
@@ -3278,8 +3374,18 @@ fn binOp(
                 else => unreachable,
             };
 
+            const lhs_bind = if (metadata) |md|
+                ReadArg.Bind{ .inst = md.lhs }
+            else
+                ReadArg.Bind{ .mcv = lhs };
+            const rhs_bind = if (metadata) |md|
+                ReadArg.Bind{ .inst = md.rhs }
+            else
+                ReadArg.Bind{ .mcv = rhs };
+
             // Generate an add/sub/mul
-            const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
+            const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null;
+            const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
 
             // Truncate if necessary
             switch (lhs_ty.zigTypeTag()) {
@@ -3463,6 +3569,63 @@ fn binOp(
     }
 }
 
+fn addSub(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    switch (lhs_ty.zigTypeTag()) {
+        .Float => return self.fail("TODO ARM binary operations on floats", .{}),
+        .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
+        .Int => {
+            const mod = self.bin_file.options.module.?;
+            assert(lhs_ty.eql(rhs_ty, mod));
+            const int_info = lhs_ty.intInfo(self.target.*);
+            if (int_info.bits <= 32) {
+                const lhs_immediate = try lhs_bind.resolveToImmediate(self);
+                const rhs_immediate = try rhs_bind.resolveToImmediate(self);
+
+                // Only say yes if the operation is
+                // commutative, i.e. we can swap both of the
+                // operands
+                const lhs_immediate_ok = switch (tag) {
+                    .add => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
+                    .sub => false,
+                    else => unreachable,
+                };
+                const rhs_immediate_ok = switch (tag) {
+                    .add,
+                    .sub,
+                    => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
+                    else => unreachable,
+                };
+
+                const mir_tag: Mir.Inst.Tag = switch (tag) {
+                    .add => .add,
+                    .sub => .sub,
+                    else => unreachable,
+                };
+
+                if (rhs_immediate_ok) {
+                    return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
+                } else if (lhs_immediate_ok) {
+                    // swap lhs and rhs
+                    return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
+                } else {
+                    return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
+                }
+            } else {
+                return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
+            }
+        },
+        else => unreachable,
+    }
+}
+
 fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
     const abi_size = ty.abiSize(self.target.*);
 
@@ -4138,8 +4301,8 @@ fn cmp(
         var lhs_reg: Register = undefined;
         var rhs_reg: Register = undefined;
 
-        const rhs_mcv = try rhs.resolveToMcv(self);
-        const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null;
+        const rhs_immediate = try rhs.resolveToImmediate(self);
+        const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
 
         if (rhs_immediate_ok) {
             const read_args = [_]ReadArg{
@@ -4155,7 +4318,7 @@ fn cmp(
                 .tag = .cmp,
                 .data = .{ .r_op_cmp = .{
                     .rn = lhs_reg,
-                    .op = Instruction.Operand.fromU32(rhs_mcv.immediate).?,
+                    .op = Instruction.Operand.fromU32(rhs_immediate.?).?,
                 } },
             });
         } else {