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).
This commit is contained in:
Koakuma
2022-04-11 20:27:38 +07:00
parent 1467590e40
commit dcb12a7941
3 changed files with 60 additions and 54 deletions

View File

@@ -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;

View File

@@ -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,

View File

@@ -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),
};
}