Commit 86dd123392

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-08-20 22:29:52
stage2 ARM: move cmp to new allocReg mechanism; remove from binOp
1 parent 0414ef5
Changed files (1)
src
arch
src/arch/arm/CodeGen.zig
@@ -1315,7 +1315,13 @@ fn minMax(
                 // register.
                 assert(lhs_reg != rhs_reg); // see note above
 
-                _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null);
+                _ = try self.addInst(.{
+                    .tag = .cmp,
+                    .data = .{ .r_op_cmp = .{
+                        .rn = lhs_reg,
+                        .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
+                    } },
+                });
 
                 const cond_choose_lhs: Condition = switch (tag) {
                     .max => switch (int_info.signedness) {
@@ -1473,7 +1479,6 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
 
                     try self.spillCompareFlagsIfOccupied();
-                    self.cpsr_flags_inst = null;
 
                     const base_tag: Air.Inst.Tag = switch (tag) {
                         .add_with_overflow => .add,
@@ -1493,7 +1498,13 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
 
                     // cmp dest, truncated
-                    _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
+                    _ = try self.addInst(.{
+                        .tag = .cmp,
+                        .data = .{ .r_op_cmp = .{
+                            .rn = dest_reg,
+                            .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none),
+                        } },
+                    });
 
                     try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
                     try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
@@ -1578,7 +1589,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
 
                     try self.spillCompareFlagsIfOccupied();
-                    self.cpsr_flags_inst = null;
 
                     const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
                         .signed => .smulbb,
@@ -1598,7 +1608,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
 
                     // cmp dest, truncated
-                    _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
+                    _ = try self.addInst(.{
+                        .tag = .cmp,
+                        .data = .{ .r_op_cmp = .{
+                            .rn = dest_reg,
+                            .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none),
+                        } },
+                    });
 
                     try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
                     try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
@@ -1608,7 +1624,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
 
                     try self.spillCompareFlagsIfOccupied();
-                    self.cpsr_flags_inst = null;
 
                     const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
                         .signed => .smull,
@@ -1672,7 +1687,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
 
                     // cmp truncated, rdlo
-                    _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null);
+                    _ = try self.addInst(.{
+                        .tag = .cmp,
+                        .data = .{ .r_op_cmp = .{
+                            .rn = truncated_reg,
+                            .op = Instruction.Operand.reg(rdlo, Instruction.Operand.Shift.none),
+                        } },
+                    });
 
                     // mov rdlo, #0
                     _ = try self.addInst(.{
@@ -1694,7 +1715,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                     });
 
                     // cmp rdhi, #0
-                    _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null);
+                    _ = try self.addInst(.{
+                        .tag = .cmp,
+                        .data = .{ .r_op_cmp = .{
+                            .rn = rdhi,
+                            .op = Instruction.Operand.fromU32(0).?,
+                        } },
+                    });
 
                     // movne rdlo, #1
                     _ = try self.addInst(.{
@@ -1725,8 +1752,6 @@ fn airShlWithOverflow(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_ty = self.air.typeOf(extra.lhs);
         const rhs_ty = self.air.typeOf(extra.rhs);
 
@@ -1742,28 +1767,107 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 if (int_info.bits <= 32) {
                     const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
 
-                    const lhs_lock: ?RegisterLock = if (lhs == .register)
-                        self.register_manager.lockRegAssumeUnused(lhs.register)
-                    else
-                        null;
-                    defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
-
                     try self.spillCompareFlagsIfOccupied();
-                    self.cpsr_flags_inst = null;
 
-                    // lsl dest, lhs, rhs
-                    const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
-                    const dest_reg = dest.register;
-                    const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
-                    defer self.register_manager.unlockReg(dest_lock);
+                    const shr_mir_tag: Mir.Inst.Tag = switch (int_info.signedness) {
+                        .signed => Mir.Inst.Tag.asr,
+                        .unsigned => Mir.Inst.Tag.lsr,
+                    };
+
+                    var lhs_reg: Register = undefined;
+                    var rhs_reg: Register = undefined;
+                    var dest_reg: Register = undefined;
+                    var reconstructed_reg: Register = undefined;
+
+                    const rhs_mcv = try self.resolveInst(extra.rhs);
+                    const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null;
+
+                    const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
+                    const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
+
+                    if (rhs_immediate_ok) {
+                        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 },
+                            .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg },
+                        };
+                        try self.allocRegs(
+                            &read_args,
+                            &write_args,
+                            null,
+                        );
+
+                        // lsl dest, lhs, rhs
+                        _ = try self.addInst(.{
+                            .tag = .lsl,
+                            .data = .{ .rr_shift = .{
+                                .rd = dest_reg,
+                                .rm = lhs_reg,
+                                .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)),
+                            } },
+                        });
 
-                    // asr/lsr reconstructed, dest, rhs
-                    const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
+                        try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
+
+                        // asr/lsr reconstructed, dest, rhs
+                        _ = try self.addInst(.{
+                            .tag = shr_mir_tag,
+                            .data = .{ .rr_shift = .{
+                                .rd = reconstructed_reg,
+                                .rm = dest_reg,
+                                .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)),
+                            } },
+                        });
+                    } else {
+                        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 },
+                            .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg },
+                        };
+                        try self.allocRegs(
+                            &read_args,
+                            &write_args,
+                            null,
+                        );
+
+                        // lsl dest, lhs, rhs
+                        _ = try self.addInst(.{
+                            .tag = .lsl,
+                            .data = .{ .rr_shift = .{
+                                .rd = dest_reg,
+                                .rm = lhs_reg,
+                                .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
+                            } },
+                        });
+
+                        try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
+
+                        // asr/lsr reconstructed, dest, rhs
+                        _ = try self.addInst(.{
+                            .tag = shr_mir_tag,
+                            .data = .{ .rr_shift = .{
+                                .rd = reconstructed_reg,
+                                .rm = dest_reg,
+                                .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
+                            } },
+                        });
+                    }
 
                     // cmp lhs, reconstructed
-                    _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
+                    _ = try self.addInst(.{
+                        .tag = .cmp,
+                        .data = .{ .r_op_cmp = .{
+                            .rn = lhs_reg,
+                            .op = Instruction.Operand.reg(reconstructed_reg, Instruction.Operand.Shift.none),
+                        } },
+                    });
 
-                    try self.genSetStack(lhs_ty, stack_offset, dest);
+                    try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg });
                     try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
 
                     break :result MCValue{ .stack_offset = stack_offset };
@@ -2662,8 +2766,8 @@ fn allocRegs(
     write_args: []const WriteArg,
     reuse_metadata: ?ReuseMetadata,
 ) InnerError!void {
-    // Air instructions have either one output or none (cmp)
-    assert(!(reuse_metadata != null and write_args.len > 1)); // see note above
+    // Air instructions have exactly one output
+    assert(!(reuse_metadata != null and write_args.len != 1)); // see note above
 
     // The operand mapping is a 1:1 mapping of read args to their
     // corresponding operand index in the Air instruction
@@ -2714,7 +2818,7 @@ fn allocRegs(
         }
     }
 
-    if (reuse_metadata != null and write_args.len > 0) {
+    if (reuse_metadata != null) {
         const inst = reuse_metadata.?.corresponding_inst;
         const operand_mapping = reuse_metadata.?.operand_mapping;
         const arg = write_args[0];
@@ -2826,7 +2930,7 @@ fn binOpRegister(
     };
     try self.allocRegs(
         &read_args,
-        if (mir_tag == .cmp) &.{} else &write_args,
+        &write_args,
         if (metadata) |md| .{
             .corresponding_inst = md.inst,
             .operand_mapping = &.{ 0, 1 },
@@ -2846,10 +2950,6 @@ fn binOpRegister(
             .rn = lhs_reg,
             .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
         } },
-        .cmp => .{ .r_op_cmp = .{
-            .rn = lhs_reg,
-            .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
-        } },
         .lsl,
         .asr,
         .lsr,
@@ -2918,7 +3018,7 @@ fn binOpImmediate(
     const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0};
     try self.allocRegs(
         &read_args,
-        if (mir_tag == .cmp) &.{} else &write_args,
+        &write_args,
         if (metadata) |md| .{
             .corresponding_inst = md.inst,
             .operand_mapping = operand_mapping,
@@ -2938,10 +3038,6 @@ fn binOpImmediate(
             .rn = lhs_reg,
             .op = Instruction.Operand.fromU32(rhs.immediate).?,
         } },
-        .cmp => .{ .r_op_cmp = .{
-            .rn = lhs_reg,
-            .op = Instruction.Operand.fromU32(rhs.immediate).?,
-        } },
         .lsl,
         .asr,
         .lsr,
@@ -2991,7 +3087,6 @@ fn binOp(
     switch (tag) {
         .add,
         .sub,
-        .cmp_eq,
         => {
             switch (lhs_ty.zigTypeTag()) {
                 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
@@ -3006,15 +3101,12 @@ fn binOp(
                         // operands
                         const lhs_immediate_ok = switch (tag) {
                             .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
-                            .sub,
-                            .cmp_eq,
-                            => false,
+                            .sub => false,
                             else => unreachable,
                         };
                         const rhs_immediate_ok = switch (tag) {
                             .add,
                             .sub,
-                            .cmp_eq,
                             => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
                             else => unreachable,
                         };
@@ -3022,7 +3114,6 @@ fn binOp(
                         const mir_tag: Mir.Inst.Tag = switch (tag) {
                             .add => .add,
                             .sub => .sub,
-                            .cmp_eq => .cmp,
                             else => unreachable,
                         };
 
@@ -4005,32 +4096,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
     const lhs_ty = self.air.typeOf(bin_op.lhs);
 
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
-        const operands: BinOpOperands = .{ .inst = .{
-            .inst = inst,
-            .lhs = bin_op.lhs,
-            .rhs = bin_op.rhs,
-        } };
-        break :blk try self.cmp(operands, lhs_ty, op);
+        break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op);
     };
 
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
-const BinOpOperands = union(enum) {
-    inst: struct {
-        inst: Air.Inst.Index,
-        lhs: Air.Inst.Ref,
-        rhs: Air.Inst.Ref,
-    },
-    mcv: struct {
-        lhs: MCValue,
-        rhs: MCValue,
-    },
-};
-
 fn cmp(
     self: *Self,
-    operands: BinOpOperands,
+    lhs: ReadArg.Bind,
+    rhs: ReadArg.Bind,
     lhs_ty: Type,
     op: math.CompareOperator,
 ) !MCValue {
@@ -4060,22 +4135,47 @@ fn cmp(
     if (int_info.bits <= 32) {
         try self.spillCompareFlagsIfOccupied();
 
-        switch (operands) {
-            .inst => |inst_op| {
-                const metadata: BinOpMetadata = .{
-                    .inst = inst_op.inst,
-                    .lhs = inst_op.lhs,
-                    .rhs = inst_op.rhs,
-                };
-                const lhs = try self.resolveInst(inst_op.lhs);
-                const rhs = try self.resolveInst(inst_op.rhs);
+        var lhs_reg: Register = undefined;
+        var rhs_reg: Register = undefined;
 
-                self.cpsr_flags_inst = inst_op.inst;
-                _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, metadata);
-            },
-            .mcv => |mcv_op| {
-                _ = try self.binOp(.cmp_eq, mcv_op.lhs, mcv_op.rhs, int_ty, int_ty, null);
-            },
+        const rhs_mcv = try rhs.resolveToMcv(self);
+        const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null;
+
+        if (rhs_immediate_ok) {
+            const read_args = [_]ReadArg{
+                .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg },
+            };
+            try self.allocRegs(
+                &read_args,
+                &.{},
+                null, // we won't be able to reuse a register as there are no write_regs
+            );
+
+            _ = try self.addInst(.{
+                .tag = .cmp,
+                .data = .{ .r_op_cmp = .{
+                    .rn = lhs_reg,
+                    .op = Instruction.Operand.fromU32(rhs_mcv.immediate).?,
+                } },
+            });
+        } else {
+            const read_args = [_]ReadArg{
+                .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg },
+                .{ .ty = int_ty, .bind = rhs, .class = gp, .reg = &rhs_reg },
+            };
+            try self.allocRegs(
+                &read_args,
+                &.{},
+                null, // we won't be able to reuse a register as there are no write_regs
+            );
+
+            _ = try self.addInst(.{
+                .tag = .cmp,
+                .data = .{ .r_op_cmp = .{
+                    .rn = lhs_reg,
+                    .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
+                } },
+            });
         }
 
         return switch (int_info.signedness) {
@@ -4349,14 +4449,13 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
 
 fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
     const error_type = ty.errorUnionSet();
-    const error_int_type = Type.initTag(.u16);
 
     if (error_type.errorSetIsEmpty()) {
         return MCValue{ .immediate = 0 }; // always false
     }
 
     const error_mcv = try self.errUnionErr(operand, ty);
-    _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
+    _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq);
     return MCValue{ .cpsr_flags = .hi };
 }
 
@@ -4587,14 +4686,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
         defer self.gpa.free(branch_into_prong_relocs);
 
         for (items) |item, idx| {
-            const condition = try self.resolveInst(pl_op.operand);
-            const item_mcv = try self.resolveInst(item);
-
-            const operands: BinOpOperands = .{ .mcv = .{
-                .lhs = condition,
-                .rhs = item_mcv,
-            } };
-            const cmp_result = try self.cmp(operands, condition_ty, .neq);
+            const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq);
             branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
         }