Commit e057ff2496

Koakuma <koachan@protonmail.com>
2022-05-06 18:16:07
stage2: sparc64: Implement SPARCv9 bpr
1 parent 8f8853c
Changed files (3)
src
src/arch/sparc64/bits.zig
@@ -1145,6 +1145,10 @@ pub const Instruction = union(enum) {
         return format2c(0b001, .{ .icond = cond }, annul, pt, ccr, disp);
     }
 
+    pub fn bpr(cond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
+        return format2d(0b011, cond, annul, pt, rs1, disp);
+    }
+
     pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
         return switch (s2) {
             Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),
src/arch/sparc64/Emit.zig
@@ -51,9 +51,11 @@ const InnerError = error{
 
 const BranchType = enum {
     bpcc,
+    bpr,
     fn default(tag: Mir.Inst.Tag) BranchType {
         return switch (tag) {
             .bpcc => .bpcc,
+            .bpr => .bpr,
             else => unreachable,
         };
     }
@@ -78,6 +80,7 @@ pub fn emitMir(
 
             .add => try emit.mirArithmetic3Op(inst),
 
+            .bpr => try emit.mirConditionalBranch(inst),
             .bpcc => try emit.mirConditionalBranch(inst),
 
             .call => @panic("TODO implement sparc64 call"),
@@ -232,15 +235,43 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
 
 fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
     const tag = emit.mir.instructions.items(.tag)[inst];
-    const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
-
-    const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
     const branch_type = emit.branch_types.get(inst).?;
-    log.debug("mirConditionalBranchImmediate: {} offset={}", .{ inst, offset });
 
     switch (branch_type) {
         .bpcc => switch (tag) {
-            .bpcc => try emit.writeInstruction(Instruction.bpcc(branch_predict_int.cond, branch_predict_int.annul, branch_predict_int.pt, branch_predict_int.ccr, @intCast(i21, offset))),
+            .bpcc => {
+                const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
+                const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_int.inst).?) - @intCast(i64, emit.code.items.len);
+                log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
+
+                try emit.writeInstruction(
+                    Instruction.bpcc(
+                        branch_predict_int.cond,
+                        branch_predict_int.annul,
+                        branch_predict_int.pt,
+                        branch_predict_int.ccr,
+                        @intCast(i21, offset),
+                    ),
+                );
+            },
+            else => unreachable,
+        },
+        .bpr => switch (tag) {
+            .bpr => {
+                const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg;
+                const offset = @intCast(i64, emit.code_offset_mapping.get(branch_predict_reg.inst).?) - @intCast(i64, emit.code.items.len);
+                log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
+
+                try emit.writeInstruction(
+                    Instruction.bpr(
+                        branch_predict_reg.cond,
+                        branch_predict_reg.annul,
+                        branch_predict_reg.pt,
+                        branch_predict_reg.rs1,
+                        @intCast(i18, offset),
+                    ),
+                );
+            },
             else => unreachable,
         },
     }
@@ -291,6 +322,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
 
     switch (tag) {
         .bpcc => return emit.mir.instructions.items(.data)[inst].branch_predict_int.inst,
+        .bpr => return emit.mir.instructions.items(.data)[inst].branch_predict_reg.inst,
         else => unreachable,
     }
 }
@@ -343,6 +375,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
 fn isBranch(tag: Mir.Inst.Tag) bool {
     return switch (tag) {
         .bpcc => true,
+        .bpr => true,
         else => false,
     };
 }
@@ -459,19 +492,27 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
     assert(offset & 0b11 == 0);
 
     switch (tag) {
+        // TODO use the following strategy to implement long branches:
+        // - Negate the conditional and target of the original instruction;
+        // - In the space immediately after the branch, load
+        //   the address of the original target, preferrably in
+        //   a PC-relative way, into %o7; and
+        // - jmpl %o7 + %g0, %g0
+
         .bpcc => {
             if (std.math.cast(i21, offset)) |_| {
                 return BranchType.bpcc;
             } else |_| {
-                // TODO use the following strategy to implement long branches:
-                // - Negate the conditional and target of the original BPcc;
-                // - In the space immediately after the branch, load
-                //   the address of the original target, preferrably in
-                //   a PC-relative way, into %o7; and
-                // - jmpl %o7 + %g0, %g0
                 return emit.fail("TODO support BPcc branches larger than +-1 MiB", .{});
             }
         },
+        .bpr => {
+            if (std.math.cast(i18, offset)) |_| {
+                return BranchType.bpr;
+            } else |_| {
+                return emit.fail("TODO support BPr branches larger than +-128 KiB", .{});
+            }
+        },
         else => unreachable,
     }
 }
src/arch/sparc64/Mir.zig
@@ -43,6 +43,10 @@ pub const Inst = struct {
         // TODO add other operations.
         add,
 
+        /// A.3 Branch on Integer Register with Prediction (BPr)
+        /// This uses the branch_predict_reg field.
+        bpr,
+
         /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
         /// This uses the branch_predict_int field.
         bpcc,
@@ -175,6 +179,16 @@ pub const Inst = struct {
             inst: Index,
         },
 
+        /// Branch with prediction, comparing a register's content with zero
+        /// Used by e.g. bpr
+        branch_predict_reg: struct {
+            annul: bool = false,
+            pt: bool = true,
+            cond: Instruction.RCondition,
+            rs1: Register,
+            inst: Index,
+        },
+
         /// No additional data
         ///
         /// Used by e.g. flushw