rpcsx/rpcs3/Emu/CPU/CPUTranslator.cpp
Nekotekina 7492f335e9 SPU analyser: basic function detection in Giga mode
Misc: fix EH frame registration (LLVM, non-Windows).
Misc: constant-folding bitcast (cpu_translator).
Misc: add syntax for LLVM arrays (cpu_translator).
Misc: use function names for proper linkage (SPU LLVM).

Changed function search and verification in Giga mode.
Basic stack frame layout analysis.
Function detection in Giga mode.
Basic use of new information in SPU LLVM.
Fixed jump table compilation in SPU LLVM.
Disable broken optimization in Accurate xfloat mode.
Make compiled SPU modules position-independent in SPU LLVM.

Optimizations include but not limited to:
 * Compiling SPU functions as native functions when eligible
 * Avoiding register context write-out
 * Aligned stack assumption (CWD alike instruction)
2019-05-11 02:13:19 +03:00

179 lines
3.9 KiB
C++

#ifdef LLVM_AVAILABLE
#include "CPUTranslator.h"
llvm::LLVMContext g_llvm_ctx;
cpu_translator::cpu_translator(llvm::Module* module, bool is_be)
: m_context(g_llvm_ctx)
, m_module(module)
, m_is_be(is_be)
{
}
void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngine& engine)
{
m_context = context;
m_engine = &engine;
const auto cpu = m_engine->getTargetMachine()->getTargetCPU();
m_use_ssse3 = true;
// Test SSSE3 feature (TODO)
if (cpu == "generic" ||
cpu == "k8" ||
cpu == "opteron" ||
cpu == "athlon64" ||
cpu == "athlon-fx" ||
cpu == "k8-sse3" ||
cpu == "opteron-sse3" ||
cpu == "athlon64-sse3" ||
cpu == "amdfam10" ||
cpu == "barcelona")
{
m_use_ssse3 = false;
}
}
llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type)
{
uint s1 = type->getScalarSizeInBits();
uint s2 = val->getType()->getScalarSizeInBits();
if (type->isVectorTy())
s1 *= type->getVectorNumElements();
if (val->getType()->isVectorTy())
s2 *= val->getType()->getVectorNumElements();
if (s1 != s2)
{
fmt::throw_exception("cpu_translator::bitcast(): incompatible type sizes (%u vs %u)", s1, s2);
}
if (const auto c1 = llvm::dyn_cast<llvm::Constant>(val))
{
return verify(HERE, llvm::ConstantFoldCastOperand(llvm::Instruction::BitCast, c1, type, m_module->getDataLayout()));
}
return m_ir->CreateBitCast(val, type);
}
template <>
v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
{
const auto t = c->getType();
if (!t->isVectorTy())
{
fmt::throw_exception("[0x%x, %u] Not a vector" HERE, a, b);
}
if (uint sz = llvm::cast<llvm::VectorType>(t)->getBitWidth() - 128)
{
fmt::throw_exception("[0x%x, %u] Bad vector size: %u" HERE, a, b, sz + 128);
}
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(c);
if (!cv)
{
if (llvm::isa<llvm::ConstantAggregateZero>(c))
{
return {};
}
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++)
{
result._u8[i] = cv->getElementAsInteger(i);
}
}
else if (sct->isIntegerTy(16))
{
for (u32 i = 0; i < 8; i++)
{
result._u16[i] = cv->getElementAsInteger(i);
}
}
else if (sct->isIntegerTy(32))
{
for (u32 i = 0; i < 4; i++)
{
result._u32[i] = cv->getElementAsInteger(i);
}
}
else if (sct->isIntegerTy(64))
{
for (u32 i = 0; i < 2; i++)
{
result._u64[i] = cv->getElementAsInteger(i);
}
}
else if (sct->isFloatTy())
{
for (u32 i = 0; i < 4; i++)
{
result._f[i] = cv->getElementAsFloat(i);
}
}
else if (sct->isDoubleTy())
{
for (u32 i = 0; i < 2; i++)
{
result._d[i] = cv->getElementAsDouble(i);
}
}
else
{
fmt::throw_exception("[0x%x, %u] Unexpected vector element type" HERE, a, b);
}
return result;
}
template <>
llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t)
{
verify(HERE), t->isVectorTy() && llvm::cast<llvm::VectorType>(t)->getBitWidth() == 128;
const auto sct = t->getScalarType();
if (sct->isIntegerTy(8))
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u8*)v._bytes, 16));
}
else if (sct->isIntegerTy(16))
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u16*)v._bytes, 8));
}
else if (sct->isIntegerTy(32))
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u32*)v._bytes, 4));
}
else if (sct->isIntegerTy(64))
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const u64*)v._bytes, 2));
}
else if (sct->isFloatTy())
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const f32*)v._bytes, 4));
}
else if (sct->isDoubleTy())
{
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef((const f64*)v._bytes, 2));
}
fmt::raw_error("No supported constant type" HERE);
}
#endif