mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-18 13:41:08 +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:
@@ -25,37 +25,36 @@ decode :: proc(
|
||||
inst_info: ^[dynamic]Instruction_Info,
|
||||
label_defs: ^[dynamic]Label_Definition,
|
||||
errors: ^[dynamic]Error,
|
||||
) -> Result {
|
||||
) -> (byte_count: u32, ok: bool) {
|
||||
n_bytes := u32(len(data)) & ~u32(1)
|
||||
errors_start := u32(len(errors))
|
||||
|
||||
pending_branches: [dynamic]isa.Branch_Target
|
||||
defer delete(pending_branches)
|
||||
|
||||
pc: u32 = 0
|
||||
for pc < n_bytes {
|
||||
if pc + 2 > n_bytes { break }
|
||||
hw := u32(read_u16_be(data, pc))
|
||||
for byte_count < n_bytes {
|
||||
if byte_count + 2 > n_bytes { break }
|
||||
hw := u32(read_u16_be(data, byte_count))
|
||||
|
||||
inst: Instruction
|
||||
info: Instruction_Info
|
||||
info.offset = pc
|
||||
info.offset = byte_count
|
||||
|
||||
matched := try_decode(hw, true, &inst, &info)
|
||||
ilen: u32 = 2
|
||||
|
||||
if !matched {
|
||||
if pc + 4 > n_bytes {
|
||||
append(errors, Error{inst_idx = pc, code = .BUFFER_TOO_SHORT})
|
||||
if byte_count + 4 > n_bytes {
|
||||
append(errors, Error{inst_idx = byte_count, code = .BUFFER_TOO_SHORT})
|
||||
break
|
||||
}
|
||||
word := (hw << 16) | u32(read_u16_be(data, pc + 2))
|
||||
word := (hw << 16) | u32(read_u16_be(data, byte_count + 2))
|
||||
matched = try_decode(word, false, &inst, &info)
|
||||
ilen = 4
|
||||
}
|
||||
|
||||
if !matched {
|
||||
append(errors, Error{inst_idx = pc, code = .INVALID_OPCODE})
|
||||
append(errors, Error{inst_idx = byte_count, code = .INVALID_OPCODE})
|
||||
inst = Instruction{mnemonic = .INVALID, length = 2, mode = .PPC32_VLE}
|
||||
ilen = 2
|
||||
} else {
|
||||
@@ -70,7 +69,7 @@ decode :: proc(
|
||||
append(&pending_branches, isa.Branch_Target{
|
||||
inst_idx = inst_idx,
|
||||
op_idx = slot,
|
||||
target = u32(i32(pc) + i32(op.relative)),
|
||||
target = u32(i32(byte_count) + i32(op.relative)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -78,11 +77,12 @@ decode :: proc(
|
||||
|
||||
append(instructions, inst)
|
||||
append(inst_info, info)
|
||||
pc += ilen
|
||||
byte_count += ilen
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
|
||||
@@ -25,24 +25,23 @@ encode :: proc(
|
||||
errors: ^[dynamic]Error,
|
||||
resolve: bool = true,
|
||||
base_address: u64 = 0,
|
||||
) -> Result {
|
||||
) -> (byte_count: u32, ok: bool) {
|
||||
n_inst := u32(len(instructions))
|
||||
if u32(len(code)) < n_inst * MAX_INST_SIZE {
|
||||
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
|
||||
|
||||
inst_pc := make([]u32, n_inst, context.temp_allocator)
|
||||
|
||||
for i in 0..<n_inst {
|
||||
inst_pc[i] = pc
|
||||
inst_pc[i] = byte_count
|
||||
inst := &instructions[i]
|
||||
ok := encode_one_inline(inst, pc, code, u16(i), relocs, errors)
|
||||
if !ok { return Result{byte_count = pc, success = false} }
|
||||
pc += u32(inst.length)
|
||||
encode_one_inline(inst, byte_count, code, u16(i), relocs, errors) or_return
|
||||
byte_count += u32(inst.length)
|
||||
}
|
||||
|
||||
for &ld in label_defs {
|
||||
@@ -57,7 +56,8 @@ encode :: proc(
|
||||
}
|
||||
|
||||
if !resolve {
|
||||
return Result{byte_count = pc, success = u32(len(errors)) == errors_start}
|
||||
ok = u32(len(errors)) == errors_start
|
||||
return
|
||||
}
|
||||
|
||||
n_relocs := u32(len(relocs))
|
||||
@@ -72,7 +72,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
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
|
||||
@@ -17,7 +17,6 @@ import "../isa"
|
||||
// VLE shares the same GPR/SPR register model as standard PowerPC; types are
|
||||
// duplicated here to keep ppc_vle as a standalone sibling package.
|
||||
|
||||
Result :: isa.Result
|
||||
Error :: isa.Error
|
||||
Error_Code :: isa.Error_Code
|
||||
Label_Definition :: isa.Label_Definition
|
||||
|
||||
@@ -26,7 +26,7 @@ Instruction :: struct #packed {
|
||||
length: u8, // 2 or 4
|
||||
form_id: u16,
|
||||
}
|
||||
#assert(size_of(Instruction) == 80)
|
||||
#assert(size_of(Instruction) == 64)
|
||||
|
||||
@(require_results)
|
||||
inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction {
|
||||
|
||||
@@ -31,7 +31,7 @@ mem_x :: #force_inline proc "contextless" (base, index: Register) -> Memory {
|
||||
}
|
||||
|
||||
Operand :: struct #packed {
|
||||
using _: struct #raw_union {
|
||||
using _: struct #raw_union #packed {
|
||||
reg: Register,
|
||||
mem: Memory,
|
||||
immediate: i64,
|
||||
@@ -40,7 +40,7 @@ Operand :: struct #packed {
|
||||
kind: Operand_Kind,
|
||||
size: u8,
|
||||
}
|
||||
#assert(size_of(Operand) == 18)
|
||||
#assert(size_of(Operand) == 14)
|
||||
|
||||
@(require_results)
|
||||
op_reg :: #force_inline proc "contextless" (r: Register) -> Operand {
|
||||
|
||||
@@ -9,99 +9,99 @@ import "../../isa"
|
||||
|
||||
@(private="file")
|
||||
check :: proc(name: string, instructions: []v.Instruction, label_defs: []isa.Label_Definition, want: []u8) {
|
||||
code := make([]u8, 64, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
code := make([]u8, 64, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
fmt.printf(" [FAIL] %s: encode failed\n", name)
|
||||
for e in errors { fmt.printf(" code=%v inst_idx=%d\n", e.code, e.inst_idx) }
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(r.byte_count) != len(want) {
|
||||
fmt.printf(" [FAIL] %s: byte_count %d (want %d)\n", name, r.byte_count, len(want))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
for i in 0..<len(want) {
|
||||
if code[i] != want[i] {
|
||||
fmt.printf(" [FAIL] %s: byte %d (got %02x, want %02x)\n", name, i, code[i], want[i])
|
||||
fmt.printf(" got ")
|
||||
for j in 0..<len(want) { fmt.printf("%02x ", code[j]) }
|
||||
fmt.printf("\n want ")
|
||||
for j in 0..<len(want) { fmt.printf("%02x ", want[j]) }
|
||||
fmt.println()
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.printf(" [ok] %-35s bytes=", name)
|
||||
for i in 0..<len(want) { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] %s: encode failed\n", name)
|
||||
for e in errors { fmt.printf(" code=%v inst_idx=%d\n", e.code, e.inst_idx) }
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(byte_count) != len(want) {
|
||||
fmt.printf(" [FAIL] %s: byte_count %d (want %d)\n", name, byte_count, len(want))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
for i in 0..<len(want) {
|
||||
if code[i] != want[i] {
|
||||
fmt.printf(" [FAIL] %s: byte %d (got %02x, want %02x)\n", name, i, code[i], want[i])
|
||||
fmt.printf(" got ")
|
||||
for j in 0..<len(want) { fmt.printf("%02x ", code[j]) }
|
||||
fmt.printf("\n want ")
|
||||
for j in 0..<len(want) { fmt.printf("%02x ", want[j]) }
|
||||
fmt.println()
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.printf(" [ok] %-35s bytes=", name)
|
||||
for i in 0..<len(want) { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
|
||||
run_branch_test :: proc() {
|
||||
fmt.println("==== ppc_vle branches + labels ====")
|
||||
fmt.println("==== ppc_vle branches + labels ====")
|
||||
|
||||
// se_b L0; se_blr; L0: se_blr
|
||||
// -> first inst: se_b with displacement 4 (encoded as 4/2=2 in 8-bit field)
|
||||
// se_b form bits 0xE800, mask 0xFF00, B8 at bits 0..7, signed << 1
|
||||
// Target = pc + 4 = 4 bytes ahead, so B8 value = 2 (= 4/2)
|
||||
// bits: 0xE8 | 0x04 wait no. Looking at binutils BD8(58, 0, 0) = (58 << 10) = 0xE800
|
||||
// Actually se_b is BD8(58,0,0). Let me just verify encoder produces something reasonable.
|
||||
{
|
||||
label_defs := [?]isa.Label_Definition{isa.Label_Definition(2)} // points to inst 2
|
||||
instructions := [?]v.Instruction{
|
||||
v.inst_branch(.SE_B, 0),
|
||||
v.inst_none(.SE_BLR),
|
||||
v.inst_none(.SE_BLR),
|
||||
}
|
||||
// Just check encode succeeds and roundtrips
|
||||
code := make([]u8, 16, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
r := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !r.success {
|
||||
fmt.printf(" [FAIL] se_b+label: encode failed\n")
|
||||
for e in errors { fmt.printf(" code=%v\n", e.code) }
|
||||
fail_count += 1
|
||||
} else {
|
||||
fmt.printf(" [ok] se_b+label: %d bytes, bytes=", r.byte_count)
|
||||
for i in 0..<r.byte_count { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
}
|
||||
// se_b L0; se_blr; L0: se_blr
|
||||
// -> first inst: se_b with displacement 4 (encoded as 4/2=2 in 8-bit field)
|
||||
// se_b form bits 0xE800, mask 0xFF00, B8 at bits 0..7, signed << 1
|
||||
// Target = pc + 4 = 4 bytes ahead, so B8 value = 2 (= 4/2)
|
||||
// bits: 0xE8 | 0x04 wait no. Looking at binutils BD8(58, 0, 0) = (58 << 10) = 0xE800
|
||||
// Actually se_b is BD8(58,0,0). Let me just verify encoder produces something reasonable.
|
||||
{
|
||||
label_defs := [?]isa.Label_Definition{isa.Label_Definition(2)} // points to inst 2
|
||||
instructions := [?]v.Instruction{
|
||||
v.inst_branch(.SE_B, 0),
|
||||
v.inst_none(.SE_BLR),
|
||||
v.inst_none(.SE_BLR),
|
||||
}
|
||||
// Just check encode succeeds and roundtrips
|
||||
code := make([]u8, 16, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
byte_count, success := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] se_b+label: encode failed\n")
|
||||
for e in errors { fmt.printf(" code=%v\n", e.code) }
|
||||
fail_count += 1
|
||||
} else {
|
||||
fmt.printf(" [ok] se_b+label: %d bytes, bytes=", byte_count)
|
||||
for i in 0..<byte_count { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
}
|
||||
|
||||
// e_b L0; nop instruction (could be e_or); L0: e_blr equivalent
|
||||
{
|
||||
label_defs := [?]isa.Label_Definition{isa.Label_Definition(2)}
|
||||
instructions := [?]v.Instruction{
|
||||
v.inst_branch(.E_B, 0),
|
||||
v.inst_none(.SE_BLR),
|
||||
v.inst_none(.SE_BLR),
|
||||
}
|
||||
code := make([]u8, 16, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
r := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !r.success {
|
||||
fmt.printf(" [FAIL] e_b+label: encode failed\n")
|
||||
fail_count += 1
|
||||
} else {
|
||||
fmt.printf(" [ok] e_b+label: %d bytes, bytes=", r.byte_count)
|
||||
for i in 0..<r.byte_count { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
}
|
||||
// e_b L0; nop instruction (could be e_or); L0: e_blr equivalent
|
||||
{
|
||||
label_defs := [?]isa.Label_Definition{isa.Label_Definition(2)}
|
||||
instructions := [?]v.Instruction{
|
||||
v.inst_branch(.E_B, 0),
|
||||
v.inst_none(.SE_BLR),
|
||||
v.inst_none(.SE_BLR),
|
||||
}
|
||||
code := make([]u8, 16, context.temp_allocator)
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
byte_count, success := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] e_b+label: encode failed\n")
|
||||
fail_count += 1
|
||||
} else {
|
||||
fmt.printf(" [ok] e_b+label: %d bytes, bytes=", byte_count)
|
||||
for i in 0..<byte_count { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
}
|
||||
|
||||
fmt.printf("\n==> branch_test: %d passed, %d failed\n", ok_count, fail_count)
|
||||
if fail_count > 0 { os.exit(1) }
|
||||
fmt.printf("\n==> branch_test: %d passed, %d failed\n", ok_count, fail_count)
|
||||
if fail_count > 0 { os.exit(1) }
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@ check :: proc(name: string, instructions: []v.Instruction, label_defs: []isa.Lab
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] %s: encode failed\n", name)
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(r.byte_count) != len(want) {
|
||||
fmt.printf(" [FAIL] %s: bc=%d want=%d\n", name, r.byte_count, len(want))
|
||||
if int(byte_count) != len(want) {
|
||||
fmt.printf(" [FAIL] %s: bc=%d want=%d\n", name, byte_count, len(want))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
@@ -61,14 +61,14 @@ run_cond_branch :: proc() {
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
r := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !r.success {
|
||||
byte_count, success := v.encode(instructions[:], label_defs[:], code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] e_bc encode failed (%d errors)\n", len(errors))
|
||||
for e in errors { fmt.printf(" code=%v\n", e.code) }
|
||||
fail_count += 1
|
||||
} else {
|
||||
fmt.printf(" [ok] e_bc 12, cr0[lt], L ")
|
||||
for i in 0..<r.byte_count { fmt.printf("%02x", code[i]) }
|
||||
for i in 0..<byte_count { fmt.printf("%02x", code[i]) }
|
||||
fmt.println()
|
||||
ok_count += 1
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ check :: proc(name: string, instructions: []v.Instruction, label_defs: []isa.Lab
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] %s: encode failed\n", name)
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(r.byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte_count=%d want=%d\n", name, r.byte_count, len(want_bytes))
|
||||
if int(byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte_count=%d want=%d\n", name, byte_count, len(want_bytes))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
@@ -45,8 +45,8 @@ check :: proc(name: string, instructions: []v.Instruction, label_defs: []isa.Lab
|
||||
dec_labs: [dynamic]v.Label_Definition
|
||||
dec_errs: [dynamic]v.Error
|
||||
defer delete(decoded); defer delete(info); defer delete(dec_labs); defer delete(dec_errs)
|
||||
dr := v.decode(code[:r.byte_count], relocs[:], &decoded, &info, &dec_labs, &dec_errs)
|
||||
if !dr.success {
|
||||
dbyte_count, dsuccess := v.decode(code[:byte_count], relocs[:], &decoded, &info, &dec_labs, &dec_errs)
|
||||
if !dsuccess {
|
||||
fmt.printf(" [FAIL] %s: decode failed\n", name)
|
||||
fail_count += 1
|
||||
return
|
||||
@@ -65,7 +65,7 @@ check :: proc(name: string, instructions: []v.Instruction, label_defs: []isa.Lab
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.printf(" [ok] %-35s %d bytes, %d insts\n", name, r.byte_count, len(decoded))
|
||||
fmt.printf(" [ok] %-35s %d bytes, %d insts\n", name, byte_count, len(decoded))
|
||||
ok_count += 1
|
||||
}
|
||||
|
||||
|
||||
@@ -69,15 +69,15 @@ run_extension :: proc() {
|
||||
relocs: [dynamic]v.Relocation; defer delete(relocs)
|
||||
errors: [dynamic]v.Error; defer delete(errors)
|
||||
labels: []isa.Label_Definition
|
||||
r := v.encode(instructions[:], labels, code, &relocs, &errors)
|
||||
check("mixed 16/32-bit sequence encodes", r.success)
|
||||
byte_count, success := v.encode(instructions[:], labels, code, &relocs, &errors)
|
||||
check("mixed 16/32-bit sequence encodes", success)
|
||||
|
||||
decoded: [dynamic]v.Instruction; defer delete(decoded)
|
||||
info: [dynamic]v.Instruction_Info; defer delete(info)
|
||||
dlabs: [dynamic]v.Label_Definition; defer delete(dlabs)
|
||||
derrs: [dynamic]v.Error; defer delete(derrs)
|
||||
dr := v.decode(code[:r.byte_count], nil, &decoded, &info, &dlabs, &derrs)
|
||||
check("mixed sequence decodes", dr.success)
|
||||
dbyte_count, dsuccess := v.decode(code[:byte_count], nil, &decoded, &info, &dlabs, &derrs)
|
||||
check("mixed sequence decodes", dsuccess)
|
||||
check("decoded 3 instructions", len(decoded) == 3)
|
||||
check("first inst is SE_MR (16-bit)", decoded[0].length == 2)
|
||||
check("second inst is E_ADDI (32-bit)", decoded[1].length == 4)
|
||||
|
||||
@@ -10,85 +10,85 @@ import "../../isa"
|
||||
stats: struct { ok, mn_alias, byte_mismatch, encode_fail, decode_fail: int }
|
||||
|
||||
run_full_sweep :: proc() {
|
||||
fmt.println("==== ppc_vle full sweep ====")
|
||||
fmt.println("==== ppc_vle full sweep ====")
|
||||
|
||||
for mn in v.Mnemonic {
|
||||
_run := v.ENCODE_RUNS[u16(mn)]
|
||||
forms := v.ENCODE_FORMS[_run.start:][:_run.count]
|
||||
for &f, fi in forms {
|
||||
test_one(mn, fi, &f)
|
||||
}
|
||||
}
|
||||
for mn in v.Mnemonic {
|
||||
_run := v.ENCODE_RUNS[u16(mn)]
|
||||
forms := v.ENCODE_FORMS[_run.start:][:_run.count]
|
||||
for &f, fi in forms {
|
||||
test_one(mn, fi, &f)
|
||||
}
|
||||
}
|
||||
|
||||
total := stats.ok + stats.mn_alias + stats.byte_mismatch + stats.encode_fail + stats.decode_fail
|
||||
fmt.printf("\n[TOTAL] %d entries\n", total)
|
||||
fmt.printf(" OK: %d (%.1f%%)\n", stats.ok, 100.0 * f32(stats.ok) / f32(total))
|
||||
fmt.printf(" MN_ALIAS: %d (%.1f%%)\n", stats.mn_alias, 100.0 * f32(stats.mn_alias) / f32(total))
|
||||
fmt.printf(" BYTE_MISMATCH: %d (%.1f%%)\n", stats.byte_mismatch, 100.0 * f32(stats.byte_mismatch) / f32(total))
|
||||
fmt.printf(" ENCODE_FAIL: %d (%.1f%%)\n", stats.encode_fail, 100.0 * f32(stats.encode_fail) / f32(total))
|
||||
fmt.printf(" DECODE_FAIL: %d (%.1f%%)\n", stats.decode_fail, 100.0 * f32(stats.decode_fail) / f32(total))
|
||||
total := stats.ok + stats.mn_alias + stats.byte_mismatch + stats.encode_fail + stats.decode_fail
|
||||
fmt.printf("\n[TOTAL] %d entries\n", total)
|
||||
fmt.printf(" OK: %d (%.1f%%)\n", stats.ok, 100.0 * f32(stats.ok) / f32(total))
|
||||
fmt.printf(" MN_ALIAS: %d (%.1f%%)\n", stats.mn_alias, 100.0 * f32(stats.mn_alias) / f32(total))
|
||||
fmt.printf(" BYTE_MISMATCH: %d (%.1f%%)\n", stats.byte_mismatch, 100.0 * f32(stats.byte_mismatch) / f32(total))
|
||||
fmt.printf(" ENCODE_FAIL: %d (%.1f%%)\n", stats.encode_fail, 100.0 * f32(stats.encode_fail) / f32(total))
|
||||
fmt.printf(" DECODE_FAIL: %d (%.1f%%)\n", stats.decode_fail, 100.0 * f32(stats.decode_fail) / f32(total))
|
||||
}
|
||||
|
||||
test_one :: proc(mn: v.Mnemonic, fi: int, f: ^v.Encoding) {
|
||||
inst := v.Instruction{
|
||||
mnemonic = mn,
|
||||
mode = .PPC32_VLE,
|
||||
form_id = u16(fi + 1),
|
||||
length = f.flags.short ? 2 : 4,
|
||||
}
|
||||
code := make([]u8, 8, context.temp_allocator)
|
||||
label_defs: []isa.Label_Definition
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
inst := v.Instruction{
|
||||
mnemonic = mn,
|
||||
mode = .PPC32_VLE,
|
||||
form_id = u16(fi + 1),
|
||||
length = f.flags.short ? 2 : 4,
|
||||
}
|
||||
code := make([]u8, 8, context.temp_allocator)
|
||||
label_defs: []isa.Label_Definition
|
||||
relocs: [dynamic]v.Relocation
|
||||
errors: [dynamic]v.Error
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
instructions := []v.Instruction{inst}
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
stats.encode_fail += 1
|
||||
return
|
||||
}
|
||||
instructions := []v.Instruction{inst}
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
stats.encode_fail += 1
|
||||
return
|
||||
}
|
||||
|
||||
decoded: [dynamic]v.Instruction
|
||||
info: [dynamic]v.Instruction_Info
|
||||
dec_labels: [dynamic]v.Label_Definition
|
||||
dec_errors: [dynamic]v.Error
|
||||
defer delete(decoded); defer delete(info); defer delete(dec_labels); defer delete(dec_errors)
|
||||
decoded: [dynamic]v.Instruction
|
||||
info: [dynamic]v.Instruction_Info
|
||||
dec_labels: [dynamic]v.Label_Definition
|
||||
dec_errors: [dynamic]v.Error
|
||||
defer delete(decoded); defer delete(info); defer delete(dec_labels); defer delete(dec_errors)
|
||||
|
||||
dr := v.decode(code[:r.byte_count], nil, &decoded, &info, &dec_labels, &dec_errors)
|
||||
if !dr.success || len(decoded) == 0 || decoded[0].mnemonic == .INVALID {
|
||||
stats.decode_fail += 1
|
||||
return
|
||||
}
|
||||
dbyte_count, dsuccess := v.decode(code[:byte_count], nil, &decoded, &info, &dec_labels, &dec_errors)
|
||||
if !dsuccess || len(decoded) == 0 || decoded[0].mnemonic == .INVALID {
|
||||
stats.decode_fail += 1
|
||||
return
|
||||
}
|
||||
|
||||
// Re-encode and check bytes
|
||||
code2 := make([]u8, 8, context.temp_allocator)
|
||||
re_relocs: [dynamic]v.Relocation
|
||||
re_errors: [dynamic]v.Error
|
||||
defer delete(re_relocs); defer delete(re_errors)
|
||||
// Re-encode and check bytes
|
||||
code2 := make([]u8, 8, context.temp_allocator)
|
||||
re_relocs: [dynamic]v.Relocation
|
||||
re_errors: [dynamic]v.Error
|
||||
defer delete(re_relocs); defer delete(re_errors)
|
||||
|
||||
rr := v.encode(decoded[:], dec_labels[:], code2, &re_relocs, &re_errors)
|
||||
if !rr.success || rr.byte_count != r.byte_count {
|
||||
stats.byte_mismatch += 1
|
||||
return
|
||||
}
|
||||
for i in 0..<r.byte_count {
|
||||
if code[i] != code2[i] {
|
||||
stats.byte_mismatch += 1
|
||||
if stats.byte_mismatch <= 10 {
|
||||
fmt.printf(" [BYTE_MISMATCH] %v: orig=", mn)
|
||||
for j in 0..<r.byte_count { fmt.printf("%02x", code[j]) }
|
||||
fmt.printf(" re=")
|
||||
for j in 0..<r.byte_count { fmt.printf("%02x", code2[j]) }
|
||||
fmt.printf(" decoded=%v\n", decoded[0].mnemonic)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
rrbyte_count, rrsuccess := v.encode(decoded[:], dec_labels[:], code2, &re_relocs, &re_errors)
|
||||
if !rrsuccess || rrbyte_count != byte_count {
|
||||
stats.byte_mismatch += 1
|
||||
return
|
||||
}
|
||||
for i in 0..<byte_count {
|
||||
if code[i] != code2[i] {
|
||||
stats.byte_mismatch += 1
|
||||
if stats.byte_mismatch <= 10 {
|
||||
fmt.printf(" [BYTE_MISMATCH] %v: orig=", mn)
|
||||
for j in 0..<byte_count { fmt.printf("%02x", code[j]) }
|
||||
fmt.printf(" re=")
|
||||
for j in 0..<byte_count { fmt.printf("%02x", code2[j]) }
|
||||
fmt.printf(" decoded=%v\n", decoded[0].mnemonic)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if decoded[0].mnemonic == mn {
|
||||
stats.ok += 1
|
||||
} else {
|
||||
stats.mn_alias += 1
|
||||
}
|
||||
if decoded[0].mnemonic == mn {
|
||||
stats.ok += 1
|
||||
} else {
|
||||
stats.mn_alias += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ check :: proc(name: string, inst: v.Instruction, want_bytes: []u8) {
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
instructions := []v.Instruction{inst}
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] %s: encode failed\n", name)
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(r.byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte_count=%d (want %d)\n", name, r.byte_count, len(want_bytes))
|
||||
if int(byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte_count=%d (want %d)\n", name, byte_count, len(want_bytes))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
|
||||
@@ -15,15 +15,15 @@ check_encode :: proc(name: string, inst: v.Instruction, want_bytes: []u8) {
|
||||
defer delete(relocs); defer delete(errors)
|
||||
|
||||
instructions := []v.Instruction{inst}
|
||||
r := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !r.success {
|
||||
byte_count, success := v.encode(instructions, label_defs, code, &relocs, &errors)
|
||||
if !success {
|
||||
fmt.printf(" [FAIL] %s: encode failed (%d errors)\n", name, len(errors))
|
||||
for e in errors { fmt.printf(" code=%v\n", e.code) }
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
if int(r.byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte count %d != %d\n", name, r.byte_count, len(want_bytes))
|
||||
if int(byte_count) != len(want_bytes) {
|
||||
fmt.printf(" [FAIL] %s: byte count %d != %d\n", name, byte_count, len(want_bytes))
|
||||
fail_count += 1
|
||||
return
|
||||
}
|
||||
@@ -46,8 +46,8 @@ check_encode :: proc(name: string, inst: v.Instruction, want_bytes: []u8) {
|
||||
dec_errors: [dynamic]v.Error
|
||||
defer delete(decoded); defer delete(info); defer delete(dec_labels); defer delete(dec_errors)
|
||||
|
||||
dr := v.decode(code[:r.byte_count], nil, &decoded, &info, &dec_labels, &dec_errors)
|
||||
if !dr.success {
|
||||
dbyte_count, dsuccess := v.decode(code[:byte_count], nil, &decoded, &info, &dec_labels, &dec_errors)
|
||||
if !dsuccess {
|
||||
fmt.printf(" [FAIL] %s: decode failed\n", name)
|
||||
fail_count += 1
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user