Merge origin/bill/rexcode: struct repack (#raw_union #packed), wasm arch

Merge gingerBill's latest into bill/rexcode. His changes: minimize the
Instruction/Operand structs across ISAs with packed raw-unions (+ the
compiler support for #raw_union #packed), the new core:rexcode/wasm arch
and wasm/module, encode() now returns (byte_count, ok) instead of a Result
struct, decode_one made public, and assorted formatting/inlining.

Conflict: arm64/tests/pipeline_smoke.odin CSEL test -- kept the generated
4-arg inst_csel(dst,src,src2,cond) (mnemonic_builders.odin is generated,
not from Bill's branch) and adopted Bill's (byte_count, success) encode
signature.

Required rebuilding ./odin from the merged source for the packed-union
syntax. Re-validated after the repack: regenerated all artifacts
(idempotent -- no spurious churn), all 10 arches gen/builders/check/test
green, and byte-compared the new arm32 BF + mips PS/MMI/DSP/R6 forms to
confirm no field truncation. arm64/arm32/mips still 100%.
This commit is contained in:
Brendan Punsky
2026-06-18 05:44:48 -04:00
committed by Flāvius
92 changed files with 9914 additions and 5421 deletions

View File

@@ -157,7 +157,7 @@ decode_bitmask_imm :: proc "contextless" (n, immr, imms: u8, is_64: bool) -> (va
elem_size: u32 = 0
s_field: u8 = 0
if n == 1 {
if !is_64 { return 0, false } // N=1 only valid for 64-bit ops
if !is_64 { return } // N=1 only valid for 64-bit ops
elem_size = 64
s_field = s
} else {
@@ -179,15 +179,15 @@ decode_bitmask_imm :: proc "contextless" (n, immr, imms: u8, is_64: bool) -> (va
elem_size = 2
s_field = s & 0b000001
case:
return 0, false
return
}
}
width: u32 = is_64 ? 64 : 32
if elem_size > width { return 0, false }
if elem_size > width { return }
ones := u32(s_field) + 1
if ones == 0 || ones >= elem_size { return 0, false }
if ones == 0 || ones >= elem_size { return }
rotation := u32(immr) & (elem_size - 1)
@@ -199,10 +199,11 @@ decode_bitmask_imm :: proc "contextless" (n, immr, imms: u8, is_64: bool) -> (va
rotated := rotate_right_u64(pattern, inv_rot, elem_size) & elem_mask
// Replicate to fill width.
out: u64 = rotated
value = rotated
for size: u32 = elem_size; size < width; size *= 2 {
out |= out << size
value |= value << size
}
if width == 32 { out &= 0xFFFFFFFF }
return out, true
if width == 32 { value &= 0xFFFFFFFF }
ok = true
return
}

View File

@@ -36,25 +36,24 @@ decode :: proc(
label_defs: ^[dynamic]Label_Definition,
errors: ^[dynamic]Error,
endianness: Endianness = .LITTLE,
) -> Result {
) -> (byte_count: u32, ok: bool) {
n_bytes := u32(len(data)) & ~u32(3)
errors_start := u32(len(errors))
pending_branches: [dynamic]isa.Branch_Target
defer delete(pending_branches)
pc: u32 = 0
for pc < n_bytes {
word := read_u32(data, pc, endianness)
for byte_count < n_bytes {
word := read_u32(data, byte_count, endianness)
inst: Instruction
info: Instruction_Info
entry_idx := decode_one_inline(word, pc, &inst, &info)
entry_idx := decode_one_inline(word, byte_count, &inst, &info)
if entry_idx < 0 {
append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE})
append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE})
inst = Instruction{mnemonic = .INVALID, length = 4}
info = Instruction_Info{offset = pc}
info = Instruction_Info{offset = byte_count}
} else {
inst_idx_for_branches := u32(len(instructions))
for slot in 0..<inst.operand_count {
@@ -71,11 +70,12 @@ decode :: proc(
append(instructions, inst)
append(inst_info, info)
pc += 4
byte_count += 4
}
isa.infer_labels_from_branches(pending_branches[:], pc, label_defs, relocs)
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs)
ok = u32(len(errors)) == errors_start
return
}
// =============================================================================

View File

@@ -43,24 +43,22 @@ encode :: proc(
endianness: Endianness = .LITTLE,
resolve: bool = true,
base_address: u64 = 0,
) -> Result {
) -> (byte_count: u32, ok: bool) {
n_inst := u32(len(instructions))
if u32(len(code)) < n_inst * 4 {
append(errors, Error{inst_idx = 0, code = .BUFFER_OVERFLOW})
return Result{byte_count = 0, success = false}
return
}
errors_start := u32(len(errors))
pending_start := u32(len(relocs))
pc: u32 = 0
// ---- PASS 1 -----------------------------------------------------------
for i in 0..<n_inst {
inst := &instructions[i]
word, ok := encode_one_inline(inst, pc, u16(i), relocs, errors)
if !ok { return Result{byte_count = pc, success = false} }
write_u32(code, pc, word, endianness)
pc += 4
word := encode_one_inline(inst, byte_count, u16(i), relocs, errors) or_return
write_u32(code, byte_count, word, endianness)
byte_count += 4
}
// ---- PASS 1.5: fixed-width => *4 -------------------------------------
@@ -71,7 +69,8 @@ encode :: proc(
}
if !resolve {
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
ok = u32(len(errors)) == errors_start
return
}
// ---- PASS 2: resolve relocations -------------------------------------
@@ -87,7 +86,8 @@ encode :: proc(
}
if write_idx != n_relocs { resize(relocs, int(write_idx)) }
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
ok = u32(len(errors)) == errors_start
return
}
// =============================================================================

View File

@@ -37,7 +37,6 @@ import "../isa"
// option 13-15 extend type (data-proc extended register, LDR/STR EXT)
// imm3 10-12 extend amount
Result :: isa.Result
Error :: isa.Error
Error_Code :: isa.Error_Code
Label_Definition :: isa.Label_Definition

View File

@@ -16,8 +16,9 @@ Instruction :: struct #packed {
operand_count: u8, // 1
flags: Instruction_Flags, // 1
length: u8, // 1 -- always 4
_: [3]u8,
}
#assert(size_of(Instruction) == 77)
#assert(size_of(Instruction) == 64)
// =============================================================================
// Builders -- the most common shapes; less-common forms can be built

View File

@@ -89,7 +89,7 @@ Extended_Reg :: struct #packed {
// 16-byte tagged operand. The union holds whichever payload matches `kind`.
Operand :: struct #packed {
using _: struct #raw_union {
using _: struct #raw_union #packed {
reg: Register, // 2
mem: Memory, // 12
immediate: i64, // 8
@@ -97,11 +97,11 @@ Operand :: struct #packed {
shifted: Shifted_Reg, // 8
extended: Extended_Reg, // 8
cond: u8, // 1
}, // 16 total because of alignment
}, // 12 total because of alignment
kind: Operand_Kind, // 1
size: u8, // 1 -- carried width info; meaning varies
}
#assert(size_of(Operand) == 18)
#assert(size_of(Operand) == 14)
// -----------------------------------------------------------------------------
// Constructors -- generic

View File

@@ -78,8 +78,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_i(.ADD_IMM, a.X0, a.X1, 100),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_IMM: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_IMM: encode", success)
eq_word("ADD X0,X1,#100", load_le(code[:], 0), 0x91019020)
}
@@ -92,8 +92,8 @@ run_pipeline_tests :: proc() {
clear(&relocs); clear(&errors)
for i in 0..<len(code) { code[i] = 0 }
insts := []a.Instruction{ a.inst_mov_imm(.MOVZ, a.X0, 0x1234, 1) }
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MOVZ: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MOVZ: encode", success)
eq_word("MOVZ X0,#0x1234,LSL#16", load_le(code[:], 0), 0xD2A24680)
}
@@ -111,8 +111,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X0), a.op_reg(a.X1), a.op_shifted(a.X2, .LSL, 3), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_SR: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_SR: encode", success)
eq_word("ADD X0,X1,X2,LSL#3", load_le(code[:], 0), 0x8B020C20)
}
@@ -129,8 +129,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X0), a.op_reg(a.SP), a.op_extended(a.W1, .UXTW, 2), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_ER: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADD_ER: encode", success)
eq_word("ADD X0,SP,W1,UXTW#2", load_le(code[:], 0), 0x8B214BE0)
}
@@ -144,8 +144,8 @@ run_pipeline_tests :: proc() {
a.inst_r_r_r (.UDIV, a.X0, a.X1, a.X2),
a.inst_r_r_r_r(.MADD, a.X0, a.X1, a.X2, a.X3),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("UDIV/MADD: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("UDIV/MADD: encode", success)
eq_word("UDIV X0,X1,X2", load_le(code[:], 0), 0x9AC20820)
eq_word("MADD X0,X1,X2,X3", load_le(code[:], 4), 0x9B020C20)
}
@@ -160,8 +160,8 @@ run_pipeline_tests :: proc() {
a.inst_r_r(.CLZ, a.X0, a.X1),
a.inst_r_r(.REV, a.X0, a.X1),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CLZ/REV: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CLZ/REV: encode", success)
eq_word("CLZ X0,X1", load_le(code[:], 0), 0xDAC01020)
eq_word("REV X0,X1", load_le(code[:], 4), 0xDAC00C20)
}
@@ -172,8 +172,8 @@ run_pipeline_tests :: proc() {
clear(&relocs); clear(&errors)
for i in 0..<len(code) { code[i] = 0 }
insts := []a.Instruction{ a.inst_csel(a.X0, a.X1, a.X2, .EQ) }
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CSEL: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CSEL: encode", success)
eq_word("CSEL X0,X1,X2,EQ", load_le(code[:], 0), 0x9A820020)
}
@@ -189,8 +189,8 @@ run_pipeline_tests :: proc() {
a.inst_ldst(.LDR, a.X0, a.mem_offset(a.X1, 16)),
a.inst_ldst(.STR, a.W0, a.mem_offset(a.SP, 20)),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("LDR/STR: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("LDR/STR: encode", success)
eq_word("LDR X0,[X1,#16]", load_le(code[:], 0), 0xF9400820)
eq_word("STR W0,[SP,#20]", load_le(code[:], 4), 0xB90017E0)
}
@@ -219,8 +219,8 @@ run_pipeline_tests :: proc() {
a.inst_none(.RET),
a.inst_branch(.BL, 0),
}
r := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("br: encode", r.success)
byte_count, success := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("br: encode", success)
eq_word("B forward (+3 words)", load_le(code[:], 0), 0x14000003)
eq_word("BL backward (-1 word)", load_le(code[:], 16), 0x97FFFFFF)
}
@@ -249,8 +249,8 @@ run_pipeline_tests :: proc() {
a.inst_tbz(a.X0, 5, 0),
a.inst_none(.NOP), // target
}
r := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("CBZ/TBZ: encode", r.success)
byte_count, success := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("CBZ/TBZ: encode", success)
eq_word("CBZ X0,+2 words", load_le(code[:], 0), 0xB4000040)
eq_word("TBZ X0,#5,+1 word", load_le(code[:], 4), 0x36280020)
}
@@ -286,8 +286,8 @@ run_pipeline_tests :: proc() {
a.inst_none(.NOP),
a.inst_none(.NOP),
}
r := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("ADR: encode", r.success)
byte_count, success := a.encode(insts, ld[:], code[:], &relocs, &errors)
ok("ADR: encode", success)
eq_word("ADR X0,+8", load_le(code[:], 0), 0x10000040)
}
@@ -315,8 +315,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X0), a.op_imm(0xDA10, 2), {}, {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("system: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("system: encode", success)
eq_word("NOP", load_le(code[:], 0), 0xD503201F)
eq_word("SVC #1", load_le(code[:], 4), 0xD4000021)
eq_word("MRS X0,NZCV", load_le(code[:], 8), 0xD53B4200)
@@ -330,8 +330,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_r(.FADD, a.d_reg(0), a.d_reg(1), a.d_reg(2)),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("FADD: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("FADD: encode", success)
eq_word("FADD D0,D1,D2", load_le(code[:], 0), 0x1E622820)
}
@@ -349,16 +349,16 @@ run_pipeline_tests :: proc() {
a.inst_cbnz(a.X0, 0),
a.inst_none(.RET),
}
r := a.encode(src, ld[:], code[:], &relocs, &errors)
ok("rt: encode", r.success)
byte_count, success := a.encode(src, ld[:], code[:], &relocs, &errors)
ok("rt: encode", success)
d_insts: [dynamic]a.Instruction
d_info: [dynamic]a.Instruction_Info
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
d := a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("rt: decode", d.success)
_, d_success := a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("rt: decode", d_success)
ok("rt: 3 insts", len(d_insts) == 3)
ok("rt: ADD", d_insts[0].mnemonic == .ADD_IMM)
ok("rt: CBNZ", d_insts[1].mnemonic == .CBNZ)
@@ -385,15 +385,15 @@ run_pipeline_tests :: proc() {
a.inst_b_cond(.EQ, 0),
a.inst_none(.RET),
}
r := a.encode(src, ld[:], code[:], &relocs, &errors)
ok("b.cond: encode", r.success)
byte_count, success := a.encode(src, ld[:], code[:], &relocs, &errors)
ok("b.cond: encode", success)
d_insts: [dynamic]a.Instruction
d_info: [dynamic]a.Instruction_Info
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
text := a.aprint(d_insts[:], d_info[:], d_labels[:],
nil, nil, nil, context.temp_allocator)
@@ -423,8 +423,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_i(.ORR_IMM, a.X0, a.X1, transmute(i64)mask),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("bitmask ORR: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("bitmask ORR: encode", success)
eq_word("ORR X0,X1,#0xFF00.. repeat", load_le(code[:], 0), 0xB2089C20)
// Round-trip: decode and verify operand round-trips back to the raw mask.
@@ -433,7 +433,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("bitmask ORR: decode", len(d_insts) == 1 && d_insts[0].mnemonic == .ORR_IMM)
if len(d_insts) == 1 {
got := u64(d_insts[0].ops[2].immediate)
@@ -457,8 +457,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_i(.AND_IMM, a.W0, a.W1, 0xF0),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("bitmask AND 32: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("bitmask AND 32: encode", success)
eq_word("AND W0,W1,#0xF0", load_le(code[:], 0), 0x12040C20)
// Round-trip.
@@ -467,7 +467,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("bitmask AND 32: decode", len(d_insts) == 1 && d_insts[0].mnemonic == .AND_IMM)
if len(d_insts) == 1 {
got := u64(d_insts[0].ops[2].immediate)
@@ -487,8 +487,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_z_s(0), a.op_z_s(1), a.op_z_s(2), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE ADD Z: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE ADD Z: encode", success)
eq_word("SVE ADD Z0.S,Z1.S,Z2.S", load_le(code[:], 0), 0x04A20020)
// Round-trip.
@@ -497,7 +497,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("SVE ADD Z: decode", len(d_insts) == 1 && d_insts[0].mnemonic == .SVE_ADD_Z)
}
@@ -514,8 +514,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_z_s(0), a.op_reg(p0), a.op_z_s(0), a.op_z_s(1)},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE ADD_PRED: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE ADD_PRED: encode", success)
eq_word("SVE ADD Z0.S,P0/M,Z0.S,Z1.S", load_le(code[:], 0), 0x04810000)
}
@@ -532,8 +532,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(p0), a.op_imm(0x1F, 1), {}, {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE PTRUE: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE PTRUE: encode", success)
eq_word("SVE PTRUE P0.B,ALL", load_le(code[:], 0), 0x2518E3E0)
}
@@ -547,8 +547,8 @@ run_pipeline_tests :: proc() {
a.inst_none(.SME_SMSTART),
a.inst_none(.SME_SMSTOP),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME SMSTART/SMSTOP: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME SMSTART/SMSTOP: encode", success)
eq_word("SME SMSTART", load_le(code[:], 0), 0xD503477F)
eq_word("SME SMSTOP", load_le(code[:], 4), 0xD503467F)
}
@@ -572,8 +572,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_imm(0, 1), a.op_reg(p0), a.op_reg(p1), a.op_z_s(0)},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME FMOPA: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME FMOPA: encode", success)
eq_word("SME FMOPA ZA0.S,P0/M,P1/M,Z0.S,Z0.S", load_le(code[:], 0), 0x80802000)
}
@@ -595,8 +595,8 @@ run_pipeline_tests :: proc() {
a.inst_r(.AMX_STZ, a.X3),
a.inst_none(.AMX_CLR),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("AMX: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("AMX: encode", success)
eq_word("AMX SET", load_le(code[:], 0), 0x00201220)
eq_word("AMX LDX X0", load_le(code[:], 4), 0x00201000)
eq_word("AMX LDY X1", load_le(code[:], 8), 0x00201021)
@@ -610,8 +610,8 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
d := a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("AMX: decode", d.success)
_, d_success := a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("AMX: decode", d_success)
ok("AMX: 6 insts", len(d_insts) == 6)
ok("AMX: SET", len(d_insts) >= 1 && d_insts[0].mnemonic == .AMX_SET)
ok("AMX: LDX", len(d_insts) >= 2 && d_insts[1].mnemonic == .AMX_LDX)
@@ -651,9 +651,9 @@ run_pipeline_tests :: proc() {
isa.label_set_at(&labels, fwd, &insts) // .L1: at instruction 4
append(&insts, a.inst_none(.RET)) // [4] byte 16: RET
r := a.encode(insts[:], labels[:], code[:], &relocs, &errors)
ok("anon labels: encode", r.success)
ok("anon labels: byte_count = 20", r.byte_count == 20)
byte_count, success := a.encode(insts[:], labels[:], code[:], &relocs, &errors)
ok("anon labels: encode", success)
ok("anon labels: byte_count = 20", byte_count == 20)
// B.LT at byte 8 -> .L1 at byte 16: offset = +8 = +2 words.
// bits = 0x54000000 | (2<<5) | LT(0xB) = 0x5400004B
@@ -670,7 +670,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("anon labels: decode 5 insts", len(d_insts) == 5)
have_back, have_fwd: bool
for ld in d_labels {
@@ -713,8 +713,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X3), a.op_imm(a.DCZID_EL0, 2), {}, {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("sysreg: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("sysreg: encode", success)
eq_word("MRS X0,NZCV", load_le(code[:], 0), 0xD53B4200)
eq_word("MRS X1,TPIDR_EL0", load_le(code[:], 4), 0xD53BD041)
eq_word("MRS X2,CNTVCT_EL0", load_le(code[:], 8), 0xD53BE042)
@@ -729,8 +729,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r(.DC_ZVA, a.X0),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("DC ZVA: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("DC ZVA: encode", success)
eq_word("DC ZVA X0", load_le(code[:], 0), 0xD50B7420)
d_insts: [dynamic]a.Instruction
@@ -738,7 +738,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("DC ZVA: decode", len(d_insts) == 1 && d_insts[0].mnemonic == .DC_ZVA)
ok("DC ZVA: Rt = X0", len(d_insts) == 1 && d_insts[0].ops[0].reg == a.X0)
}
@@ -756,8 +756,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X0), a.op_shifted(a.X1, .LSL, 0), {}, {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CMP_SR: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("CMP_SR: encode", success)
eq_word("CMP X0,X1", load_le(code[:], 0), 0xEB01001F)
}
@@ -786,8 +786,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X0), a.op_reg(a.X1), a.op_reg(a.X2), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MOPS CPY: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MOPS CPY: encode", success)
eq_word("CPYP X0,X1,X2", load_le(code[:], 0), 0x1D020420)
eq_word("CPYM X0,X1,X2", load_le(code[:], 4), 0x1D420420)
eq_word("CPYE X0,X1,X2", load_le(code[:], 8), 0x1D820420)
@@ -808,8 +808,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_z_s(0), a.op_z_s(1), a.op_z_s(2), a.op_imm(2, 1)},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE FMLA indexed: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE FMLA indexed: encode", success)
eq_word("SVE FMLA Z0.S, Z1.S, Z2.S[2]", load_le(code[:], 0), 0x64B20020)
}
@@ -835,8 +835,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_z_s(0), a.op_reg(p0), a.op_mem(mem), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE LD1W gather: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SVE LD1W gather: encode", success)
eq_word("SVE LD1W Z0.S,P0/Z,[X1,Z2.S,UXTW]", load_le(code[:], 0), 0x85024020)
}
@@ -864,8 +864,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_imm(slice_packed, 2), a.op_reg(p5), a.op_mem(mem), {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME LD1B tile vs LLVM: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("SME LD1B tile vs LLVM: encode", success)
eq_word("SME LD1B ZA0V.B[W14,5],P5/Z,[X10,X21]", load_le(code[:], 0), 0xE015D545)
d_insts: [dynamic]a.Instruction
@@ -873,7 +873,7 @@ run_pipeline_tests :: proc() {
d_labels: [dynamic]a.Label_Definition
defer delete(d_insts); defer delete(d_info); defer delete(d_labels)
clear(&errors)
a.decode(code[:r.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
a.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
ok("SME LD1B tile: decode 1 inst", len(d_insts) == 1)
ok("SME LD1B tile: mnemonic", len(d_insts) == 1 && d_insts[0].mnemonic == .SME_LD1B_TILE)
ok("SME LD1B tile: slice roundtrip",
@@ -891,8 +891,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_v_4s(0), a.op_v_4s(1), a.op_v_4s(2), a.op_imm(0, 1)},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("FCMLA: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("FCMLA: encode", success)
eq_word("FCMLA V0.4S,V1.4S,V2.4S,#0", load_le(code[:], 0), 0x6E82C420)
}
@@ -908,8 +908,8 @@ run_pipeline_tests :: proc() {
a.inst_none(.TCOMMIT),
a.inst_r(.TTEST, a.X1),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("TME: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("TME: encode", success)
eq_word("TSTART X0", load_le(code[:], 0), 0xD5233060)
eq_word("TCOMMIT", load_le(code[:], 4), 0xD503307F)
eq_word("TTEST X1", load_le(code[:], 8), 0xD5233161)
@@ -925,8 +925,8 @@ run_pipeline_tests :: proc() {
a.inst_r_r(.UXTB, a.W0, a.W1),
a.inst_r_r(.SXTW, a.X0, a.W1),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("extend aliases: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("extend aliases: encode", success)
eq_word("UXTB W0,W1", load_le(code[:], 0), 0x53001C20)
eq_word("SXTW X0,W1", load_le(code[:], 4), 0x93407C20)
}
@@ -942,8 +942,8 @@ run_pipeline_tests :: proc() {
a.inst_r_r_r(.ADC, a.X0, a.X1, a.X2),
a.inst_r_r_r(.SBCS, a.X3, a.X4, a.X5),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADC/SBCS: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ADC/SBCS: encode", success)
eq_word("ADC X0,X1,X2", load_le(code[:], 0), 0x9A020020)
eq_word("SBCS X3,X4,X5", load_le(code[:], 4), 0xFA050083)
}
@@ -961,8 +961,8 @@ run_pipeline_tests :: proc() {
ops = {a.op_reg(a.X7), a.op_imm(a.RNDR, 2), {}, {}},
},
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MRS X7,RNDR: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("MRS X7,RNDR: encode", success)
eq_word("MRS X7,RNDR", load_le(code[:], 0), 0xD53B2407)
}
@@ -979,8 +979,8 @@ run_pipeline_tests :: proc() {
a.inst_ldst(.LDAPUR, a.X0, a.mem_offset(a.X1, 8)),
a.inst_ldst(.STLUR, a.X2, a.mem_offset(a.SP, -8)),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("RCpc unscaled: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("RCpc unscaled: encode", success)
eq_word("LDAPUR X0,[X1,#8]", load_le(code[:], 0), 0xD9408020)
eq_word("STLUR X2,[SP,#-8]", load_le(code[:], 4), 0xD91F83E2)
}
@@ -994,8 +994,8 @@ run_pipeline_tests :: proc() {
a.inst_none(.BTI_J),
a.inst_none(.PSB_CSYNC),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("barriers/BTI: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("barriers/BTI: encode", success)
eq_word("SB", load_le(code[:], 0), 0xD50330FF)
eq_word("BTI j", load_le(code[:], 4), 0xD503245F)
eq_word("PSB CSYNC", load_le(code[:], 8), 0xD503223F)
@@ -1011,8 +1011,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_i(.LSL_IMM, a.W0, a.W1, 4),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("LSL_IMM 32: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("LSL_IMM 32: encode", success)
eq_word("LSL W0,W1,#4", load_le(code[:], 0), 0x531C6C20)
}
@@ -1026,8 +1026,8 @@ run_pipeline_tests :: proc() {
insts := []a.Instruction{
a.inst_r_r_i(.ROR_IMM, a.W0, a.W1, 4),
}
r := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ROR_IMM 32: encode", r.success)
byte_count, success := a.encode(insts, nil, code[:], &relocs, &errors)
ok("ROR_IMM 32: encode", success)
eq_word("ROR W0,W1,#4", load_le(code[:], 0), 0x13811020)
}