mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-19 16:42:33 +00:00
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:
@@ -29,25 +29,24 @@ decode :: proc(
|
||||
label_defs: ^[dynamic]Label_Definition,
|
||||
errors: ^[dynamic]Error,
|
||||
endianness: Endianness = .BIG,
|
||||
) -> Result {
|
||||
) -> (byte_count: u32, ok: bool) {
|
||||
n_bytes := u32(len(data)) & ~u32(3) // drop dangling tail
|
||||
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 {
|
||||
@@ -64,12 +63,13 @@ 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)
|
||||
isa.infer_labels_from_branches(pending_branches[:], byte_count, label_defs, relocs)
|
||||
|
||||
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
|
||||
ok = u32(len(errors)) == errors_start
|
||||
return
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -38,25 +38,21 @@ encode :: proc(
|
||||
endianness: Endianness = .BIG,
|
||||
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
|
||||
|
||||
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
|
||||
@@ -67,7 +63,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
|
||||
@@ -87,7 +84,8 @@ encode :: proc(
|
||||
resize(relocs, int(write_idx))
|
||||
}
|
||||
|
||||
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
|
||||
ok = u32(len(errors)) == errors_start
|
||||
return
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -32,7 +32,6 @@ import "../isa"
|
||||
// is sign-extended and pre-scaled by element size, so the effective
|
||||
// range is `±64 × element_size` bytes.
|
||||
|
||||
Result :: isa.Result
|
||||
Error :: isa.Error
|
||||
Error_Code :: isa.Error_Code
|
||||
Label_Definition :: isa.Label_Definition
|
||||
|
||||
@@ -76,8 +76,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
rsp.inst_r_m (.LW, rsp.T0, rsp.mem(rsp.SP, 16)),
|
||||
rsp.inst_none (.NOP),
|
||||
}
|
||||
e := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("scalar: encode success", e.success)
|
||||
byte_count, success := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("scalar: encode success", success)
|
||||
eq_word ("scalar: ADD word", load_be(code[:], 0), 0x012A4020)
|
||||
eq_word ("scalar: ADDIU word", load_be(code[:], 4), 0x25280064)
|
||||
eq_word ("scalar: LW word", load_be(code[:], 8), 0x8FA80010)
|
||||
@@ -90,8 +90,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
d := rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("scalar: decode success", d.success)
|
||||
dbyte_count, dsuccess := rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("scalar: decode success", dsuccess)
|
||||
ok("scalar: 4 insts", len(d_insts) == 4)
|
||||
ok("scalar[0] ADD", d_insts[0].mnemonic == .ADD)
|
||||
ok("scalar[3] NOP", d_insts[3].mnemonic == .NOP)
|
||||
@@ -115,8 +115,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
insts := []rsp.Instruction{
|
||||
rsp.inst_v_v_v(.VMULF, rsp.VR0, rsp.VR1, rsp.VR2, 3),
|
||||
}
|
||||
e := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("vu: encode", e.success)
|
||||
byte_count, success := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("vu: encode", success)
|
||||
eq_word("vu: VMULF", load_be(code[:], 0), 0x4A620800)
|
||||
|
||||
d_insts: [dynamic]rsp.Instruction
|
||||
@@ -126,8 +126,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
d := rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("vu: decode", d.success)
|
||||
dbyte_count, dsuccess := rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("vu: decode", dsuccess)
|
||||
ok("vu: VMULF mnem", d_insts[0].mnemonic == .VMULF)
|
||||
i0 := d_insts[0]
|
||||
ok("vu: vd=$v0", i0.ops[0].reg == rsp.VR0)
|
||||
@@ -153,8 +153,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
insts := []rsp.Instruction{
|
||||
rsp.inst_v_vmem(.LQV, rsp.VR4, rsp.vmem(rsp.T0, 0, 16)),
|
||||
}
|
||||
e := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("vls: encode", e.success)
|
||||
byte_count, success := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok ("vls: encode", success)
|
||||
eq_word("vls: LQV", load_be(code[:], 0), 0xC9042010)
|
||||
|
||||
d_insts: [dynamic]rsp.Instruction
|
||||
@@ -164,8 +164,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
d := rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("vls: decode", d.success)
|
||||
dbyte_count, dsuccess := rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("vls: decode", dsuccess)
|
||||
ok("vls: LQV mnem", d_insts[0].mnemonic == .LQV)
|
||||
i0 := d_insts[0]
|
||||
ok("vls: vt=$v4", i0.ops[0].reg == rsp.VR4)
|
||||
@@ -195,8 +195,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
rsp.inst_branch2(.BNE, rsp.T0, rsp.ZERO, 0),
|
||||
rsp.inst_none(.NOP),
|
||||
}
|
||||
e := rsp.encode(insts, ld_in[:], code[:], &relocs, &errors)
|
||||
ok("br: encode", e.success)
|
||||
byte_count, success := rsp.encode(insts, ld_in[:], code[:], &relocs, &errors)
|
||||
ok("br: encode", success)
|
||||
eq_word("br: BNE word", load_be(code[:], 8), 0x1500FFFD)
|
||||
|
||||
d_insts: [dynamic]rsp.Instruction
|
||||
@@ -206,8 +206,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
d := rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("br: decode", d.success)
|
||||
dbyte_count, dsuccess := rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("br: decode", dsuccess)
|
||||
ok("br: 1 label inferred", len(d_labels) == 1)
|
||||
ok("br: label at byte 0", int(d_labels[0]) == 0)
|
||||
|
||||
@@ -233,8 +233,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
ops = {rsp.op_reg(rsp.T0), rsp.op_reg(rsp.VCO), {}, {}},
|
||||
},
|
||||
}
|
||||
e := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok("cop2c: encode", e.success)
|
||||
byte_count, success := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok("cop2c: encode", success)
|
||||
eq_word("cop2c: CFC2",load_be(code[:], 0), 0x48480000)
|
||||
|
||||
d_insts: [dynamic]rsp.Instruction
|
||||
@@ -244,8 +244,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
d := rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("cop2c: decode", d.success)
|
||||
dbyte_count, dsuccess := rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
ok("cop2c: decode", dsuccess)
|
||||
ok("cop2c: CFC2 mnem",d_insts[0].mnemonic == .CFC2)
|
||||
|
||||
text := rsp.aprint(d_insts[:], d_info[:], d_labels[:],
|
||||
@@ -268,8 +268,8 @@ run_rsp_pipeline_tests :: proc() {
|
||||
ops = {rsp.op_reg(rsp.T0), rsp.op_reg(rsp.Register(rsp.REG_CP0 | 4)), {}, {}},
|
||||
},
|
||||
}
|
||||
e := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok("cp0: encode", e.success)
|
||||
byte_count, success := rsp.encode(insts, nil, code[:], &relocs, &errors)
|
||||
ok("cp0: encode", success)
|
||||
eq_word("cp0: MTC0", load_be(code[:], 0), 0x40882000)
|
||||
|
||||
d_insts: [dynamic]rsp.Instruction
|
||||
@@ -279,7 +279,7 @@ run_rsp_pipeline_tests :: proc() {
|
||||
defer delete(d_info)
|
||||
defer delete(d_labels)
|
||||
clear(&errors)
|
||||
rsp.decode(code[:e.byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
rsp.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors)
|
||||
|
||||
text := rsp.aprint(d_insts[:], d_info[:], d_labels[:],
|
||||
nil, nil, nil, context.temp_allocator)
|
||||
|
||||
Reference in New Issue
Block a user