Commit dcb12a7941

Koakuma <koachan@protonmail.com>
2022-04-11 15:27:38
stage2: sparcv9: Use regular structs to encode instructions
Currently packed structs still has endian-dependent behavior, so it results in code that is not portable across platforms (see also issue 10113).
1 parent 1467590
Changed files (3)
src
src/arch/sparcv9/bits.zig
@@ -164,27 +164,33 @@ pub const Instruction = union(enum) {
     // name them with letters since there's no official naming scheme.
     // TODO: need to rename the minor formats to a more descriptive name.
 
+    // I am using regular structs instead of packed ones to avoid
+    // endianness-dependent behavior when constructing the actual
+    // assembly instructions.
+    // See also: https://github.com/ziglang/zig/issues/10113
+    // TODO: change it back to packed structs once the issue is resolved.
+
     // Format 1 (op = 1): CALL
-    format_1: packed struct {
+    format_1: struct {
         op: u2 = 0b01,
         disp30: u30,
     },
 
     // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
-    format_2a: packed struct {
+    format_2a: struct {
         op: u2 = 0b00,
         rd: u5,
         op2: u3,
         imm22: u22,
     },
-    format_2b: packed struct {
+    format_2b: struct {
         op: u2 = 0b00,
         a: u1,
         cond: u4,
         op2: u3,
         disp22: u22,
     },
-    format_2c: packed struct {
+    format_2c: struct {
         op: u2 = 0b00,
         a: u1,
         cond: u4,
@@ -194,7 +200,7 @@ pub const Instruction = union(enum) {
         p: u1,
         disp19: u19,
     },
-    format_2d: packed struct {
+    format_2d: struct {
         op: u2 = 0b00,
         a: u1,
         fixed: u1 = 0b0,
@@ -207,7 +213,7 @@ pub const Instruction = union(enum) {
     },
 
     // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
-    format_3a: packed struct {
+    format_3a: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -224,7 +230,7 @@ pub const Instruction = union(enum) {
         i: u1 = 0b1,
         simm13: u13,
     },
-    format_3c: packed struct {
+    format_3c: struct {
         op: u2,
         reserved1: u5 = 0b00000,
         op3: u6,
@@ -241,7 +247,7 @@ pub const Instruction = union(enum) {
         i: u1 = 0b1,
         simm13: u13,
     },
-    format_3e: packed struct {
+    format_3e: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -260,7 +266,7 @@ pub const Instruction = union(enum) {
         rcond: u3,
         simm10: u10,
     },
-    format_3g: packed struct {
+    format_3g: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -269,7 +275,7 @@ pub const Instruction = union(enum) {
         reserved: u8 = 0b00000000,
         rs2: u5,
     },
-    format_3h: packed struct {
+    format_3h: struct {
         op: u2 = 0b10,
         fixed1: u5 = 0b00000,
         op3: u6 = 0b101000,
@@ -279,7 +285,7 @@ pub const Instruction = union(enum) {
         cmask: u3,
         mmask: u4,
     },
-    format_3i: packed struct {
+    format_3i: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -288,13 +294,13 @@ pub const Instruction = union(enum) {
         imm_asi: u8,
         rs2: u5,
     },
-    format_3j: packed struct {
+    format_3j: struct {
         op: u2,
         impl_dep1: u5,
         op3: u6,
         impl_dep2: u19,
     },
-    format_3k: packed struct {
+    format_3k: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -304,7 +310,7 @@ pub const Instruction = union(enum) {
         reserved: u7 = 0b0000000,
         rs2: u5,
     },
-    format_3l: packed struct {
+    format_3l: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -314,7 +320,7 @@ pub const Instruction = union(enum) {
         reserved: u7 = 0b0000000,
         shcnt32: u5,
     },
-    format_3m: packed struct {
+    format_3m: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -324,7 +330,7 @@ pub const Instruction = union(enum) {
         reserved: u6 = 0b000000,
         shcnt64: u6,
     },
-    format_3n: packed struct {
+    format_3n: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -332,7 +338,7 @@ pub const Instruction = union(enum) {
         opf: u9,
         rs2: u5,
     },
-    format_3o: packed struct {
+    format_3o: struct {
         op: u2,
         fixed: u3 = 0b000,
         cc1: u1,
@@ -342,7 +348,7 @@ pub const Instruction = union(enum) {
         opf: u9,
         rs2: u5,
     },
-    format_3p: packed struct {
+    format_3p: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -350,20 +356,20 @@ pub const Instruction = union(enum) {
         opf: u9,
         rs2: u5,
     },
-    format_3q: packed struct {
+    format_3q: struct {
         op: u2,
         rd: u5,
         op3: u6,
         rs1: u5,
         reserved: u14 = 0b00000000000000,
     },
-    format_3r: packed struct {
+    format_3r: struct {
         op: u2,
         fcn: u5,
         op3: u6,
         reserved: u19 = 0b0000000000000000000,
     },
-    format_3s: packed struct {
+    format_3s: struct {
         op: u2,
         rd: u5,
         op3: u6,
@@ -371,7 +377,7 @@ pub const Instruction = union(enum) {
     },
 
     //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
-    format_4a: packed struct {
+    format_4a: struct {
         op: u2 = 0b10,
         rd: u5,
         op3: u6,
@@ -392,7 +398,7 @@ pub const Instruction = union(enum) {
         cc0: u1,
         simm11: u11,
     },
-    format_4c: packed struct {
+    format_4c: struct {
         op: u2 = 0b10,
         rd: u5,
         op3: u6,
@@ -415,7 +421,7 @@ pub const Instruction = union(enum) {
         cc0: u1,
         simm11: u11,
     },
-    format_4e: packed struct {
+    format_4e: struct {
         op: u2 = 0b10,
         rd: u5,
         op3: u6,
@@ -426,7 +432,7 @@ pub const Instruction = union(enum) {
         reserved: u4 = 0b0000,
         sw_trap: u7,
     },
-    format_4f: packed struct {
+    format_4f: struct {
         op: u2 = 0b10,
         rd: u5,
         op3: u6,
@@ -436,7 +442,7 @@ pub const Instruction = union(enum) {
         opf_low: u5,
         rs2: u5,
     },
-    format_4g: packed struct {
+    format_4g: struct {
         op: u2 = 0b10,
         rd: u5,
         op3: u6,
@@ -512,37 +518,37 @@ pub const Instruction = union(enum) {
     pub fn toU32(self: Instruction) u32 {
         // TODO: Remove this once packed structs work.
         return switch (self) {
-            .format_1 => |v| @bitCast(u32, v),
-            .format_2a => |v| @bitCast(u32, v),
-            .format_2b => |v| @bitCast(u32, v),
-            .format_2c => |v| @bitCast(u32, v),
-            .format_2d => |v| @bitCast(u32, v),
-            .format_3a => |v| @bitCast(u32, v),
+            .format_1 => |v| (@as(u32, v.op) << 30) | @as(u32, v.disp30),
+            .format_2a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.imm22),
+            .format_2b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | @as(u32, v.disp22),
+            .format_2c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.cond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.cc1) << 21) | (@as(u32, v.cc0) << 20) | (@as(u32, v.p) << 19) | @as(u32, v.disp19),
+            .format_2d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.a) << 29) | (@as(u32, v.fixed) << 28) | (@as(u32, v.rcond) << 25) | (@as(u32, v.op2) << 22) | (@as(u32, v.d16hi) << 20) | (@as(u32, v.p) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.d16lo),
+            .format_3a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
             .format_3b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
-            .format_3c => |v| @bitCast(u32, v),
+            .format_3c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved2) << 5) | @as(u32, v.rs2),
             .format_3d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
-            .format_3e => |v| @bitCast(u32, v),
+            .format_3e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
             .format_3f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | @as(u32, v.simm10),
-            .format_3g => |v| @bitCast(u32, v),
-            .format_3h => |v| @bitCast(u32, v),
-            .format_3i => |v| @bitCast(u32, v),
-            .format_3j => |v| @bitCast(u32, v),
-            .format_3k => |v| @bitCast(u32, v),
-            .format_3l => |v| @bitCast(u32, v),
-            .format_3m => |v| @bitCast(u32, v),
-            .format_3n => |v| @bitCast(u32, v),
-            .format_3o => |v| @bitCast(u32, v),
-            .format_3p => |v| @bitCast(u32, v),
-            .format_3q => |v| @bitCast(u32, v),
-            .format_3r => |v| @bitCast(u32, v),
-            .format_3s => |v| @bitCast(u32, v),
-            .format_4a => |v| @bitCast(u32, v),
+            .format_3g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
+            .format_3h => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed1) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed2) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.reserved) << 7) | (@as(u32, v.cmask) << 4) | @as(u32, v.mmask),
+            .format_3i => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.imm_asi) << 5) | @as(u32, v.rs2),
+            .format_3j => |v| (@as(u32, v.op) << 30) | (@as(u32, v.impl_dep1) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.impl_dep2),
+            .format_3k => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
+            .format_3l => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 5) | @as(u32, v.shcnt32),
+            .format_3m => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.x) << 12) | (@as(u32, v.reserved) << 6) | @as(u32, v.shcnt64),
+            .format_3n => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.reserved) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+            .format_3o => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fixed) << 27) | (@as(u32, v.cc1) << 26) | (@as(u32, v.cc0) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+            .format_3p => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.opf) << 5) | @as(u32, v.rs2),
+            .format_3q => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | @as(u32, v.reserved),
+            .format_3r => |v| (@as(u32, v.op) << 30) | (@as(u32, v.fcn) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
+            .format_3s => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | @as(u32, v.reserved),
+            .format_4a => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
             .format_4b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
-            .format_4c => |v| @bitCast(u32, v),
+            .format_4c => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 5) | @as(u32, v.rs2),
             .format_4d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
-            .format_4e => |v| @bitCast(u32, v),
-            .format_4f => |v| @bitCast(u32, v),
-            .format_4g => |v| @bitCast(u32, v),
+            .format_4e => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | (@as(u32, v.reserved) << 7) | @as(u32, v.sw_trap),
+            .format_4f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.fixed) << 13) | (@as(u32, v.rcond) << 10) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
+            .format_4g => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.fixed) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.opf_cc) << 11) | (@as(u32, v.opf_low) << 5) | @as(u32, v.rs2),
         };
     }
 
src/arch/sparcv9/Emit.zig
@@ -290,7 +290,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
 
 fn writeInstruction(emit: *Emit, instruction: Instruction) !void {
     // SPARCv9 instructions are always arranged in BE regardless of the
-    // endianness mode the CPU is running in.
+    // endianness mode the CPU is running in (Section 3.1 of the ISA specification).
     // This is to ease porting in case someone wants to do a LE SPARCv9 backend.
     const endian = Endian.Big;
 
src/arch/sparcv9/Mir.zig
@@ -62,7 +62,7 @@ pub const Inst = struct {
 
         /// A.27 Load Integer
         /// Those uses the arithmetic_3op field.
-        /// Note that the ldd variant of this instruction is deprecated, do not emit
+        /// Note that the ldd variant of this instruction is deprecated, so do not emit
         /// it unless specifically requested (e.g. by inline assembly).
         // TODO add other operations.
         ldub,