mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-05 03:30:21 +00:00
rexcode/arm32: MVE VHCADD (saturating halving complex add) + VCMLA
New MVE_ROT_HCADD (#90/#270 at bit12) and MVE_ROT_CMLA (#0/90/180/270 at bits 24:23) rotation encodings -- the rotation degrees round-trip properly (unlike the existing FCMA VCMLA which leaves it unencoded). One form each with the element-size bits left variable (MVE convention). Verify round-trips; all rotations byte-exact vs llvm-mc; 600 tests green. (VMLSV/VMLSVA reduce ops deferred: their format decode-collides with other MVE encodings given the 4-bit VN_Q vs MVE's 3-bit Qn.)
This commit is contained in:
@@ -352,6 +352,10 @@ unpack_operand :: proc(word: u32, enc: Operand_Encoding, ot: Operand_Type) -> Op
|
||||
lane = (word >> 21) & 1
|
||||
}
|
||||
return op_dpr_lane(Register(REG_DPR | u16(n)), u8(lane))
|
||||
case .MVE_ROT_HCADD:
|
||||
return op_imm(((word >> 12) & 1) == 1 ? 270 : 90)
|
||||
case .MVE_ROT_CMLA:
|
||||
return op_imm(i64((word >> 23) & 0x3) * 90)
|
||||
case .VD_Q:
|
||||
n := (((word >> 22) & 1) << 4 | ((word >> 12) & 0xF)) >> 1
|
||||
return op_reg(Register(REG_QPR | u16(n)))
|
||||
|
||||
@@ -436,6 +436,10 @@ pack_operand_inline :: #force_inline proc(
|
||||
v |= (l & 1) << 21
|
||||
}
|
||||
return v
|
||||
case .MVE_ROT_HCADD:
|
||||
return (u32(op.immediate) == 270 ? 1 : 0) << 12
|
||||
case .MVE_ROT_CMLA:
|
||||
return ((u32(op.immediate) / 90) & 0x3) << 23
|
||||
case .VFP_IMM8:
|
||||
// Run the VFP 8-bit float encoder; the user supplies the wire-format
|
||||
// 32-bit float bit pattern (for F32). The encoder finds the abcdefgh.
|
||||
|
||||
@@ -312,6 +312,10 @@ Operand_Encoding :: enum u8 {
|
||||
VMOV_LANE_8,
|
||||
VMOV_LANE_16,
|
||||
VMOV_LANE_32,
|
||||
// MVE complex-op rotation immediate (user passes degrees):
|
||||
// MVE_ROT_HCADD: #90/#270 -> bit 12; MVE_ROT_CMLA: #0/90/180/270 -> bits 24:23
|
||||
MVE_ROT_HCADD,
|
||||
MVE_ROT_CMLA,
|
||||
VFP_IMM8, // VFP immediate (VMOV.F32/F64 #imm)
|
||||
NEON_IMM8_ABCDEFGH, // bits 18-16 (abc) + bits 3-0 (defgh)
|
||||
NEON_CMODE, // bits 11-8 (cmode for VMOV/VMVN immediate)
|
||||
|
||||
@@ -1388,6 +1388,10 @@ inst_vqrdmlsdh_q_q_q :: #force_inline proc "contextless" (dst: Regis
|
||||
emit_vqrdmlsdh_q_q_q :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_vqrdmlsdh_q_q_q(dst, src, src2)) }
|
||||
inst_vqrdmlsdhx_q_q_q :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .VQRDMLSDHX, operand_count = 3, mode = .T32, cond = 14, length = 4, ops = {op_reg(dst), op_reg(src), op_reg(src2), {}}} }
|
||||
emit_vqrdmlsdhx_q_q_q :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_vqrdmlsdhx_q_q_q(dst, src, src2)) }
|
||||
inst_vhcadd_sat_q_q_q_imm :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register, imm: i64) -> Instruction { return Instruction{mnemonic = .VHCADD_SAT, operand_count = 4, mode = .T32, cond = 14, length = 4, ops = {op_reg(dst), op_reg(src), op_reg(src2), op_imm(imm)}} }
|
||||
emit_vhcadd_sat_q_q_q_imm :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register, imm: i64) { append(instructions, inst_vhcadd_sat_q_q_q_imm(dst, src, src2, imm)) }
|
||||
inst_vcmla_mve_q_q_q_imm :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register, imm: i64) -> Instruction { return Instruction{mnemonic = .VCMLA_MVE, operand_count = 4, mode = .T32, cond = 14, length = 4, ops = {op_reg(dst), op_reg(src), op_reg(src2), op_imm(imm)}} }
|
||||
emit_vcmla_mve_q_q_q_imm :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register, imm: i64) { append(instructions, inst_vcmla_mve_q_q_q_imm(dst, src, src2, imm)) }
|
||||
inst_vldrb_q_mem :: #force_inline proc "contextless" (dst: Register, src: Memory) -> Instruction { return Instruction{mnemonic = .VLDRB, operand_count = 2, mode = .T32, cond = 14, length = 4, ops = {op_reg(dst), op_mem(src), {}, {}}} }
|
||||
emit_vldrb_q_mem :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Memory) { append(instructions, inst_vldrb_q_mem(dst, src)) }
|
||||
inst_vldrh_q_mem :: #force_inline proc "contextless" (dst: Register, src: Memory) -> Instruction { return Instruction{mnemonic = .VLDRH, operand_count = 2, mode = .T32, cond = 14, length = 4, ops = {op_reg(dst), op_mem(src), {}, {}}} }
|
||||
@@ -2637,6 +2641,10 @@ inst_vqrdmlsdh :: inst_vqrdmlsdh_q_q_q
|
||||
emit_vqrdmlsdh :: emit_vqrdmlsdh_q_q_q
|
||||
inst_vqrdmlsdhx :: inst_vqrdmlsdhx_q_q_q
|
||||
emit_vqrdmlsdhx :: emit_vqrdmlsdhx_q_q_q
|
||||
inst_vhcadd_sat :: inst_vhcadd_sat_q_q_q_imm
|
||||
emit_vhcadd_sat :: emit_vhcadd_sat_q_q_q_imm
|
||||
inst_vcmla_mve :: inst_vcmla_mve_q_q_q_imm
|
||||
emit_vcmla_mve :: emit_vcmla_mve_q_q_q_imm
|
||||
inst_vldrb :: inst_vldrb_q_mem
|
||||
emit_vldrb :: emit_vldrb_q_mem
|
||||
inst_vldrh :: inst_vldrh_q_mem
|
||||
|
||||
@@ -3688,6 +3688,14 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{
|
||||
{.VMOV_LANE, {.DPR_ELEM, .GPR, .NONE, .NONE}, {.VMOV_LANE_32, .RT_A32, .NONE, .NONE}, 0x0E000B10, 0x0FD00F7F, .VFPV2, .A32, {}},
|
||||
},
|
||||
|
||||
// MVE (M-profile vector) multiply-subtract-across-vector reduce, halving
|
||||
// complex add (saturating), and complex multiply-accumulate. T32; the
|
||||
// complex ops carry a rotation immediate (degrees).
|
||||
// One form per mnemonic with the element-size bits left variable in the
|
||||
// mask (the MVE convention); the complex ops encode the rotation immediate.
|
||||
.VHCADD_SAT = { {.VHCADD_SAT, {.QPR, .QPR, .QPR, .IMM}, {.VD_Q, .VN_Q, .VM_Q, .MVE_ROT_HCADD}, 0xEE000F00, 0xFFE10FF1, .MVE_INT, .T32, {thumb32=true, cond_in_28=false}} },
|
||||
.VCMLA_MVE = { {.VCMLA_MVE, {.QPR, .QPR, .QPR, .IMM}, {.VD_Q, .VN_Q, .VM_Q, .MVE_ROT_CMLA}, 0xFC200840, 0xFE611FF1, .MVE_FP, .T32, {thumb32=true, cond_in_28=false}} },
|
||||
|
||||
// SPECGEN:BEGIN
|
||||
.VADDL = {
|
||||
{.VADDL, {.QPR, .DPR, .DPR, .NONE}, {.VD_Q, .VN_D, .VM_D, .NONE}, 0xF2800000, 0xFFB01F50, .NEON, .A32, {cond_in_28=false}},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ package rexcode_arm32_generated
|
||||
import lib "../.."
|
||||
|
||||
@(rodata)
|
||||
ENCODE_FORMS := [1671]lib.Encoding{
|
||||
ENCODE_FORMS := [1673]lib.Encoding{
|
||||
// .AND
|
||||
{ .AND, {.GPR,.GPR,.IMM_MOD,.NONE}, {.RD,.RN_A32,.A32_IMM_MOD,.NONE}, 0x02000000, 0x0FE00000, .BASE, .A32, {} },
|
||||
{ .AND, {.GPR,.GPR,.GPR_SHIFTED,.NONE}, {.RD,.RN_A32,.RM_A32,.NONE}, 0x00000000, 0x0FE00010, .BASE, .A32, {} },
|
||||
@@ -2262,6 +2262,10 @@ ENCODE_FORMS := [1671]lib.Encoding{
|
||||
{ .VQRDMLSDH, {.QPR,.QPR,.QPR,.NONE}, {.VD_Q,.VN_Q,.VM_Q,.NONE}, 0xFE000E01, 0xFF811F51, .MVE_INT, .T32, {thumb32=true} },
|
||||
// .VQRDMLSDHX
|
||||
{ .VQRDMLSDHX, {.QPR,.QPR,.QPR,.NONE}, {.VD_Q,.VN_Q,.VM_Q,.NONE}, 0xFE001E01, 0xFF811F51, .MVE_INT, .T32, {thumb32=true} },
|
||||
// .VHCADD_SAT
|
||||
{ .VHCADD_SAT, {.QPR,.QPR,.QPR,.IMM}, {.VD_Q,.VN_Q,.VM_Q,.MVE_ROT_HCADD}, 0xEE000F00, 0xFFE10FF1, .MVE_INT, .T32, {thumb32=true} },
|
||||
// .VCMLA_MVE
|
||||
{ .VCMLA_MVE, {.QPR,.QPR,.QPR,.IMM}, {.VD_Q,.VN_Q,.VM_Q,.MVE_ROT_CMLA}, 0xFC200840, 0xFE611FF1, .MVE_FP, .T32, {thumb32=true} },
|
||||
// .VLDRB
|
||||
{ .VLDRB, {.QPR,.MEM,.NONE,.NONE}, {.VD_Q,.MEM_IMM12_OFFSET,.NONE,.NONE}, 0xED901E00, 0xFFB01F00, .MVE_INT, .T32, {thumb32=true} },
|
||||
// .VLDRH
|
||||
@@ -2918,27 +2922,27 @@ ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{
|
||||
.VQRDMLSDH = { 1649, 1},
|
||||
.VQRDMLSDHX = { 1650, 1},
|
||||
.VPRINT = { 1651, 0},
|
||||
.VHCADD_SAT = { 1651, 0},
|
||||
.VCMLA_MVE = { 1651, 0},
|
||||
.VLDRB = { 1651, 1},
|
||||
.VLDRH = { 1652, 1},
|
||||
.VLDRW = { 1653, 1},
|
||||
.VLDRD = { 1654, 1},
|
||||
.VSTRB = { 1655, 1},
|
||||
.VSTRH = { 1656, 1},
|
||||
.VSTRW = { 1657, 1},
|
||||
.VSTRD = { 1658, 1},
|
||||
.VLD20 = { 1659, 1},
|
||||
.VLD21 = { 1660, 1},
|
||||
.VLD40 = { 1661, 1},
|
||||
.VLD41 = { 1662, 1},
|
||||
.VLD42 = { 1663, 1},
|
||||
.VLD43 = { 1664, 1},
|
||||
.VST20 = { 1665, 1},
|
||||
.VST21 = { 1666, 1},
|
||||
.VST40 = { 1667, 1},
|
||||
.VST41 = { 1668, 1},
|
||||
.VST42 = { 1669, 1},
|
||||
.VST43 = { 1670, 1},
|
||||
._COUNT = { 1671, 0},
|
||||
.VHCADD_SAT = { 1651, 1},
|
||||
.VCMLA_MVE = { 1652, 1},
|
||||
.VLDRB = { 1653, 1},
|
||||
.VLDRH = { 1654, 1},
|
||||
.VLDRW = { 1655, 1},
|
||||
.VLDRD = { 1656, 1},
|
||||
.VSTRB = { 1657, 1},
|
||||
.VSTRH = { 1658, 1},
|
||||
.VSTRW = { 1659, 1},
|
||||
.VSTRD = { 1660, 1},
|
||||
.VLD20 = { 1661, 1},
|
||||
.VLD21 = { 1662, 1},
|
||||
.VLD40 = { 1663, 1},
|
||||
.VLD41 = { 1664, 1},
|
||||
.VLD42 = { 1665, 1},
|
||||
.VLD43 = { 1666, 1},
|
||||
.VST20 = { 1667, 1},
|
||||
.VST21 = { 1668, 1},
|
||||
.VST40 = { 1669, 1},
|
||||
.VST41 = { 1670, 1},
|
||||
.VST42 = { 1671, 1},
|
||||
.VST43 = { 1672, 1},
|
||||
._COUNT = { 1673, 0},
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user