Commit 481bd4761a

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-08-26 19:27:20
stage2 ARM: remove remaining uses of binOp{Register,Immediate}
1 parent 95b8a5f
Changed files (1)
src
arch
src/arch/arm/CodeGen.zig
@@ -1264,11 +1264,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
 fn minMax(
     self: *Self,
     tag: Air.Inst.Tag,
-    maybe_inst: ?Air.Inst.Index,
-    lhs: MCValue,
-    rhs: MCValue,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
     lhs_ty: Type,
     rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
 ) !MCValue {
     switch (lhs_ty.zigTypeTag()) {
         .Float => return self.fail("TODO ARM min/max on floats", .{}),
@@ -1278,34 +1278,25 @@ fn minMax(
             assert(lhs_ty.eql(rhs_ty, mod));
             const int_info = lhs_ty.intInfo(self.target.*);
             if (int_info.bits <= 32) {
-                const lhs_is_register = lhs == .register;
-                const rhs_is_register = rhs == .register;
+                var lhs_reg: Register = undefined;
+                var rhs_reg: Register = undefined;
+                var dest_reg: Register = undefined;
 
-                const lhs_reg = switch (lhs) {
-                    .register => |r| r,
-                    else => try self.copyToTmpRegister(lhs_ty, lhs),
+                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 lhs_reg_lock = self.register_manager.lockReg(lhs_reg);
-                defer if (lhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
-
-                const rhs_reg = switch (rhs) {
-                    .register => |r| r,
-                    else => try self.copyToTmpRegister(rhs_ty, rhs),
+                const write_args = [_]WriteArg{
+                    .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
                 };
-                const rhs_reg_lock = self.register_manager.lockReg(rhs_reg);
-                defer if (rhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
-
-                const dest_reg = if (maybe_inst) |inst| blk: {
-                    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-
-                    if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
-                        break :blk lhs_reg;
-                    } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
-                        break :blk rhs_reg;
-                    } else {
-                        break :blk try self.register_manager.allocReg(inst, gp);
-                    }
-                } else try self.register_manager.allocReg(null, gp);
+                try self.allocRegs(
+                    &read_args,
+                    &write_args,
+                    if (maybe_inst) |inst| .{
+                        .corresponding_inst = inst,
+                        .operand_mapping = &.{ 0, 1 },
+                    } else null,
+                );
 
                 // lhs == reg should have been checked by airMinMax
                 //
@@ -1369,15 +1360,17 @@ fn minMax(
 fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
     const tag = self.air.instructions.items(.tag)[inst];
     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 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);
         if (bin_op.lhs == bin_op.rhs) break :result lhs;
 
-        break :result try self.minMax(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
+        break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
     };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
@@ -1538,21 +1531,21 @@ 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);
+                    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_with_overflow => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
+                        .add_with_overflow => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
                         .sub_with_overflow => false,
                         else => unreachable,
                     };
                     const rhs_immediate_ok = switch (tag) {
                         .add_with_overflow,
                         .sub_with_overflow,
-                        => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
+                        => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
                         else => unreachable,
                     };
 
@@ -1567,12 +1560,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                     const dest = blk: {
                         if (rhs_immediate_ok) {
-                            break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null);
+                            break :blk try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, null);
                         } else if (lhs_immediate_ok) {
                             // swap lhs and rhs
-                            break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null);
+                            break :blk try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, null);
                         } else {
-                            break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null);
+                            break :blk try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null);
                         }
                     };
 
@@ -1599,8 +1592,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
     const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
     if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
     const result: MCValue = 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);
 
@@ -1625,7 +1618,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                         .unsigned => .mul,
                     };
 
-                    const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
+                    const dest = try self.binOpRegisterNew(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);
@@ -1660,45 +1653,26 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                         .unsigned => .umull,
                     };
 
-                    // TODO extract umull etc. to binOpTwoRegister
-                    // once MCValue.rr is implemented
-                    const lhs_is_register = lhs == .register;
-                    const rhs_is_register = rhs == .register;
-
-                    const lhs_lock: ?RegisterLock = if (lhs_is_register)
-                        self.register_manager.lockReg(lhs.register)
-                    else
-                        null;
-                    defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
-
-                    const lhs_reg = if (lhs_is_register)
-                        lhs.register
-                    else
-                        try self.register_manager.allocReg(null, gp);
-                    const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
-                    defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
-
-                    const rhs_reg = if (rhs_is_register)
-                        rhs.register
-                    else
-                        try self.register_manager.allocReg(null, gp);
-                    const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
-                    defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
-
-                    const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
-                    const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
-                    defer for (dest_regs_locks) |reg| {
-                        self.register_manager.unlockReg(reg);
-                    };
-                    const rdlo = dest_regs[0];
-                    const rdhi = dest_regs[1];
-
-                    if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
-                    if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
+                    var lhs_reg: Register = undefined;
+                    var rhs_reg: Register = undefined;
+                    var rdhi: Register = undefined;
+                    var rdlo: Register = undefined;
+                    var truncated_reg: Register = undefined;
 
-                    const truncated_reg = try self.register_manager.allocReg(null, gp);
-                    const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
-                    defer self.register_manager.unlockReg(truncated_reg_lock);
+                    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 = &rdhi },
+                        .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &rdlo },
+                        .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &truncated_reg },
+                    };
+                    try self.allocRegs(
+                        &read_args,
+                        &write_args,
+                        null,
+                    );
 
                     _ = try self.addInst(.{
                         .tag = base_tag,
@@ -2933,172 +2907,10 @@ fn allocRegs(
     }
 }
 
-/// Don't call this function directly. Use binOp instead.
+/// Wrapper around allocRegs and addInst tailored for specific Mir
+/// instructions which are binary operations acting on two registers
 ///
-/// Calling this function signals an intention to generate a Mir
-/// instruction of the form
-///
-///     op dest, lhs, rhs
-///
-/// Asserts that generating an instruction of that form is possible.
-fn binOpRegister(
-    self: *Self,
-    mir_tag: Mir.Inst.Tag,
-    lhs: MCValue,
-    rhs: MCValue,
-    lhs_ty: Type,
-    rhs_ty: Type,
-    metadata: ?BinOpMetadata,
-) !MCValue {
-    var lhs_reg: Register = undefined;
-    var rhs_reg: Register = undefined;
-    var dest_reg: Register = undefined;
-
-    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 };
-    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 (metadata) |md| .{
-            .corresponding_inst = md.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 };
-}
-
-/// Don't call this function directly. Use binOp instead.
-///
-/// Calling this function signals an intention to generate a Mir
-/// instruction of the form
-///
-///     op dest, lhs, #rhs_imm
-///
-/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
-/// rhs and vice versa. This parameter is only used when maybe_inst !=
-/// null.
-///
-/// Asserts that generating an instruction of that form is possible.
-fn binOpImmediate(
-    self: *Self,
-    mir_tag: Mir.Inst.Tag,
-    lhs: MCValue,
-    rhs: MCValue,
-    lhs_ty: Type,
-    lhs_and_rhs_swapped: bool,
-    metadata: ?BinOpMetadata,
-) !MCValue {
-    var lhs_reg: Register = undefined;
-    var dest_reg: Register = undefined;
-
-    const lhs_bind = blk: {
-        if (metadata) |md| {
-            const inst = if (lhs_and_rhs_swapped) md.rhs else md.lhs;
-            break :blk ReadArg.Bind{ .inst = inst };
-        } else {
-            break :blk ReadArg.Bind{ .mcv = lhs };
-        }
-    };
-
-    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 (metadata) |md| .{
-            .corresponding_inst = md.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 };
-}
-
-/// TODO
+/// Returns the destination register
 fn binOpRegisterNew(
     self: *Self,
     mir_tag: Mir.Inst.Tag,
@@ -3167,7 +2979,11 @@ fn binOpRegisterNew(
     return MCValue{ .register = dest_reg };
 }
 
-/// TODO
+/// Wrapper around allocRegs and addInst tailored for specific Mir
+/// instructions which are binary operations acting on a register and
+/// an immediate
+///
+/// Returns the destination register
 fn binOpImmediateNew(
     self: *Self,
     mir_tag: Mir.Inst.Tag,
@@ -3228,12 +3044,6 @@ fn binOpImmediateNew(
     return MCValue{ .register = dest_reg };
 }
 
-const BinOpMetadata = struct {
-    inst: Air.Inst.Index,
-    lhs: Air.Inst.Ref,
-    rhs: Air.Inst.Ref,
-};
-
 fn addSub(
     self: *Self,
     tag: Air.Inst.Tag,