SPU/PPU LLVM: Fix cpu_translator::get_const_vector<v128>()

This commit is contained in:
Eladash 2020-07-29 20:24:26 +03:00 committed by Ani
parent e52dd9dc6f
commit f6764767f6
4 changed files with 49 additions and 47 deletions

View File

@ -83,12 +83,31 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type)
}
template <>
v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32 a, u32 b)
{
v128 result{};
if (!llvm::isa<llvm::Constant>(c))
{
return {false, result};
}
const auto t = c->getType();
if (!t->isVectorTy())
{
if (const auto ci = llvm::dyn_cast<llvm::ConstantInt>(c); ci && ci->getBitWidth() == 128)
{
auto cv = ci->getValue();
for (int i = 0; i < 128; i++)
{
result._bit[i] = cv[i];
}
return {true, result};
}
fmt::throw_exception("[0x%x, %u] Not a vector" HERE, a, b);
}
@ -106,13 +125,17 @@ v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
return {};
}
if (llvm::isa<llvm::ConstantExpr>(c))
{
// Sorry, if we cannot evaluate it we cannot use it
fmt::throw_exception("[0x%x, %u] Constant Expression!" HERE, a, b);
}
fmt::throw_exception("[0x%x, %u] Unexpected constant type" HERE, a, b);
}
const auto sct = t->getScalarType();
v128 result;
if (sct->isIntegerTy(8))
{
for (u32 i = 0; i < 16; i++)
@ -160,12 +183,17 @@ v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
fmt::throw_exception("[0x%x, %u] Unexpected vector element type" HERE, a, b);
}
return result;
return {true, result};
}
template <>
llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t)
{
if (const auto ct = llvm::dyn_cast<llvm::IntegerType>(t); ct && ct->getBitWidth() == 128)
{
return llvm::ConstantInt::get(t, llvm::APInt(128, llvm::makeArrayRef(reinterpret_cast<const u64*>(v._bytes), 2)));
}
verify(HERE), t->isVectorTy() && llvm::cast<llvm::VectorType>(t)->getBitWidth() == 128;
const auto sct = t->getScalarType();

View File

@ -2837,7 +2837,7 @@ public:
}
template <typename R = v128>
R get_const_vector(llvm::Constant*, u32 a, u32 b);
std::pair<bool, R> get_const_vector(llvm::Value*, u32 a, u32 b);
template <typename T = v128>
llvm::Constant* make_const_vector(T, llvm::Type*);

View File

@ -947,10 +947,8 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
auto [a, b, c] = get_vrs<f32[4]>(op.va, op.vb, op.vc);
// Optimization: Emit only a floating multiply if the addend is zero
if (auto cv = llvm::dyn_cast<llvm::Constant>(b.value))
if (auto [ok, data] = get_const_vector(b.value, m_addr, 2000); ok)
{
v128 data = get_const_vector(cv, m_addr, 2000);
if (data == v128{})
{
set_vr(op.vd, vec_handle_result(a * c));
@ -1253,10 +1251,8 @@ void PPUTranslator::VNMSUBFP(ppu_opcode_t op)
auto [a, b, c] = get_vrs<f32[4]>(op.va, op.vb, op.vc);
// Optimization: Emit only a floating multiply if the addend is zero
if (const auto cv = llvm::dyn_cast<llvm::Constant>(b.value))
if (const auto [ok, data] = get_const_vector(b.value, m_addr, 2004); ok)
{
const v128 data = get_const_vector(cv, m_addr, 2004);
if (data == v128{})
{
set_vr(op.vd, vec_handle_result(-a * c));
@ -1438,10 +1434,8 @@ void PPUTranslator::VSEL(ppu_opcode_t op)
const auto c = get_vr<u32[4]>(op.vc);
// Check if the constant mask doesn't require bit granularity
if (auto ci = llvm::dyn_cast<llvm::Constant>(c.value))
if (auto [ok, mask] = get_const_vector(c.value, m_addr, 9000); ok)
{
v128 mask = get_const_vector(ci, m_addr, 9000);
bool sel_32 = true;
for (u32 i = 0; i < 4; i++)
{

View File

@ -7088,10 +7088,8 @@ public:
const auto c = get_vr(op.rc);
// Check if the constant mask doesn't require bit granularity
if (auto ci = llvm::dyn_cast<llvm::Constant>(c.value))
if (auto [ok, mask] = get_const_vector(c.value, m_pos, 8000); ok)
{
v128 mask = get_const_vector(ci, m_pos, 8000);
bool sel_32 = true;
for (u32 i = 0; i < 4; i++)
{
@ -7192,11 +7190,9 @@ public:
const auto c = get_vr<u8[16]>(op.rc);
if (auto ci = llvm::dyn_cast<llvm::Constant>(c.value))
if (auto [ok, mask] = get_const_vector(c.value, m_pos, 57216); ok)
{
// Optimization: SHUFB with constant mask
v128 mask = get_const_vector(ci, m_pos, 57216);
if (((mask._u64[0] | mask._u64[1]) & 0xe0e0e0e0e0e0e0e0) == 0)
{
// Trivial insert or constant shuffle (TODO)
@ -7291,10 +7287,8 @@ public:
return;
}
if (auto ci = llvm::dyn_cast<llvm::Constant>(b.value))
if (auto [ok, data] = get_const_vector(b.value, m_pos, 7000); ok)
{
v128 data = get_const_vector(ci, m_pos, 7000);
const bool all_bytes_equiv = data == v128::from8p(data._u8[0]);
if (all_bytes_equiv)
{
@ -7310,10 +7304,8 @@ public:
if (auto [ok, v0] = match_expr(b, byteswap(match<u8[16]>())); ok)
{
if (auto ci = llvm::dyn_cast<llvm::Constant>(a.value))
if (auto [ok, data] = get_const_vector(a.value, m_pos, 7000); ok)
{
v128 data = get_const_vector(ci, m_pos, 7000);
const bool all_bytes_equiv = data == v128::from8p(data._u8[0]);
if (all_bytes_equiv)
{
@ -7542,9 +7534,8 @@ public:
const auto a = get_vr<f32[4]>(op.ra);
const auto b = get_vr<f32[4]>(op.rb);
if (auto cv = llvm::dyn_cast<llvm::Constant>(b.value))
if (auto [ok, data] = get_const_vector(b.value, m_pos, 5000); ok)
{
v128 data = get_const_vector(cv, m_pos, 5000);
bool safe_int_compare = true;
for (u32 i = 0; i < 4; i++)
@ -7569,9 +7560,8 @@ public:
}
}
if (auto cv = llvm::dyn_cast<llvm::Constant>(a.value))
if (auto [ok, data] = get_const_vector(a.value, m_pos, 5000); ok)
{
v128 data = get_const_vector(cv, m_pos, 5000);
bool safe_int_compare = true;
for (u32 i = 0; i < 4; i++)
@ -7735,10 +7725,8 @@ public:
// Optimization: Emit only a floating multiply if the addend is zero
// This is odd since SPU code could just use the FM instruction, but it seems common enough
if (auto cv = llvm::dyn_cast<llvm::Constant>(c.value))
if (auto [ok, data] = get_const_vector(c.value, m_pos, 4000); ok)
{
v128 data = get_const_vector(cv, m_pos, 4000);
if (is_spu_float_zero(data))
{
r = eval(a * b);
@ -7746,10 +7734,8 @@ public:
}
}
if (auto cv = llvm::dyn_cast<llvm::Constant>(b.value))
if (auto [ok, data] = get_const_vector(b.value, m_pos, 4000); ok)
{
v128 data = get_const_vector(cv, m_pos, 4000);
if (is_spu_float_zero(data))
{
// Just return the added value if either a or b is 0
@ -7757,10 +7743,8 @@ public:
}
}
if (auto cv = llvm::dyn_cast<llvm::Constant>(a.value))
if (auto [ok, data] = get_const_vector(a.value, m_pos, 4000); ok)
{
v128 data = get_const_vector(cv, m_pos, 4000);
if (is_spu_float_zero(data))
{
return c;
@ -7995,9 +7979,8 @@ public:
value_t<s32[4]> a = get_vr<s32[4]>(op.ra);
value_t<f64[4]> r;
if (auto ca = llvm::dyn_cast<llvm::Constant>(a.value))
if (auto [ok, data] = get_const_vector(a.value, m_pos, 25971); ok)
{
v128 data = get_const_vector(ca, m_pos, 25971);
r.value = build<f64[4]>(data._s32[0], data._s32[1], data._s32[2], data._s32[3]).eval(m_ir);
}
else
@ -8036,9 +8019,8 @@ public:
value_t<s32[4]> a = get_vr<s32[4]>(op.ra);
value_t<f64[4]> r;
if (auto ca = llvm::dyn_cast<llvm::Constant>(a.value))
if (auto [ok, data] = get_const_vector(a.value, m_pos, 20971); ok)
{
v128 data = get_const_vector(ca, m_pos, 20971);
r.value = build<f64[4]>(data._u32[0], data._u32[1], data._u32[2], data._u32[3]).eval(m_ir);
}
else
@ -8090,9 +8072,8 @@ public:
for (auto pair : std::initializer_list<std::pair<value_t<u32[4]>, value_t<u32[4]>>>{{a, b}, {b, a}})
{
if (auto cv = llvm::dyn_cast<llvm::Constant>(pair.first.value))
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos, 10000); ok)
{
v128 data = get_const_vector(cv, m_pos, 10000);
data._u32[3] %= SPU_LS_SIZE;
if (data._u32[3] % 0x10 == 0)
@ -8115,9 +8096,8 @@ public:
for (auto pair : std::initializer_list<std::pair<value_t<u32[4]>, value_t<u32[4]>>>{{a, b}, {b, a}})
{
if (auto cv = llvm::dyn_cast<llvm::Constant>(pair.first.value))
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos, 10000); ok)
{
v128 data = get_const_vector(cv, m_pos, 10000);
data._u32[3] %= SPU_LS_SIZE;
if (data._u32[3] % 0x10 == 0)