diff --git a/core/rexcode/arm32/instructions.odin b/core/rexcode/arm32/instructions.odin index c4972bbe8..1cbeaa08e 100644 --- a/core/rexcode/arm32/instructions.odin +++ b/core/rexcode/arm32/instructions.odin @@ -40,39 +40,47 @@ Instruction :: struct #packed { // Builders // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = mode == .A32 ? 4 : 2, mode = mode, cond = 14} } // 1-operand +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, r: Register, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(r), {}, {}, {}}} } +@(require_results) inst_i :: #force_inline proc "contextless" (m: Mnemonic, v: i64, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_imm(v), {}, {}, {}}} } // 2-operand +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rm: Register, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_reg(rm), {}, {}}} } +@(require_results) inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, v: i64, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_imm(v), {}, {}}} } // 3-operand data-proc (ADD/SUB/AND/etc.) +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rn, rm: Register, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_reg(rn), op_reg(rm), {}}} } +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd, rn: Register, v: i64, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_reg(rn), op_imm(v), {}}} } +@(require_results) inst_r_r_r_shifted :: #force_inline proc "contextless" ( m: Mnemonic, rd, rn, rm: Register, st: Shift_Type, amt: u8, mode: Mode = .A32, ) -> Instruction { @@ -81,33 +89,39 @@ inst_r_r_r_shifted :: #force_inline proc "contextless" ( } // 4-operand MLA / MLS / SMLAL etc. +@(require_results) inst_r_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rn, rm, ra: Register, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 4, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_reg(rn), op_reg(rm), op_reg(ra)}} } // Memory load/store +@(require_results) inst_load :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, mm: Memory, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(rd), op_mem(mm), {}, {}}} } +@(require_results) inst_store :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, mm: Memory, mode: Mode = .A32) -> Instruction { return inst_load(m, rd, mm, mode) } // LDM/STM/PUSH/POP block move +@(require_results) inst_block :: #force_inline proc "contextless" (m: Mnemonic, base: Register, mask: u16, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_reg(base), op_reg_list(mask), {}, {}}} } // Branches with label +@(require_results) inst_branch :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32, mode: Mode = .A32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = mode == .A32 ? 4 : 4, mode = mode, cond = 14, ops = {op_label(label_id), {}, {}, {}}} } // Set condition code on any builder +@(require_results) inst_set_cond :: #force_inline proc "contextless" (inst: Instruction, cond: u8) -> Instruction { out := inst out.cond = cond @@ -115,6 +129,7 @@ inst_set_cond :: #force_inline proc "contextless" (inst: Instruction, cond: u8) } // Set S flag (sets APSR.NZCV) +@(require_results) inst_set_flags :: #force_inline proc "contextless" (inst: Instruction) -> Instruction { out := inst out.flags.sets_flags = true diff --git a/core/rexcode/arm64/instructions.odin b/core/rexcode/arm64/instructions.odin index 811be0bb4..5c5cb7857 100644 --- a/core/rexcode/arm64/instructions.odin +++ b/core/rexcode/arm64/instructions.odin @@ -22,89 +22,104 @@ Instruction :: struct #packed { // inline by the caller using the Instruction struct directly. // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 4} } // Single-register (e.g. BR, BLR). +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, r: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_reg(r), {}, {}, {}}} } // 2-register (e.g. CLZ, RBIT). +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rn: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_reg(rn), {}, {}}} } // 3-register (e.g. ADD shifted, MUL, UDIV, ASRV). +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rn, rm: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rn), op_reg(rm), {}}} } // 4-register R4-type (MADD, MSUB, SMADDL, ...). +@(require_results) inst_r_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rn, rm, ra: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 4, length = 4, ops = {op_reg(rd), op_reg(rn), op_reg(rm), op_reg(ra)}} } // 2-register + immediate (e.g. ADD imm). +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd, rn: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rn), op_imm(imm), {}}} } // 1-register + immediate (e.g. MOVZ). +@(require_results) inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_imm(imm), {}, {}}} } // MOVZ/MOVN/MOVK with explicit hw shift (0/16/32/48). +@(require_results) inst_mov_imm :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, imm: i64, hw: u8) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_imm(imm), op_imm(i64(hw), 1), {}}} } // Load/store register: Rt + memory. +@(require_results) inst_ldst :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rt), op_mem(mm), {}, {}}} } // Load/store pair: Rt, Rt2, memory. +@(require_results) inst_ldp_stp :: #force_inline proc "contextless" (m: Mnemonic, rt, rt2: Register, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rt), op_reg(rt2), op_mem(mm), {}}} } // PC-relative branch (B, BL). +@(require_results) inst_branch :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_label(label_id, 4), {}, {}, {}}} } // Conditional branch (B.cond label). +@(require_results) inst_b_cond :: #force_inline proc "contextless" (c: Cond, label_id: u32) -> Instruction { return Instruction{mnemonic = .B_COND, operand_count = 2, length = 4, ops = {op_cond(c), op_label(label_id, 4), {}, {}}} } // CBZ/CBNZ: Rt, label. +@(require_results) inst_cbz :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rt), op_label(label_id, 4), {}, {}}} } // TBZ/TBNZ: Rt, bit, label. +@(require_results) inst_tbz :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, bit: u8, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rt), op_imm(i64(bit), 1), op_label(label_id, 4), {}}} } // CSEL/CSINC/CSINV/CSNEG: Rd, Rn, Rm, cond. +@(require_results) inst_csel :: #force_inline proc "contextless" (m: Mnemonic, rd, rn, rm: Register, c: Cond) -> Instruction { return Instruction{mnemonic = m, operand_count = 4, length = 4, ops = {op_reg(rd), op_reg(rn), op_reg(rm), op_cond(c)}} diff --git a/core/rexcode/mips/instructions.odin b/core/rexcode/mips/instructions.odin index f6672f610..692a1c5e6 100644 --- a/core/rexcode/mips/instructions.odin +++ b/core/rexcode/mips/instructions.odin @@ -26,44 +26,52 @@ Instruction :: struct #packed { // Builders (mirror x86's `inst_*` shapes; per the cross-arch contract) // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 4} } +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, a: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_reg(a), {}, {}, {}}} } +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, dst, src: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(dst), op_reg(src), {}, {}}} } +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, dst, s1, s2: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(dst), op_reg(s1), op_reg(s2), {}}} } // MIPS three-operand immediate: $rt, $rs, imm (e.g. ADDI rt, rs, imm). +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt, rs: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rt), op_reg(rs), op_imm(imm, 2), {}}} } // Two-operand immediate (e.g. LUI rt, imm; LI variants). +@(require_results) inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rt), op_imm(imm, 2), {}, {}}} } // Load/store: reg + memory (LW $rt, disp($rs)). +@(require_results) inst_r_m :: #force_inline proc "contextless" (m: Mnemonic, r: Register, mm: Memory, size: u8 = 4) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(r), op_mem(mm, size), {}, {}}} } // Shift by immediate: $rd, $rt, shamt (SLL/SRL/SRA). +@(require_results) inst_shift :: #force_inline proc "contextless" (m: Mnemonic, rd, rt: Register, shamt: u8) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rt), op_imm(i64(shamt), 1), {}}} @@ -74,30 +82,35 @@ inst_shift_v :: inst_r_r_r // Single-operand: JR $rs, JALR $rd (with implicit RA), MFHI/MFLO/MTHI/MTLO, // SYSCALL/BREAK take an imm code so they use inst_i below. +@(require_results) inst_i :: #force_inline proc "contextless" (m: Mnemonic, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_imm(imm, 4), {}, {}, {}}} } // Two-reg branch + label (BEQ/BNE: rs, rt, target). +@(require_results) inst_branch2 :: #force_inline proc "contextless" (m: Mnemonic, rs, rt: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rs), op_reg(rt), op_label(label_id), {}}} } // One-reg branch + label (BLTZ/BGEZ/BLEZ/BGTZ/BLTZAL/BGEZAL/...). +@(require_results) inst_branch1 :: #force_inline proc "contextless" (m: Mnemonic, rs: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rs), op_label(label_id), {}, {}}} } // J-type jump (J/JAL: target only). +@(require_results) inst_jump :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_label(label_id), {}, {}, {}}} } // COP0 move with explicit selector: MFC0 $rt, $rd, sel (R2+). +@(require_results) inst_cp0_sel :: #force_inline proc "contextless" (m: Mnemonic, rt, rd: Register, sel: u8) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rt), op_reg(rd), op_imm(i64(sel), 1), {}}} diff --git a/core/rexcode/mos6502/instructions.odin b/core/rexcode/mos6502/instructions.odin index 916b82179..cd2758537 100644 --- a/core/rexcode/mos6502/instructions.odin +++ b/core/rexcode/mos6502/instructions.odin @@ -25,10 +25,12 @@ Instruction :: struct #packed { // Builders (mirror the contract: shape spelled out, comma-separated) // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 1} } +@(require_results) inst_a :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { // Explicit accumulator (e.g. `ROL A`). Encodes to 1 byte (opcode only) // and counts as 1 operand for the matcher. @@ -38,6 +40,7 @@ inst_a :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { } } +@(require_results) inst_i :: #force_inline proc "contextless" (m: Mnemonic, imm: i64) -> Instruction { return Instruction{ mnemonic = m, operand_count = 1, length = 2, @@ -45,6 +48,7 @@ inst_i :: #force_inline proc "contextless" (m: Mnemonic, imm: i64) -> Instructio } } +@(require_results) inst_m :: #force_inline proc "contextless" (m: Mnemonic, mm: Memory) -> Instruction { return Instruction{ mnemonic = m, operand_count = 1, length = 0, // filled by encoder @@ -52,6 +56,7 @@ inst_m :: #force_inline proc "contextless" (m: Mnemonic, mm: Memory) -> Instruct } } +@(require_results) inst_rel :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{ mnemonic = m, operand_count = 1, length = 2, @@ -60,6 +65,7 @@ inst_rel :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Ins } // BBR/BBS: zero-page byte + relative branch (3-byte encoding). +@(require_results) inst_zp_rel :: #force_inline proc "contextless" (m: Mnemonic, zp: u8, label_id: u32) -> Instruction { return Instruction{ mnemonic = m, operand_count = 2, length = 3, @@ -68,6 +74,7 @@ inst_zp_rel :: #force_inline proc "contextless" (m: Mnemonic, zp: u8, label_id: } // HuC6280 TST # imm, addr (3 or 4 bytes depending on addressing mode). +@(require_results) inst_tst :: #force_inline proc "contextless" (m: Mnemonic, imm: i64, mm: Memory) -> Instruction { return Instruction{ mnemonic = m, operand_count = 2, length = 0, @@ -76,6 +83,7 @@ inst_tst :: #force_inline proc "contextless" (m: Mnemonic, imm: i64, mm: Memory) } // HuC6280 block transfer: src, dst, length (7-byte encoding). +@(require_results) inst_block :: #force_inline proc "contextless" (m: Mnemonic, src, dst, length_val: u16) -> Instruction { return Instruction{ mnemonic = m, operand_count = 3, length = 7, diff --git a/core/rexcode/mos65816/instructions.odin b/core/rexcode/mos65816/instructions.odin index 320d71cf6..478be8560 100644 --- a/core/rexcode/mos65816/instructions.odin +++ b/core/rexcode/mos65816/instructions.odin @@ -18,35 +18,42 @@ Instruction :: struct #packed { } #assert(size_of(Instruction) == 40) +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 1} } +@(require_results) inst_a :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 1, ops = {op_reg(A), {}}} } +@(require_results) inst_i8 :: #force_inline proc "contextless" (m: Mnemonic, v: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 2, ops = {op_imm8(v), {}}} } +@(require_results) inst_i16 :: #force_inline proc "contextless" (m: Mnemonic, v: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 3, ops = {op_imm16(v), {}}} } +@(require_results) inst_m :: #force_inline proc "contextless" (m: Mnemonic, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 0, ops = {op_mem(mm), {}}} } +@(require_results) inst_rel :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 2, ops = {op_label(label_id, 1), {}}} } +@(require_results) inst_rel_long :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 3, ops = {op_label(label_id, 2), {}}} @@ -54,6 +61,7 @@ inst_rel_long :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) - // MVN/MVP src, dst -- caller writes "natural" order; encoder reverses to // the WDC-specified opcode | dst_bank | src_bank byte layout. +@(require_results) inst_block_move :: #force_inline proc "contextless" (m: Mnemonic, src_bank, dst_bank: u8) -> Instruction { return Instruction{ mnemonic = m, operand_count = 2, length = 3, diff --git a/core/rexcode/ppc/instructions.odin b/core/rexcode/ppc/instructions.odin index ca7853f9c..decd8fffc 100644 --- a/core/rexcode/ppc/instructions.odin +++ b/core/rexcode/ppc/instructions.odin @@ -32,74 +32,89 @@ Instruction :: struct #packed { // Builders // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 4, mode = mode} } +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, r: Register, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, mode = mode, ops = {op_reg(r), {}, {}, {}}} } +@(require_results) inst_i :: #force_inline proc "contextless" (m: Mnemonic, v: i64, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, mode = mode, ops = {op_imm(v), {}, {}, {}}} } +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, ra: Register, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, mode = mode, ops = {op_reg(rd), op_reg(ra), {}, {}}} } +@(require_results) inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, v: i64, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, mode = mode, ops = {op_reg(rd), op_imm(v), {}, {}}} } +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, ra, rb: Register, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, mode = mode, ops = {op_reg(rd), op_reg(ra), op_reg(rb), {}}} } +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd, ra: Register, v: i64, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, mode = mode, ops = {op_reg(rd), op_reg(ra), op_imm(v), {}}} } +@(require_results) inst_r_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, ra, rb, rc: Register, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 4, length = 4, mode = mode, ops = {op_reg(rd), op_reg(ra), op_reg(rb), op_reg(rc)}} } // Memory load/store: RT, [RA + disp] or [RA + RB]. +@(require_results) inst_load :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, mm: Memory, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, mode = mode, ops = {op_reg(rt), op_mem(mm), {}, {}}} } +@(require_results) inst_store :: #force_inline proc "contextless" (m: Mnemonic, rs: Register, mm: Memory, mode: Mode = .PPC32) -> Instruction { return inst_load(m, rs, mm, mode) } // Branches with label resolution +@(require_results) inst_branch :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, mode = mode, ops = {op_label(label_id), {}, {}, {}}} } // Conditional branch with BO/BI baked into the mnemonic (BEQ/BNE/...) + label +@(require_results) inst_branch_cond :: #force_inline proc "contextless" (m: Mnemonic, crf: Register, label_id: u32, mode: Mode = .PPC32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, mode = mode, ops = {op_reg(crf), op_label(label_id), {}, {}}} } // Flag setters +@(require_results) inst_set_rc :: #force_inline proc "contextless" (inst: Instruction) -> Instruction { out := inst out.flags.sets_cr0 = true return out } +@(require_results) inst_set_oe :: #force_inline proc "contextless" (inst: Instruction) -> Instruction { out := inst out.flags.has_oe = true return out } +@(require_results) inst_set_lk :: #force_inline proc "contextless" (inst: Instruction) -> Instruction { out := inst out.flags.lk = true diff --git a/core/rexcode/ppc_vle/instructions.odin b/core/rexcode/ppc_vle/instructions.odin index 056e73a0a..db0a4049a 100644 --- a/core/rexcode/ppc_vle/instructions.odin +++ b/core/rexcode/ppc_vle/instructions.odin @@ -25,39 +25,47 @@ Instruction :: struct #packed { form_id: u16, } +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 2, mode = .PPC32_VLE} } +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, r: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 2, mode = .PPC32_VLE, ops = {op_reg(r), {}, {}, {}}} } +@(require_results) inst_i :: #force_inline proc "contextless" (m: Mnemonic, v: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, mode = .PPC32_VLE, ops = {op_imm(v), {}, {}, {}}} } +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, ra: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 2, mode = .PPC32_VLE, ops = {op_reg(rd), op_reg(ra), {}, {}}} } +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, ra, rb: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, mode = .PPC32_VLE, ops = {op_reg(rd), op_reg(ra), op_reg(rb), {}}} } +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd, ra: Register, v: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, mode = .PPC32_VLE, ops = {op_reg(rd), op_reg(ra), op_imm(v), {}}} } +@(require_results) inst_load :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, mode = .PPC32_VLE, ops = {op_reg(rt), op_mem(mm), {}, {}}} } +@(require_results) inst_branch :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, mode = .PPC32_VLE, ops = {op_label(label_id), {}, {}, {}}} diff --git a/core/rexcode/riscv/instructions.odin b/core/rexcode/riscv/instructions.odin index 509f7294e..ec73b59e0 100644 --- a/core/rexcode/riscv/instructions.odin +++ b/core/rexcode/riscv/instructions.odin @@ -26,83 +26,97 @@ Instruction :: struct #packed { // Builders (shape spelled out, comma-separated) // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 4} } // R-type: rd, rs1, rs2 +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rs1, rs2: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rs1), op_reg(rs2), {}}} } // I-type (ALU): rd, rs1, imm12 +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rd, rs1: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rs1), op_imm(imm, 2), {}}} } // I-type (shift): rd, rs1, shamt +@(require_results) inst_shift :: #force_inline proc "contextless" (m: Mnemonic, rd, rs1: Register, shamt: u8) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rs1), op_imm(i64(shamt), 1), {}}} } // I-type load: rd, disp(base) +@(require_results) inst_load :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_mem(mm), {}, {}}} } // S-type store: rs2 (data), disp(base) +@(require_results) inst_store :: #force_inline proc "contextless" (m: Mnemonic, rs2: Register, mm: Memory) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rs2), op_mem(mm), {}, {}}} } // U-type: rd, imm20 +@(require_results) inst_u :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_imm(imm, 4), {}, {}}} } // J-type: rd, label +@(require_results) inst_jal :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_label(label_id, 4), {}, {}}} } // B-type branch: rs1, rs2, label +@(require_results) inst_branch :: #force_inline proc "contextless" (m: Mnemonic, rs1, rs2: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rs1), op_reg(rs2), op_label(label_id, 2), {}}} } // JALR: rd, rs1, imm12 (indirect jump with offset) +@(require_results) inst_jalr :: #force_inline proc "contextless" (rd, rs1: Register, imm: i64) -> Instruction { return Instruction{mnemonic = .JALR, operand_count = 3, length = 4, ops = {op_reg(rd), op_reg(rs1), op_imm(imm, 2), {}}} } // CSR ops: rd, csr, rs1 +@(require_results) inst_csr :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, csr: u16, rs1: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_imm(i64(csr), 2), op_reg(rs1), {}}} } // CSR immediate ops: rd, csr, zimm5 +@(require_results) inst_csr_i :: #force_inline proc "contextless" (m: Mnemonic, rd: Register, csr: u16, zimm5: u8) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rd), op_imm(i64(csr), 2), op_imm(i64(zimm5), 1), {}}} } // FP R4-type: rd, rs1, rs2, rs3 (FMADD/FMSUB/FNMADD/FNMSUB) +@(require_results) inst_r4 :: #force_inline proc "contextless" (m: Mnemonic, rd, rs1, rs2, rs3: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 4, length = 4, ops = {op_reg(rd), op_reg(rs1), op_reg(rs2), op_reg(rs3)}} } // FP R-type with 2 regs: rd, rs1 (FSQRT, FCVT, FMV, FCLASS, ...) +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, rd, rs1: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rd), op_reg(rs1), {}, {}}} diff --git a/core/rexcode/rsp/instructions.odin b/core/rexcode/rsp/instructions.odin index 858789ad2..d1acb4fb2 100644 --- a/core/rexcode/rsp/instructions.odin +++ b/core/rexcode/rsp/instructions.odin @@ -22,55 +22,67 @@ Instruction :: struct #packed { // Builders (mirror x86/mips conventions) // ============================================================================= +@(require_results) inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction { return Instruction{mnemonic = m, operand_count = 0, length = 4} } +@(require_results) inst_r :: #force_inline proc "contextless" (m: Mnemonic, a: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_reg(a), {}, {}, {}}} } +@(require_results) inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, d, s: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(d), op_reg(s), {}, {}}} } +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, d, s1, s2: Register) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(d), op_reg(s1), op_reg(s2), {}}} } +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt, rs: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rt), op_reg(rs), op_imm(imm, 2), {}}} } +@(require_results) inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, imm: i64) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rt), op_imm(imm, 2), {}, {}}} } +@(require_results) inst_r_m :: #force_inline proc "contextless" (m: Mnemonic, r: Register, mm: Memory, size: u8 = 4) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(r), op_mem(mm, size), {}, {}}} } // Vector ALU: 3-operand vector op with optional element selector on vt. +@(require_results) inst_v_v_v :: #force_inline proc "contextless" (m: Mnemonic, vd, vs, vt: Register, vt_element: u8 = 0) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_vr(vd), op_vr(vs), op_vr(vt, vt_element), {}}} } // Vector load/store: $vt[element], offset(base). +@(require_results) inst_v_vmem :: #force_inline proc "contextless" (m: Mnemonic, vt: Register, vmem_op: Vector_Mem) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_vr(vt, vmem_op.element), op_vmem(vmem_op, 16), {}, {}}} } // Branch helpers +@(require_results) inst_branch1 :: #force_inline proc "contextless" (m: Mnemonic, rs: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 2, length = 4, ops = {op_reg(rs), op_label(label_id), {}, {}}} } +@(require_results) inst_branch2 :: #force_inline proc "contextless" (m: Mnemonic, rs, rt: Register, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 3, length = 4, ops = {op_reg(rs), op_reg(rt), op_label(label_id), {}}} } +@(require_results) inst_jump :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction { return Instruction{mnemonic = m, operand_count = 1, length = 4, ops = {op_label(label_id), {}, {}, {}}} diff --git a/core/rexcode/x86/instructions.odin b/core/rexcode/x86/instructions.odin index f85b443fa..6a2fcfe3b 100644 --- a/core/rexcode/x86/instructions.odin +++ b/core/rexcode/x86/instructions.odin @@ -42,6 +42,7 @@ Instruction :: struct #packed { // ----------------------------------------------------------------------------- // Convenient instruction builders for common patterns +@(require_results) inst_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -50,6 +51,7 @@ inst_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, s } } +@(require_results) inst_r_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Register, source: Memory, size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -58,6 +60,7 @@ inst_r_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: R } } +@(require_results) inst_m_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Memory, size: u8, source: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -66,6 +69,7 @@ inst_m_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: M } } +@(require_results) inst_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Register, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -74,6 +78,7 @@ inst_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: R } } +@(require_results) inst_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, r: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -82,6 +87,7 @@ inst_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, r: Register) -> } } +@(require_results) inst_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, m: Memory, size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -90,6 +96,7 @@ inst_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, m: Memory, size: } } +@(require_results) inst_none :: #force_inline proc "contextless" (mnemonic: Mnemonic) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -97,6 +104,7 @@ inst_none :: #force_inline proc "contextless" (mnemonic: Mnemonic) -> Instructio } } +@(require_results) inst_rel :: #force_inline proc "contextless" (mnemonic: Mnemonic, label_id: u32, size: u8 = 4) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -106,6 +114,7 @@ inst_rel :: #force_inline proc "contextless" (mnemonic: Mnemonic, label_id: u32, } // 3-operand register instructions (VEX/EVEX: VADDPS xmm0, xmm1, xmm2) +@(require_results) inst_r_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1, source2: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -115,6 +124,7 @@ inst_r_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, } // 3-operand register-register-memory (VEX/EVEX: VADDPS xmm0, xmm1, [mem]) +@(require_results) inst_r_r_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1: Register, source2: Memory, size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -124,6 +134,7 @@ inst_r_r_m :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, } // 3-operand register-register-immediate (e.g., SHLD r64, r64, imm8) +@(require_results) inst_r_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source: Register, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -133,6 +144,7 @@ inst_r_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, } // Memoryory-immediate (MOV [mem], imm32) +@(require_results) inst_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Memory, size: u8, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -142,6 +154,7 @@ inst_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: M } // Single immediate (PUSH imm32, RET imm16, INT imm8, etc.) +@(require_results) inst_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -151,6 +164,7 @@ inst_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, immediate: i64, } // 3-operand register-memory-immediate (IMUL r64, m64, imm32) +@(require_results) inst_r_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Register, source: Memory, mem_size: u8, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -160,6 +174,7 @@ inst_r_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: } // 3-operand memory-register-immediate (SHLD m64, r64, imm8) +@(require_results) inst_m_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Memory, mem_size: u8, source: Register, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -169,6 +184,7 @@ inst_m_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: } // Relative offset (JMP rel8, JCC rel32, etc.) - uses raw offset, not label +@(require_results) inst_rel_offset :: #force_inline proc "contextless" (mnemonic: Mnemonic, offset: i64, offset_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -178,6 +194,7 @@ inst_rel_offset :: #force_inline proc "contextless" (mnemonic: Mnemonic, offset: } // 3-operand register-memory-register (BEXTR r64, m64, r64) +@(require_results) inst_r_m_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: Register, source1: Memory, mem_size: u8, source2: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -187,6 +204,7 @@ inst_r_m_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination: } // 4-operand register instructions (EVEX with 4 operands) +@(require_results) inst_r_r_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1, source2, source3: Register) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -196,6 +214,7 @@ inst_r_r_r_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destinatio } // 4-operand: 3 registers + immediate (VCMPPS xmm, xmm, xmm, imm8) +@(require_results) inst_r_r_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1, source2: Register, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -205,6 +224,7 @@ inst_r_r_r_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destinatio } // 4-operand: 2 registers + memory + immediate (VCMPPS xmm, xmm, m128, imm8) +@(require_results) inst_r_r_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1: Register, source2: Memory, mem_size: u8, immediate: i64, immediate_size: u8) -> Instruction { return Instruction{ mnemonic = mnemonic, @@ -214,6 +234,7 @@ inst_r_r_m_i :: #force_inline proc "contextless" (mnemonic: Mnemonic, destinatio } // 4-operand: 2 registers + memory + register (VBLENDVPS xmm, xmm, m128, xmm) +@(require_results) inst_r_r_m_r :: #force_inline proc "contextless" (mnemonic: Mnemonic, destination, source1: Register, source2: Memory, mem_size: u8, source3: Register) -> Instruction { return Instruction{ mnemonic = mnemonic,