mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-18 21:51:08 +00:00
rexcode/arm64: NEON permute, compare-zero, SXTL/UXTL encode forms
ZIP1/2, UZP1/2, TRN1/2 (three-same permute); CMLE/CMLT and FP FCMLE/FCMLT (compare against zero, with the literal #0 / #0.0 operand); SXTL/SXTL2/UXTL/UXTL2 (= SSHLL/USHLL #0, plain 2-register widen, shift implicit in the static bits). All reuse the VD/VN/VM register slots, so no encoder change. specgen gains an emit_cmp0 shape plus permute and widen families. All forms byte-exact vs llvm-mc; 461 tests green.
This commit is contained in:
@@ -1033,6 +1033,10 @@ inst_fcmge_r_r_r :: #force_inline proc "contextless" (dst: Regist
|
||||
emit_fcmge_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_fcmge_r_r_r(dst, src, src2)) }
|
||||
inst_fcmgt_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .FCMGT, 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_fcmgt_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_fcmgt_r_r_r(dst, src, src2)) }
|
||||
inst_fcmle_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .FCMLE, operand_count = 2, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_2s(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_fcmle_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_fcmle_r_r(dst, src)) }
|
||||
inst_fcmlt_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .FCMLT, operand_count = 2, length = 4, ops = {op_v_2s(u8(reg_hw(dst))), op_v_2s(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_fcmlt_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_fcmlt_r_r(dst, src)) }
|
||||
inst_facge_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .FACGE, 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_facge_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_facge_r_r_r(dst, src, src2)) }
|
||||
inst_facgt_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .FACGT, 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))), {}}} }
|
||||
@@ -1047,6 +1051,10 @@ inst_cmhi_r_r_r :: #force_inline proc "contextless" (dst: Regist
|
||||
emit_cmhi_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_cmhi_r_r_r(dst, src, src2)) }
|
||||
inst_cmhs_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .CMHS, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_cmhs_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_cmhs_r_r_r(dst, src, src2)) }
|
||||
inst_cmle_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .CMLE, operand_count = 2, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_cmle_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_cmle_r_r(dst, src)) }
|
||||
inst_cmlt_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .CMLT, operand_count = 2, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_cmlt_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_cmlt_r_r(dst, src)) }
|
||||
inst_cmtst_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .CMTST, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_cmtst_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_cmtst_r_r_r(dst, src, src2)) }
|
||||
inst_and_v_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .AND_V, operand_count = 3, length = 4, ops = {op_v_16b(u8(reg_hw(dst))), op_v_16b(u8(reg_hw(src))), op_v_16b(u8(reg_hw(src2))), {}}} }
|
||||
@@ -1107,6 +1115,26 @@ inst_ushll_r_r_i :: #force_inline proc "contextless" (dst: Regist
|
||||
emit_ushll_r_r_i :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, imm: i64) { append(instructions, inst_ushll_r_r_i(dst, src, imm)) }
|
||||
inst_ushll2_r_r_i :: #force_inline proc "contextless" (dst: Register, src: Register, imm: i64) -> Instruction { return Instruction{mnemonic = .USHLL2, operand_count = 3, length = 4, ops = {op_v_8h(u8(reg_hw(dst))), op_v_16b(u8(reg_hw(src))), op_imm(imm, 4), {}}} }
|
||||
emit_ushll2_r_r_i :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, imm: i64) { append(instructions, inst_ushll2_r_r_i(dst, src, imm)) }
|
||||
inst_sxtl_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .SXTL, operand_count = 2, length = 4, ops = {op_v_8h(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_sxtl_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_sxtl_r_r(dst, src)) }
|
||||
inst_sxtl2_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .SXTL2, operand_count = 2, length = 4, ops = {op_v_8h(u8(reg_hw(dst))), op_v_16b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_sxtl2_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_sxtl2_r_r(dst, src)) }
|
||||
inst_uxtl_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .UXTL, operand_count = 2, length = 4, ops = {op_v_8h(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_uxtl_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_uxtl_r_r(dst, src)) }
|
||||
inst_uxtl2_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .UXTL2, operand_count = 2, length = 4, ops = {op_v_8h(u8(reg_hw(dst))), op_v_16b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_uxtl2_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_uxtl2_r_r(dst, src)) }
|
||||
inst_zip1_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .ZIP1, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_zip1_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_zip1_r_r_r(dst, src, src2)) }
|
||||
inst_zip2_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .ZIP2, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_zip2_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_zip2_r_r_r(dst, src, src2)) }
|
||||
inst_uzp1_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .UZP1, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_uzp1_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_uzp1_r_r_r(dst, src, src2)) }
|
||||
inst_uzp2_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .UZP2, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_uzp2_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_uzp2_r_r_r(dst, src, src2)) }
|
||||
inst_trn1_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .TRN1, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_trn1_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_trn1_r_r_r(dst, src, src2)) }
|
||||
inst_trn2_r_r_r :: #force_inline proc "contextless" (dst: Register, src: Register, src2: Register) -> Instruction { return Instruction{mnemonic = .TRN2, operand_count = 3, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), op_v_8b(u8(reg_hw(src2))), {}}} }
|
||||
emit_trn2_r_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register, src2: Register) { append(instructions, inst_trn2_r_r_r(dst, src, src2)) }
|
||||
inst_not_v_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .NOT_V, operand_count = 2, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
emit_not_v_r_r :: #force_inline proc(instructions: ^[dynamic]Instruction, dst: Register, src: Register) { append(instructions, inst_not_v_r_r(dst, src)) }
|
||||
inst_rbit_v_r_r :: #force_inline proc "contextless" (dst: Register, src: Register) -> Instruction { return Instruction{mnemonic = .RBIT_V, operand_count = 2, length = 4, ops = {op_v_8b(u8(reg_hw(dst))), op_v_8b(u8(reg_hw(src))), {}, {}}} }
|
||||
@@ -2946,6 +2974,10 @@ inst_fcmge :: inst_fcmge_r_r_r
|
||||
emit_fcmge :: emit_fcmge_r_r_r
|
||||
inst_fcmgt :: inst_fcmgt_r_r_r
|
||||
emit_fcmgt :: emit_fcmgt_r_r_r
|
||||
inst_fcmle :: inst_fcmle_r_r
|
||||
emit_fcmle :: emit_fcmle_r_r
|
||||
inst_fcmlt :: inst_fcmlt_r_r
|
||||
emit_fcmlt :: emit_fcmlt_r_r
|
||||
inst_facge :: inst_facge_r_r_r
|
||||
emit_facge :: emit_facge_r_r_r
|
||||
inst_facgt :: inst_facgt_r_r_r
|
||||
@@ -2960,6 +2992,10 @@ inst_cmhi :: inst_cmhi_r_r_r
|
||||
emit_cmhi :: emit_cmhi_r_r_r
|
||||
inst_cmhs :: inst_cmhs_r_r_r
|
||||
emit_cmhs :: emit_cmhs_r_r_r
|
||||
inst_cmle :: inst_cmle_r_r
|
||||
emit_cmle :: emit_cmle_r_r
|
||||
inst_cmlt :: inst_cmlt_r_r
|
||||
emit_cmlt :: emit_cmlt_r_r
|
||||
inst_cmtst :: inst_cmtst_r_r_r
|
||||
emit_cmtst :: emit_cmtst_r_r_r
|
||||
inst_and_v :: inst_and_v_r_r_r
|
||||
@@ -3020,6 +3056,26 @@ inst_ushll :: inst_ushll_r_r_i
|
||||
emit_ushll :: emit_ushll_r_r_i
|
||||
inst_ushll2 :: inst_ushll2_r_r_i
|
||||
emit_ushll2 :: emit_ushll2_r_r_i
|
||||
inst_sxtl :: inst_sxtl_r_r
|
||||
emit_sxtl :: emit_sxtl_r_r
|
||||
inst_sxtl2 :: inst_sxtl2_r_r
|
||||
emit_sxtl2 :: emit_sxtl2_r_r
|
||||
inst_uxtl :: inst_uxtl_r_r
|
||||
emit_uxtl :: emit_uxtl_r_r
|
||||
inst_uxtl2 :: inst_uxtl2_r_r
|
||||
emit_uxtl2 :: emit_uxtl2_r_r
|
||||
inst_zip1 :: inst_zip1_r_r_r
|
||||
emit_zip1 :: emit_zip1_r_r_r
|
||||
inst_zip2 :: inst_zip2_r_r_r
|
||||
emit_zip2 :: emit_zip2_r_r_r
|
||||
inst_uzp1 :: inst_uzp1_r_r_r
|
||||
emit_uzp1 :: emit_uzp1_r_r_r
|
||||
inst_uzp2 :: inst_uzp2_r_r_r
|
||||
emit_uzp2 :: emit_uzp2_r_r_r
|
||||
inst_trn1 :: inst_trn1_r_r_r
|
||||
emit_trn1 :: emit_trn1_r_r_r
|
||||
inst_trn2 :: inst_trn2_r_r_r
|
||||
emit_trn2 :: emit_trn2_r_r_r
|
||||
inst_not_v :: inst_not_v_r_r
|
||||
emit_not_v :: emit_not_v_r_r
|
||||
inst_rbit_v :: inst_rbit_v_r_r
|
||||
|
||||
@@ -3260,6 +3260,62 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{
|
||||
{.URSHL, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x6EE05400, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD permute (ZIP/UZP/TRN).
|
||||
.ZIP1 = {
|
||||
{.ZIP1, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E003800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E003800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E403800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E403800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E803800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E803800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP1, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC03800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
.ZIP2 = {
|
||||
{.ZIP2, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E007800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E007800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E407800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E407800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E807800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E807800, 0xFFE0FC00, .NEON, {}},
|
||||
{.ZIP2, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC07800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
.UZP1 = {
|
||||
{.UZP1, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E001800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E001800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E401800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E401800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E801800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E801800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP1, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC01800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
.UZP2 = {
|
||||
{.UZP2, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E005800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E005800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E405800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E405800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E805800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E805800, 0xFFE0FC00, .NEON, {}},
|
||||
{.UZP2, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC05800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
.TRN1 = {
|
||||
{.TRN1, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E002800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E002800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E402800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E402800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E802800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E802800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN1, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC02800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
.TRN2 = {
|
||||
{.TRN2, {.V_8B, .V_8B, .V_8B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E006800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_16B, .V_16B, .V_16B, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E006800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_4H, .V_4H, .V_4H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E406800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_8H, .V_8H, .V_8H, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E406800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_2S, .V_2S, .V_2S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x0E806800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_4S, .V_4S, .V_4S, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4E806800, 0xFFE0FC00, .NEON, {}},
|
||||
{.TRN2, {.V_2D, .V_2D, .V_2D, .NONE}, {.VD, .VN, .VM, .NONE}, 0x4EC06800, 0xFFE0FC00, .NEON, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD two-register misc.
|
||||
.ABS_V = {
|
||||
{.ABS_V, {.V_8B, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0E20B800, 0xFFFFFC00, .NEON, {}},
|
||||
@@ -3879,6 +3935,28 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{
|
||||
{.SQXTUN2, {.V_4S, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EA12800, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD two-register widen (SXTL/UXTL = SSHLL/USHLL #0).
|
||||
.SXTL = {
|
||||
{.SXTL, {.V_8H, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0F08A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.SXTL, {.V_4S, .V_4H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0F10A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.SXTL, {.V_2D, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0F20A400, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
.SXTL2 = {
|
||||
{.SXTL2, {.V_8H, .V_16B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4F08A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.SXTL2, {.V_4S, .V_8H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4F10A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.SXTL2, {.V_2D, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4F20A400, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
.UXTL = {
|
||||
{.UXTL, {.V_8H, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2F08A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.UXTL, {.V_4S, .V_4H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2F10A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.UXTL, {.V_2D, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2F20A400, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
.UXTL2 = {
|
||||
{.UXTL2, {.V_8H, .V_16B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6F08A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.UXTL2, {.V_4S, .V_8H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6F10A400, 0xFFFFFC00, .NEON, {}},
|
||||
{.UXTL2, {.V_2D, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6F20A400, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD two-register pairwise long.
|
||||
.SADDLP = {
|
||||
{.SADDLP, {.V_4H, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0E202800, 0xFFFFFC00, .NEON, {}},
|
||||
@@ -4010,6 +4088,40 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{
|
||||
{.FCVTXN2, {.V_4S, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6E616800, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD compare against zero.
|
||||
.CMLE = {
|
||||
{.CMLE, {.V_8B, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2E209800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_16B, .V_16B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6E209800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_4H, .V_4H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2E609800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_8H, .V_8H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6E609800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_2S, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2EA09800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_4S, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EA09800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLE, {.V_2D, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EE09800, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
.CMLT = {
|
||||
{.CMLT, {.V_8B, .V_8B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0E20A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_16B, .V_16B, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4E20A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_4H, .V_4H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0E60A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_8H, .V_8H, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4E60A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_2S, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0EA0A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_4S, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4EA0A800, 0xFFFFFC00, .NEON, {}},
|
||||
{.CMLT, {.V_2D, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4EE0A800, 0xFFFFFC00, .NEON, {}},
|
||||
},
|
||||
.FCMLE = {
|
||||
{.FCMLE, {.V_2S, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2EA0D800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLE, {.V_4S, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EA0D800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLE, {.V_2D, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EE0D800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLE, {.V_4H_FP16, .V_4H_FP16, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x2EF8D800, 0xFFFFFC00, .FP16, {}},
|
||||
{.FCMLE, {.V_8H_FP16, .V_8H_FP16, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x6EF8D800, 0xFFFFFC00, .FP16, {}},
|
||||
},
|
||||
.FCMLT = {
|
||||
{.FCMLT, {.V_2S, .V_2S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0EA0E800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLT, {.V_4S, .V_4S, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4EA0E800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLT, {.V_2D, .V_2D, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4EE0E800, 0xFFFFFC00, .NEON, {}},
|
||||
{.FCMLT, {.V_4H_FP16, .V_4H_FP16, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x0EF8E800, 0xFFFFFC00, .FP16, {}},
|
||||
{.FCMLT, {.V_8H_FP16, .V_8H_FP16, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x4EF8E800, 0xFFFFFC00, .FP16, {}},
|
||||
},
|
||||
|
||||
// Advanced SIMD shift by immediate.
|
||||
.SHL_V = {
|
||||
{.SHL_V, {.V_8B, .V_8B, .VEC_SHIFT, .NONE}, {.VD, .VN, .NEON_SHL_IMM, .NONE}, 0x0F085400, 0xFFF8FC00, .NEON, {}},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -84,6 +84,31 @@ local function emit(mnem, llvm, enc_str, feature, variants)
|
||||
return string.format("\t.%s = {\n%s\n\t},", mnem, table.concat(rows, "\n"))
|
||||
end
|
||||
|
||||
-- Compare-against-zero: a 2-register shape whose asm carries a literal #0
|
||||
-- (integer) or #0.0 (FP) third operand that emits no bits. Modeled with two
|
||||
-- register operands (VD, VN); mask derived by varying the registers only.
|
||||
local function emit_cmp0(mnem, llvm, fp, arr)
|
||||
local rows = {}
|
||||
local suf = fp and ", #0.0" or ", #0"
|
||||
for _, a in ipairs(arr) do
|
||||
local function mk(r) return string.format("%s v%d.%s, v%d.%s%s", llvm, r, ARR[a].asm, r, ARR[a].asm, suf) end
|
||||
local w0, w31 = word(mk(0)), word(mk(31))
|
||||
if w0 and w31 then
|
||||
local mask = bit.band(bit.bnot(bit.bxor(w0, w31)), 0xFFFFFFFF)
|
||||
local f = ARR[a].feat or "NEON"
|
||||
rows[#rows+1] = string.format(
|
||||
"\t\t{.%s, {.%s, .%s, .NONE, .NONE}, {.VD, .VN, .NONE, .NONE}, 0x%s, 0x%s, .%s, {}},",
|
||||
mnem, ARR[a].vt, ARR[a].vt, bit.tohex(w0):upper(), bit.tohex(mask):upper(), f)
|
||||
n_forms = n_forms + 1
|
||||
else
|
||||
skips[#skips+1] = mnem.." "..a
|
||||
end
|
||||
end
|
||||
if #rows == 0 then return nil end
|
||||
n_mnem = n_mnem + 1
|
||||
return string.format("\t.%s = {\n%s\n\t},", mnem, table.concat(rows, "\n"))
|
||||
end
|
||||
|
||||
-- ---- Uniform shapes (all operands share one arrangement) -------------------
|
||||
local VD_VN_VM = padded({".VD",".VN",".VM"}, 3)
|
||||
local VD_VN = padded({".VD",".VN"}, 2)
|
||||
@@ -101,6 +126,9 @@ local UNIFORM = {
|
||||
{"ADDP_V","addp"},{"SMAXP","smaxp"},{"SMINP","sminp"},{"UMAXP","umaxp"},{"UMINP","uminp"},
|
||||
{"SSHL","sshl"},{"USHL","ushl"},{"SRSHL","srshl"},{"URSHL","urshl"},
|
||||
}},
|
||||
{ title="permute (ZIP/UZP/TRN)", enc=VD_VN_VM, nreg=3, items={
|
||||
{"ZIP1","zip1"},{"ZIP2","zip2"},{"UZP1","uzp1"},{"UZP2","uzp2"},{"TRN1","trn1"},{"TRN2","trn2"},
|
||||
}},
|
||||
{ title="two-register misc", enc=VD_VN, nreg=2, items={
|
||||
{"ABS_V","abs"},{"NEG_V","neg"},
|
||||
{"NOT_V","not"},{"RBIT_V","rbit"},
|
||||
@@ -168,6 +196,10 @@ local FCVTN_LO = {{"4HF","4S"},{"2S","2D"}}
|
||||
local FCVTN_HI = {{"8HF","4S"},{"4S","2D"}}
|
||||
local FCVTXN_LO = {{"2S","2D"}}
|
||||
local FCVTXN_HI = {{"4S","2D"}}
|
||||
-- SXTL/UXTL widen (= SSHLL/USHLL #0): Vd.<wide>, Vn.<narrow>; shift is implicit
|
||||
-- in the static bits, so this is a plain 2-register form (no shift operand).
|
||||
local SXTL_LO = {{"8H","8B"},{"4S","4H"},{"2D","2S"}}
|
||||
local SXTL_HI = {{"8H","16B"},{"4S","8H"},{"2D","4S"}}
|
||||
|
||||
local DIFF = {
|
||||
{ title="three-different (long)", enc=VD_VN_VM, items={
|
||||
@@ -203,6 +235,10 @@ local DIFF = {
|
||||
{"UQXTN","uqxtn",XTN_LO},{"UQXTN2","uqxtn2",XTN_HI},
|
||||
{"SQXTUN","sqxtun",XTN_LO},{"SQXTUN2","sqxtun2",XTN_HI},
|
||||
}},
|
||||
{ title="two-register widen (SXTL/UXTL = SSHLL/USHLL #0)", enc=VD_VN, items={
|
||||
{"SXTL","sxtl",SXTL_LO},{"SXTL2","sxtl2",SXTL_HI},
|
||||
{"UXTL","uxtl",SXTL_LO},{"UXTL2","uxtl2",SXTL_HI},
|
||||
}},
|
||||
{ title="two-register pairwise long", enc=VD_VN, items={
|
||||
{"SADDLP","saddlp",PLONG},{"UADDLP","uaddlp",PLONG},
|
||||
{"SADALP","sadalp",PLONG},{"UADALP","uadalp",PLONG},
|
||||
@@ -231,6 +267,17 @@ for _, fam in ipairs(DIFF) do
|
||||
sections[#sections+1] = "\t// Advanced SIMD "..fam.title..".\n" .. table.concat(blk, "\n")
|
||||
end
|
||||
|
||||
-- ---- Compare against zero (integer + floating-point) -----------------------
|
||||
do
|
||||
local FP_ARR = {"2S","4S","2D","4HF","8HF"}
|
||||
local blk = {}
|
||||
for _, b in ipairs({
|
||||
emit_cmp0("CMLE","cmle",false,ALL_ARR), emit_cmp0("CMLT","cmlt",false,ALL_ARR),
|
||||
emit_cmp0("FCMLE","fcmle",true,FP_ARR), emit_cmp0("FCMLT","fcmlt",true,FP_ARR),
|
||||
}) do blk[#blk+1] = b end
|
||||
sections[#sections+1] = "\t// Advanced SIMD compare against zero.\n" .. table.concat(blk, "\n")
|
||||
end
|
||||
|
||||
-- ---- NEON shift-by-immediate ----------------------------------------------
|
||||
-- <mnem> Vd.T, Vn.T, #shift. immh:immb carries element size + amount; mask is
|
||||
-- derived empirically by also varying the shift (canon = operand bits 0, other =
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user