SPU LLVM: Use TBL for AArch64 ROTQBY shuffles
This commit is contained in:
@@ -5783,6 +5783,45 @@ public:
|
|||||||
return zshuffle(std::forward<TA>(a), 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
return zshuffle(std::forward<TA>(a), 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto rotqby_reverse_base()
|
||||||
|
{
|
||||||
|
return build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto rotqby_forward_base()
|
||||||
|
{
|
||||||
|
return build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto rotqby_zero_base()
|
||||||
|
{
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
return rotqby_forward_base();
|
||||||
|
#else
|
||||||
|
return build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto rotqby_reverse_zero_base()
|
||||||
|
{
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
return rotqby_reverse_base();
|
||||||
|
#else
|
||||||
|
return build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// For use in rotqby family of instructions only
|
||||||
|
template <typename T, typename U>
|
||||||
|
auto pshufb_for_x86_and_tbl_for_aarch64(T&& a, U&& b)
|
||||||
|
{
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
|
return tbl(std::forward<T>(a), std::forward<U>(b));
|
||||||
|
#else
|
||||||
|
return pshufb(std::forward<T>(a), std::forward<U>(b));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
static llvm_calli<u8[16], T, U> rotqbybi(T&& a, U&& b)
|
static llvm_calli<u8[16], T, U> rotqbybi(T&& a, U&& b)
|
||||||
{
|
{
|
||||||
@@ -5799,7 +5838,7 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
const auto sc = rotqby_reverse_base();
|
||||||
const auto sh = sc + (splat_scalar(b) >> 3);
|
const auto sh = sc + (splat_scalar(b) >> 3);
|
||||||
|
|
||||||
if (m_use_avx512_icl)
|
if (m_use_avx512_icl)
|
||||||
@@ -5807,9 +5846,9 @@ public:
|
|||||||
return eval(vpermb(as, sh));
|
return eval(vpermb(as, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
return eval(pshufb(as, (sh & 0xf)));
|
return eval(pshufb_for_x86_and_tbl_for_aarch64(as, (sh & 0xf)));
|
||||||
}
|
}
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = sc - (splat_scalar(b) >> 3);
|
const auto sh = sc - (splat_scalar(b) >> 3);
|
||||||
|
|
||||||
if (m_use_avx512_icl)
|
if (m_use_avx512_icl)
|
||||||
@@ -5817,7 +5856,7 @@ public:
|
|||||||
return eval(vpermb(a, sh));
|
return eval(vpermb(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
return eval(pshufb(a, (sh & 0xf)));
|
return eval(pshufb_for_x86_and_tbl_for_aarch64(a, (sh & 0xf)));
|
||||||
});
|
});
|
||||||
|
|
||||||
set_vr(op.rt, rotqbybi(get_vr<u8[16]>(op.ra), get_vr<u8[16]>(op.rb)));
|
set_vr(op.rt, rotqbybi(get_vr<u8[16]>(op.ra), get_vr<u8[16]>(op.rb)));
|
||||||
@@ -5845,15 +5884,15 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
const auto sc = rotqby_reverse_base();
|
||||||
const auto sh = sc - splat_scalar(minusbx);
|
const auto sh = sc - splat_scalar(minusbx);
|
||||||
set_vr(op.rt, pshufb(as, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sc = build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
|
const auto sc = rotqby_zero_base();
|
||||||
const auto sh = sc + splat_scalar(minusbx);
|
const auto sh = sc + splat_scalar(minusbx);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHLQBYBI(spu_opcode_t op)
|
void SHLQBYBI(spu_opcode_t op)
|
||||||
@@ -5864,15 +5903,15 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112);
|
const auto sc = rotqby_reverse_zero_base();
|
||||||
const auto sh = sc + (splat_scalar(b) >> 3);
|
const auto sh = sc + (splat_scalar(b) >> 3);
|
||||||
set_vr(op.rt, pshufb(as, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = sc - (splat_scalar(b) >> 3);
|
const auto sh = sc - (splat_scalar(b) >> 3);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename RT, typename T>
|
template <typename RT, typename T>
|
||||||
@@ -6026,7 +6065,7 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
const auto sc = rotqby_reverse_base();
|
||||||
const auto sh = eval(sc + splat_scalar(b));
|
const auto sh = eval(sc + splat_scalar(b));
|
||||||
|
|
||||||
if (m_use_avx512_icl)
|
if (m_use_avx512_icl)
|
||||||
@@ -6035,11 +6074,11 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_vr(op.rt, pshufb(as, (sh & 0xf)));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, (sh & 0xf)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = eval(sc - splat_scalar(b));
|
const auto sh = eval(sc - splat_scalar(b));
|
||||||
|
|
||||||
if (m_use_avx512_icl)
|
if (m_use_avx512_icl)
|
||||||
@@ -6048,7 +6087,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_vr(op.rt, pshufb(a, (sh & 0xf)));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, (sh & 0xf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ROTQMBY(spu_opcode_t op)
|
void ROTQMBY(spu_opcode_t op)
|
||||||
@@ -6067,15 +6106,15 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
const auto sc = rotqby_reverse_base();
|
||||||
const auto sh = sc - (splat_scalar(minusbx) & 0x1f);
|
const auto sh = sc - (splat_scalar(minusbx) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(as, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sc = build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
|
const auto sc = rotqby_zero_base();
|
||||||
const auto sh = sc + (splat_scalar(minusbx) & 0x1f);
|
const auto sh = sc + (splat_scalar(minusbx) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHLQBY(spu_opcode_t op)
|
void SHLQBY(spu_opcode_t op)
|
||||||
@@ -6086,15 +6125,15 @@ public:
|
|||||||
// Data with swapped endian from a load instruction
|
// Data with swapped endian from a load instruction
|
||||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||||
{
|
{
|
||||||
const auto sc = build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112);
|
const auto sc = rotqby_reverse_zero_base();
|
||||||
const auto sh = sc + (splat_scalar(b) & 0x1f);
|
const auto sh = sc + (splat_scalar(b) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(as, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(as, sh));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = sc - (splat_scalar(b) & 0x1f);
|
const auto sh = sc - (splat_scalar(b) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -6192,26 +6231,26 @@ public:
|
|||||||
void ROTQBYI(spu_opcode_t op)
|
void ROTQBYI(spu_opcode_t op)
|
||||||
{
|
{
|
||||||
const auto a = get_vr<u8[16]>(op.ra);
|
const auto a = get_vr<u8[16]>(op.ra);
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = (sc - get_imm<u8[16]>(op.i7, false)) & 0xf;
|
const auto sh = (sc - get_imm<u8[16]>(op.i7, false)) & 0xf;
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ROTQMBYI(spu_opcode_t op)
|
void ROTQMBYI(spu_opcode_t op)
|
||||||
{
|
{
|
||||||
const auto a = get_vr<u8[16]>(op.ra);
|
const auto a = get_vr<u8[16]>(op.ra);
|
||||||
const auto sc = build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
|
const auto sc = rotqby_zero_base();
|
||||||
const auto sh = sc + (-get_imm<u8[16]>(op.i7, false) & 0x1f);
|
const auto sh = sc + (-get_imm<u8[16]>(op.i7, false) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHLQBYI(spu_opcode_t op)
|
void SHLQBYI(spu_opcode_t op)
|
||||||
{
|
{
|
||||||
if (get_reg_raw(op.ra) && !op.i7) return set_reg_fixed(op.rt, get_reg_raw(op.ra), false); // For expressions matching
|
if (get_reg_raw(op.ra) && !op.i7) return set_reg_fixed(op.rt, get_reg_raw(op.ra), false); // For expressions matching
|
||||||
const auto a = get_vr<u8[16]>(op.ra);
|
const auto a = get_vr<u8[16]>(op.ra);
|
||||||
const auto sc = build<u8[16]>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
const auto sc = rotqby_forward_base();
|
||||||
const auto sh = sc - (get_imm<u8[16]>(op.i7, false) & 0x1f);
|
const auto sh = sc - (get_imm<u8[16]>(op.i7, false) & 0x1f);
|
||||||
set_vr(op.rt, pshufb(a, sh));
|
set_vr(op.rt, pshufb_for_x86_and_tbl_for_aarch64(a, sh));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGT(spu_opcode_t op)
|
void CGT(spu_opcode_t op)
|
||||||
|
|||||||
Reference in New Issue
Block a user