Commit b6d7f63f34

Koakuma <koachan@protonmail.com>
2022-04-20 16:16:17
stage2: sparcv9: Implement jmpl lowering
1 parent 59905a6
Changed files (4)
src/arch/sparcv9/bits.zig
@@ -271,6 +271,8 @@ pub const Instruction = union(enum) {
         rd: u5,
         op3: u6,
         rs1: u5,
+        // See Errata 58 of SPARCv9 specification
+        // https://sparc.org/errata-for-v9/#58
         i: u1 = 0b1,
         reserved: u8 = 0b00000000,
         rs2: u5,
@@ -977,10 +979,10 @@ pub const Instruction = union(enum) {
         };
     }
 
-    pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+    pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
         return switch (s2) {
-            Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
-            i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
+            Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),
+            i13 => format3b(0b10, 0b11_1000, rs1, rs2, rd),
             else => unreachable,
         };
     }
@@ -1017,6 +1019,14 @@ pub const Instruction = union(enum) {
         };
     }
 
+    pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+        return switch (s2) {
+            Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
+            i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
+            else => unreachable,
+        };
+    }
+
     pub fn nop() Instruction {
         return sethi(0, .g0);
     }
src/arch/sparcv9/CodeGen.zig
@@ -1,5 +1,7 @@
 //! SPARCv9 codegen.
 //! This lowers AIR into MIR.
+//! For now this only implements medium/low code model with absolute addressing.
+//! TODO add support for other code models.
 const std = @import("std");
 const assert = std.debug.assert;
 const log = std.log.scoped(.codegen);
@@ -884,7 +886,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
 
                 _ = try self.addInst(.{
                     .tag = .jmpl,
-                    .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
+                    .data = .{
+                        .arithmetic_3op = .{
+                            .is_imm = false,
+                            .rd = .o7,
+                            .rs1 = .o7,
+                            .rs2_or_imm = .{ .rs2 = .g0 },
+                        },
+                    },
                 });
             } else if (func_value.castTag(.extern_fn)) |_| {
                 return self.fail("TODO implement calling extern functions", .{});
@@ -899,7 +908,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
 
         _ = try self.addInst(.{
             .tag = .jmpl,
-            .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
+            .data = .{
+                .arithmetic_3op = .{
+                    .is_imm = false,
+                    .rd = .o7,
+                    .rs1 = .o7,
+                    .rs2_or_imm = .{ .rs2 = .g0 },
+                },
+            },
         });
     }
 
src/arch/sparcv9/Emit.zig
@@ -56,8 +56,7 @@ pub fn emitMir(
 
             .call => @panic("TODO implement sparcv9 call"),
 
-            .jmpl => @panic("TODO implement sparcv9 jmpl"),
-            .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
+            .jmpl => try emit.mirArithmetic3Op(inst),
 
             .ldub => try emit.mirArithmetic3Op(inst),
             .lduh => try emit.mirArithmetic3Op(inst),
@@ -163,6 +162,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
         const imm = data.rs2_or_imm.imm;
         switch (tag) {
             .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
+            .jmpl => try emit.writeInstruction(Instruction.jmpl(i13, rs1, imm, rd)),
             .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)),
             .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
             .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
@@ -177,6 +177,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
         const rs2 = data.rs2_or_imm.rs2;
         switch (tag) {
             .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
+            .jmpl => try emit.writeInstruction(Instruction.jmpl(Register, rs1, rs2, rd)),
             .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)),
             .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
             .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
src/arch/sparcv9/Mir.zig
@@ -54,11 +54,8 @@ pub const Inst = struct {
         call,
 
         /// A.24 Jump and Link
-        /// jmpl (far direct jump) uses the branch_link field,
-        /// while jmpl_i (indirect jump) uses the branch_link_indirect field.
-        /// Those two MIR instructions will be lowered into SPARCv9 jmpl instruction.
+        /// It uses the arithmetic_3op field.
         jmpl,
-        jmpl_i,
 
         /// A.27 Load Integer
         /// Those uses the arithmetic_3op field.
@@ -167,13 +164,6 @@ pub const Inst = struct {
             link: Register = .o7,
         },
 
-        /// Indirect branch and link (always unconditional).
-        /// Used by e.g. jmpl_i
-        branch_link_indirect: struct {
-            reg: Register,
-            link: Register = .o7,
-        },
-
         /// Branch with prediction.
         /// Used by e.g. bpcc
         branch_predict: struct {