mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-03 20:58:32 +00:00
rexcode/arm64: CCMP/CCMN-imm, HINT, MSR-imm, USDOT encode forms
Conditional compare immediate (CCMP_IMM/CCMN_IMM: imm5 at 20:16 via a new IMM5_HI encoding, bit 11 set), HINT #imm7, MSR <pstatefield>,#imm (new MSR_PSTATE encoding placing op1 at 18:16 / op2 at 7:5, CRm via the shared BARRIER_FIELD), and USDOT (I8MM unsigned-by-signed dot product, .2S/.4S). Hand-written into the core (outside the specgen region). All forms byte-exact vs llvm-mc and decode-clean; 461 tests green.
This commit is contained in:
@@ -234,6 +234,11 @@ extract_operand_inline :: #force_inline proc "contextless" (
|
||||
return Operand{immediate = i64(((word >> 11) & 0xF) >> mb), kind = .IMMEDIATE, size = 1}
|
||||
case .NEON_EXT_IDX:
|
||||
return Operand{immediate = i64((word >> 11) & 0xF), kind = .IMMEDIATE, size = 1}
|
||||
case .IMM5_HI:
|
||||
return Operand{immediate = i64((word >> 16) & 0x1F), kind = .IMMEDIATE, size = 1}
|
||||
case .MSR_PSTATE:
|
||||
v := ((word >> 16) & 0x7) << 3 | ((word >> 5) & 0x7)
|
||||
return Operand{immediate = i64(v), kind = .IMMEDIATE, size = 1}
|
||||
|
||||
// ---- Memory operand variants ------------------------------------------
|
||||
case .OFFSET_BASE_U12:
|
||||
|
||||
@@ -478,6 +478,13 @@ pack_operand_inline :: #force_inline proc(
|
||||
case .NEON_EXT_IDX:
|
||||
return (u32(op.immediate) & 0xF) << 11
|
||||
|
||||
// CCMP/CCMN immediate (imm5 at 20:16) and MSR-immediate PSTATE selector.
|
||||
case .IMM5_HI:
|
||||
return (u32(op.immediate) & 0x1F) << 16
|
||||
case .MSR_PSTATE:
|
||||
v := u32(op.immediate)
|
||||
return ((v >> 3) & 0x7) << 16 | (v & 0x7) << 5
|
||||
|
||||
// NEON MOVI/FMOV immediate split: abc at bits 18-16, defgh at bits 9-5.
|
||||
case .NEON_IMM8_FMOV:
|
||||
v := u32(op.immediate) & 0xFF
|
||||
|
||||
@@ -246,6 +246,13 @@ Operand_Encoding :: enum u8 {
|
||||
NEON_IDX4, // INS source lane index in imm4 (14:11); index << markerbit
|
||||
NEON_EXT_IDX, // EXT byte index in imm4 (14:11)
|
||||
|
||||
// ---- MSR (immediate to PSTATE): pstate field selector op1:op2 ----
|
||||
// User passes the combined 6-bit selector (op1<<3 | op2); op1 lands at
|
||||
// bits 18:16, op2 at bits 7:5. The #imm goes to CRm (bits 11:8) via
|
||||
// BARRIER_FIELD, which it shares with the DMB/DSB barrier encoding.
|
||||
IMM5_HI, // generic 5-bit immediate at bits 20:16 (CCMP/CCMN immediate)
|
||||
MSR_PSTATE, // PSTATE field selector: op1 at 18:16, op2 at 7:5
|
||||
|
||||
// ---- LSE atomics ------------------------------------------------------
|
||||
ATOMIC_RS, // Rs (source / compare) at bits 16-20
|
||||
ATOMIC_RT, // Rt (target) at bits 0-4
|
||||
|
||||
@@ -121,8 +121,12 @@ inst_csneg_r_r_r_c :: #force_inline proc "contextless" (dst: Regist
|
||||
emit_csneg_r_r_r_c :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register, cond: Cond) { append(instructions, inst_csneg_r_r_r_c(dst, src, src2, cond)) }
|
||||
inst_ccmp_reg_r_r_i_c :: #force_inline proc "contextless" (dst: Register, src: Register, imm: i64, cond: Cond) -> Instruction { return Instruction{mnemonic = .CCMP_REG, operand_count = 4, length = 4, ops = {op_reg(dst), op_reg(src), op_imm(imm, 1), op_cond(cond)}} }
|
||||
emit_ccmp_reg_r_r_i_c :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, imm: i64, cond: Cond) { append(instructions, inst_ccmp_reg_r_r_i_c(dst, src, imm, cond)) }
|
||||
inst_ccmp_imm_r_i_i_c :: #force_inline proc "contextless" (dst: Register, imm: i64, imm2: i64, cond: Cond) -> Instruction { return Instruction{mnemonic = .CCMP_IMM, operand_count = 4, length = 4, ops = {op_reg(dst), op_imm(imm, 1), op_imm(imm2, 1), op_cond(cond)}} }
|
||||
emit_ccmp_imm_r_i_i_c :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, imm: i64, imm2: i64, cond: Cond) { append(instructions, inst_ccmp_imm_r_i_i_c(dst, imm, imm2, cond)) }
|
||||
inst_ccmn_reg_r_r_i_c :: #force_inline proc "contextless" (dst: Register, src: Register, imm: i64, cond: Cond) -> Instruction { return Instruction{mnemonic = .CCMN_REG, operand_count = 4, length = 4, ops = {op_reg(dst), op_reg(src), op_imm(imm, 1), op_cond(cond)}} }
|
||||
emit_ccmn_reg_r_r_i_c :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, imm: i64, cond: Cond) { append(instructions, inst_ccmn_reg_r_r_i_c(dst, src, imm, cond)) }
|
||||
inst_ccmn_imm_r_i_i_c :: #force_inline proc "contextless" (dst: Register, imm: i64, imm2: i64, cond: Cond) -> Instruction { return Instruction{mnemonic = .CCMN_IMM, operand_count = 4, length = 4, ops = {op_reg(dst), op_imm(imm, 1), op_imm(imm2, 1), op_cond(cond)}} }
|
||||
emit_ccmn_imm_r_i_i_c :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, imm: i64, imm2: i64, cond: Cond) { append(instructions, inst_ccmn_imm_r_i_i_c(dst, imm, imm2, cond)) }
|
||||
inst_extr_r_r_r_i :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register, imm: i64) -> Instruction { return Instruction{mnemonic = .EXTR, operand_count = 4, length = 4, ops = {op_reg(dst), op_reg(src), op_reg(src2), op_imm(imm, 1)}} }
|
||||
emit_extr_r_r_r_i :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register, imm: i64) { append(instructions, inst_extr_r_r_r_i(dst, src, src2, imm)) }
|
||||
inst_b_l :: #force_inline proc "contextless" (label: u32) -> Instruction { return inst_branch(.B, label) }
|
||||
@@ -205,8 +209,12 @@ inst_sev_none :: #force_inline proc "contextless" () -> Instru
|
||||
emit_sev_none :: #force_inline proc(instructions: ^[dynamic]Instruction) { append(instructions, inst_sev_none()) }
|
||||
inst_sevl_none :: #force_inline proc "contextless" () -> Instruction { return inst_none(.SEVL) }
|
||||
emit_sevl_none :: #force_inline proc(instructions: ^[dynamic]Instruction) { append(instructions, inst_sevl_none()) }
|
||||
inst_hint_i :: #force_inline proc "contextless" (imm: i64) -> Instruction { return Instruction{mnemonic = .HINT, operand_count = 1, length = 4, ops = {op_imm(imm, 1), {}, {}, {}}} }
|
||||
emit_hint_i :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64) { append(instructions, inst_hint_i(imm)) }
|
||||
inst_mrs_r_i :: #force_inline proc "contextless" (dst: Register, imm: i64) -> Instruction { return inst_r_i(.MRS, dst, imm) }
|
||||
emit_mrs_r_i :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, imm: i64) { append(instructions, inst_mrs_r_i(dst, imm)) }
|
||||
inst_msr_imm_i_i :: #force_inline proc "contextless" (imm: i64, imm2: i64) -> Instruction { return Instruction{mnemonic = .MSR_IMM, operand_count = 2, length = 4, ops = {op_imm(imm, 4), op_imm(imm2, 1), {}, {}}} }
|
||||
emit_msr_imm_i_i :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64, imm2: i64) { append(instructions, inst_msr_imm_i_i(imm, imm2)) }
|
||||
inst_msr_reg_i_r :: #force_inline proc "contextless" (imm: i64, src: Register) -> Instruction { return Instruction{mnemonic = .MSR_REG, operand_count = 2, length = 4, ops = {op_imm(imm, 4), op_reg(src), {}, {}}} }
|
||||
emit_msr_reg_i_r :: #force_inline proc(instructions: ^[dynamic]Instruction, imm: i64, src: Register) { append(instructions, inst_msr_reg_i_r(imm, src)) }
|
||||
inst_isb_i :: #force_inline proc "contextless" (imm: i64) -> Instruction { return Instruction{mnemonic = .ISB, operand_count = 1, length = 4, ops = {op_imm(imm, 1), {}, {}, {}}} }
|
||||
@@ -953,6 +961,8 @@ inst_sdot_r_r_r :: #force_inline proc "contextless" (dst: Regist
|
||||
emit_sdot_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_sdot_r_r_r(dst, src, src2)) }
|
||||
inst_udot_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .UDOT, operand_count = 3, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_udot_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_udot_r_r_r(dst, src, src2)) }
|
||||
inst_usdot_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .USDOT, operand_count = 3, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_usdot_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_usdot_r_r_r(dst, src, src2)) }
|
||||
inst_fadd_v_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .FADD_V, operand_count = 3, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_2s(u8(reg_hw(src))), op_v_2s(u8(reg_hw(src2))), {}}} }
|
||||
emit_fadd_v_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_fadd_v_r_r_r(dst, src, src2)) }
|
||||
inst_fsub_v_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .FSUB_V, operand_count = 3, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_2s(u8(reg_hw(src))), op_v_2s(u8(reg_hw(src2))), {}}} }
|
||||
@@ -2142,8 +2152,12 @@ inst_csneg :: inst_csneg_r_r_r_c
|
||||
emit_csneg :: emit_csneg_r_r_r_c
|
||||
inst_ccmp_reg :: inst_ccmp_reg_r_r_i_c
|
||||
emit_ccmp_reg :: emit_ccmp_reg_r_r_i_c
|
||||
inst_ccmp_imm :: inst_ccmp_imm_r_i_i_c
|
||||
emit_ccmp_imm :: emit_ccmp_imm_r_i_i_c
|
||||
inst_ccmn_reg :: inst_ccmn_reg_r_r_i_c
|
||||
emit_ccmn_reg :: emit_ccmn_reg_r_r_i_c
|
||||
inst_ccmn_imm :: inst_ccmn_imm_r_i_i_c
|
||||
emit_ccmn_imm :: emit_ccmn_imm_r_i_i_c
|
||||
inst_extr :: inst_extr_r_r_r_i
|
||||
emit_extr :: emit_extr_r_r_r_i
|
||||
inst_b :: inst_b_l
|
||||
@@ -2224,8 +2238,12 @@ inst_sev :: inst_sev_none
|
||||
emit_sev :: emit_sev_none
|
||||
inst_sevl :: inst_sevl_none
|
||||
emit_sevl :: emit_sevl_none
|
||||
inst_hint :: inst_hint_i
|
||||
emit_hint :: emit_hint_i
|
||||
inst_mrs :: inst_mrs_r_i
|
||||
emit_mrs :: emit_mrs_r_i
|
||||
inst_msr_imm :: inst_msr_imm_i_i
|
||||
emit_msr_imm :: emit_msr_imm_i_i
|
||||
inst_msr_reg :: inst_msr_reg_i_r
|
||||
emit_msr_reg :: emit_msr_reg_i_r
|
||||
inst_isb :: inst_isb_i
|
||||
@@ -2972,6 +2990,8 @@ inst_sdot :: inst_sdot_r_r_r
|
||||
emit_sdot :: emit_sdot_r_r_r
|
||||
inst_udot :: inst_udot_r_r_r
|
||||
emit_udot :: emit_udot_r_r_r
|
||||
inst_usdot :: inst_usdot_r_r_r
|
||||
emit_usdot :: emit_usdot_r_r_r
|
||||
inst_fadd_v :: inst_fadd_v_r_r_r
|
||||
emit_fadd_v :: emit_fadd_v_r_r_r
|
||||
inst_fsub_v :: inst_fsub_v_r_r_r
|
||||
|
||||
@@ -300,6 +300,24 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{
|
||||
{.CCMN_REG, {.W_REG, .W_REG, .NZCV_IMM, .COND}, {.RN, .RM, .NZCV_FIELD, .COND_HI}, 0x3A400000, 0xFFE00C10, .BASE, {sets_flags=true}},
|
||||
{.CCMN_REG, {.X_REG, .X_REG, .NZCV_IMM, .COND}, {.RN, .RM, .NZCV_FIELD, .COND_HI}, 0xBA400000, 0xFFE00C10, .BASE, {sets_flags=true, is_64=true}},
|
||||
},
|
||||
// Conditional compare (immediate): imm5 at 20:16 replaces Rm; bit 11 = 1.
|
||||
.CCMP_IMM = {
|
||||
{.CCMP_IMM, {.W_REG, .IMM_5, .NZCV_IMM, .COND}, {.RN, .IMM5_HI, .NZCV_FIELD, .COND_HI}, 0x7A400800, 0xFFE00C10, .BASE, {sets_flags=true}},
|
||||
{.CCMP_IMM, {.X_REG, .IMM_5, .NZCV_IMM, .COND}, {.RN, .IMM5_HI, .NZCV_FIELD, .COND_HI}, 0xFA400800, 0xFFE00C10, .BASE, {sets_flags=true, is_64=true}},
|
||||
},
|
||||
.CCMN_IMM = {
|
||||
{.CCMN_IMM, {.W_REG, .IMM_5, .NZCV_IMM, .COND}, {.RN, .IMM5_HI, .NZCV_FIELD, .COND_HI}, 0x3A400800, 0xFFE00C10, .BASE, {sets_flags=true}},
|
||||
{.CCMN_IMM, {.X_REG, .IMM_5, .NZCV_IMM, .COND}, {.RN, .IMM5_HI, .NZCV_FIELD, .COND_HI}, 0xBA400800, 0xFFE00C10, .BASE, {sets_flags=true, is_64=true}},
|
||||
},
|
||||
// HINT #imm7 (imm at 11:5); NOP/YIELD/etc. are specific values of this.
|
||||
.HINT = { {.HINT, {.IMM_8, .NONE, .NONE, .NONE}, {.HINT_FIELD, .NONE, .NONE, .NONE}, 0xD503201F, 0xFFFFF01F, .BASE, {}} },
|
||||
// MSR <pstatefield>, #imm: op1:op2 selector (combined) + CRm immediate.
|
||||
.MSR_IMM = { {.MSR_IMM, {.SYS_REG, .IMM_4, .NONE, .NONE}, {.MSR_PSTATE, .BARRIER_FIELD, .NONE, .NONE}, 0xD500401F, 0xFFF8F01F, .BASE, {}} },
|
||||
// USDOT (unsigned-by-signed dot product, I8MM): Vd.<2S|4S>, Vn.<8B|16B>, Vm.<8B|16B>.
|
||||
.USDOT = {
|
||||
{.USDOT, {.V_2S, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E809C00, 0xFFE0FC00, .DOT, {}},
|
||||
{.USDOT, {.V_4S, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E809C00, 0xFFE0FC00, .DOT, {}},
|
||||
},
|
||||
|
||||
// =========================================================================
|
||||
// §8 Branches
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user