Commit e7fde5f64e

Koakuma <koachan@protonmail.com>
2022-06-12 19:25:24
stage2: sparc64: Introduce condition_register MCValue type
Introduce condition_register MCValue type for future uses with BPr/MOVr (mostly when needing to compare a signed value with zero)
1 parent accc3ba
Changed files (4)
src/arch/sparc64/bits.zig
@@ -475,6 +475,21 @@ pub const Instruction = union(enum) {
         ne_zero,
         gt_zero,
         ge_zero,
+
+        /// Returns the condition which is true iff the given condition is
+        /// false (if such a condition exists).
+        pub fn negate(cond: RCondition) RCondition {
+            return switch (cond) {
+                .eq_zero => .ne_zero,
+                .ne_zero => .eq_zero,
+                .lt_zero => .ge_zero,
+                .ge_zero => .lt_zero,
+                .le_zero => .gt_zero,
+                .gt_zero => .le_zero,
+                .reserved1 => unreachable,
+                .reserved2 => unreachable,
+            };
+        }
     };
 
     pub const ASI = enum(u8) {
src/arch/sparc64/CodeGen.zig
@@ -96,6 +96,9 @@ stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
 /// Tracks the current instruction allocated to the condition flags
 condition_flags_inst: ?Air.Inst.Index = null,
 
+/// Tracks the current instruction allocated to the condition register
+condition_register_inst: ?Air.Inst.Index = null,
+
 /// Offset from the stack base, representing the end of the stack frame.
 max_end_stack: u32 = 0,
 /// Represents the current end stack offset. If there is no existing slot
@@ -148,6 +151,13 @@ const MCValue = union(enum) {
         cond: Instruction.Condition,
         ccr: Instruction.CCR,
     },
+    /// The value is in the specified Register. The value is 1 (if
+    /// the type is u1) or true (if the type in bool) iff the
+    /// specified condition is true.
+    condition_register: struct {
+        cond: Instruction.RCondition,
+        reg: Register,
+    },
 
     fn isMemory(mcv: MCValue) bool {
         return switch (mcv) {
@@ -171,6 +181,8 @@ const MCValue = union(enum) {
 
             .immediate,
             .memory,
+            .condition_flags,
+            .condition_register,
             .ptr_stack_offset,
             .undef,
             => false,
@@ -1748,7 +1760,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                         _ = try self.addInst(.{
                             .tag = .movcc,
                             .data = .{
-                                .conditional_move = .{
+                                .conditional_move_int = .{
                                     .ccr = rwo.flag.ccr,
                                     .cond = .{ .icond = rwo.flag.cond },
                                     .is_imm = true,
@@ -2401,6 +2413,17 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
                 },
             },
         }),
+        .condition_register => |reg| try self.addInst(.{
+            .tag = .bpr,
+            .data = .{
+                .branch_predict_reg = .{
+                    .rs1 = reg.reg,
+                    // Here we map to the opposite condition because the jump is to the false branch.
+                    .cond = reg.cond.negate(),
+                    .inst = undefined, // Will be filled by performReloc
+                },
+            },
+        }),
         else => blk: {
             const reg = switch (condition) {
                 .register => |r| r,
@@ -2655,7 +2678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
             _ = try self.addInst(.{
                 .tag = .movcc,
                 .data = .{
-                    .conditional_move = .{
+                    .conditional_move_int = .{
                         .ccr = ccr,
                         .cond = condition,
                         .is_imm = true,
@@ -2665,6 +2688,34 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
                 },
             });
         },
+        .condition_register => |op| {
+            const condition = op.cond;
+            const register = op.reg;
+
+            _ = try self.addInst(.{
+                .tag = .mov,
+                .data = .{
+                    .arithmetic_2op = .{
+                        .is_imm = false,
+                        .rs1 = reg,
+                        .rs2_or_imm = .{ .rs2 = .g0 },
+                    },
+                },
+            });
+
+            _ = try self.addInst(.{
+                .tag = .movr,
+                .data = .{
+                    .conditional_move_reg = .{
+                        .cond = condition,
+                        .is_imm = true,
+                        .rd = reg,
+                        .rs1 = register,
+                        .rs2_or_imm = .{ .imm = 1 },
+                    },
+                },
+            });
+        },
         .undef => {
             if (!self.wantSafety())
                 return; // The already existing value will do just fine.
@@ -2832,6 +2883,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
             }
         },
         .condition_flags,
+        .condition_register,
         .immediate,
         .ptr_stack_offset,
         => {
@@ -2872,7 +2924,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
             _ = try self.addInst(.{
                 .tag = .movcc,
                 .data = .{
-                    .conditional_move = .{
+                    .conditional_move_int = .{
                         .ccr = rwo.flag.ccr,
                         .cond = .{ .icond = rwo.flag.cond },
                         .is_imm = true,
@@ -3124,6 +3176,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
         .unreach => unreachable,
         .dead => unreachable,
         .condition_flags,
+        .condition_register,
         .register_with_overflow,
         => unreachable, // cannot hold an address
         .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
@@ -3475,6 +3528,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
         .unreach => unreachable,
         .dead => unreachable,
         .condition_flags,
+        .condition_register,
         .register_with_overflow,
         => unreachable, // cannot hold an address
         .immediate => |imm| {
src/arch/sparc64/Emit.zig
@@ -99,6 +99,8 @@ pub fn emitMir(
 
             .movcc => try emit.mirConditionalMove(inst),
 
+            .movr => @panic("TODO implement sparc64 movr"),
+
             .mulx => try emit.mirArithmetic3Op(inst),
 
             .nop => try emit.mirNop(),
@@ -314,7 +316,7 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {
 
     switch (tag) {
         .movcc => {
-            const data = emit.mir.instructions.items(.data)[inst].conditional_move;
+            const data = emit.mir.instructions.items(.data)[inst].conditional_move_int;
             if (data.is_imm) {
                 try emit.writeInstruction(Instruction.movcc(
                     i11,
src/arch/sparc64/Mir.zig
@@ -78,9 +78,13 @@ pub const Inst = struct {
         xnor,
 
         /// A.35 Move Integer Register on Condition (MOVcc)
-        /// This uses the conditional_move field.
+        /// This uses the conditional_move_int field.
         movcc,
 
+        /// A.36 Move Integer Register on Register Condition (MOVr)
+        /// This uses the conditional_move_reg field.
+        movr,
+
         /// A.37 Multiply and Divide (64-bit)
         /// This uses the arithmetic_3op field.
         // TODO add other operations.
@@ -230,12 +234,12 @@ pub const Inst = struct {
             inst: Index,
         },
 
-        /// Conditional move.
+        /// Conditional move, checking the integer status code
         /// if is_imm true then it uses the imm field of rs2_or_imm,
         /// otherwise it uses rs2 field.
         ///
         /// Used by e.g. movcc
-        conditional_move: struct {
+        conditional_move_int: struct {
             is_imm: bool,
             ccr: Instruction.CCR,
             cond: Instruction.Condition,
@@ -246,6 +250,22 @@ pub const Inst = struct {
             },
         },
 
+        /// Conditional move, comparing a register's content with zero
+        /// if is_imm true then it uses the imm field of rs2_or_imm,
+        /// otherwise it uses rs2 field.
+        ///
+        /// Used by e.g. movr
+        conditional_move_reg: struct {
+            is_imm: bool,
+            cond: Instruction.RCondition,
+            rd: Register,
+            rs1: Register,
+            rs2_or_imm: union {
+                rs2: Register,
+                imm: i10,
+            },
+        },
+
         /// No additional data
         ///
         /// Used by e.g. flushw