mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 17:11:23 +00:00
SPU/PPU LLVM: Fix cpu_translator::get_const_vector<v128>()
This commit is contained in:
parent
e52dd9dc6f
commit
f6764767f6
@ -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();
|
||||
|
@ -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*);
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user