rpcsx/rpcs3/Emu/CPU/CPUTranslator.cpp

351 lines
8.5 KiB
C++
Raw Normal View History

2020-12-05 13:08:24 +01:00
#ifdef LLVM_AVAILABLE
2018-01-29 22:31:38 +01:00
2016-06-07 22:24:20 +02:00
#include "CPUTranslator.h"
2018-01-29 22:31:38 +01:00
#include "util/v128.hpp"
#include "util/v128sse.hpp"
2018-05-01 12:21:45 +02:00
llvm::LLVMContext g_llvm_ctx;
llvm::Value* peek_through_bitcasts(llvm::Value* arg)
{
llvm::CastInst* i;
while ((i = llvm::dyn_cast_or_null<llvm::CastInst>(arg)) && i->getOpcode() == llvm::Instruction::BitCast)
{
arg = i->getOperand(0);
}
return arg;
}
cpu_translator::cpu_translator(llvm::Module* _module, bool is_be)
2018-05-01 12:21:45 +02:00
: m_context(g_llvm_ctx)
, m_module(_module)
2018-01-29 22:31:38 +01:00
, m_is_be(is_be)
{
register_intrinsic("x86_pshufb", [&](llvm::CallInst* ci) -> llvm::Value*
{
const auto data0 = ci->getOperand(0);
const auto index = ci->getOperand(1);
const auto zeros = llvm::ConstantAggregateZero::get(get_type<u8[16]>());
if (m_use_ssse3)
{
return m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_ssse3_pshuf_b_128), {data0, index});
}
else
{
// Emulate PSHUFB (TODO)
const auto mask = m_ir->CreateAnd(index, 0xf);
const auto loop = llvm::BasicBlock::Create(m_context, "", m_ir->GetInsertBlock()->getParent());
const auto prev = ci->getParent();
const auto next = prev->splitBasicBlock(ci->getNextNode());
llvm::cast<llvm::BranchInst>(m_ir->GetInsertBlock()->getTerminator())->setOperand(0, loop);
llvm::Value* result;
//m_ir->CreateBr(loop);
m_ir->SetInsertPoint(loop);
const auto i = m_ir->CreatePHI(get_type<u32>(), 2);
const auto v = m_ir->CreatePHI(get_type<u8[16]>(), 2);
i->addIncoming(m_ir->getInt32(0), prev);
i->addIncoming(m_ir->CreateAdd(i, m_ir->getInt32(1)), loop);
v->addIncoming(zeros, prev);
result = m_ir->CreateInsertElement(v, m_ir->CreateExtractElement(data0, m_ir->CreateExtractElement(mask, i)), i);
v->addIncoming(result, loop);
m_ir->CreateCondBr(m_ir->CreateICmpULT(i, m_ir->getInt32(16)), loop, next);
m_ir->SetInsertPoint(next->getFirstNonPHI());
result = m_ir->CreateSelect(m_ir->CreateICmpSLT(index, zeros), zeros, result);
return result;
}
});
}
void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngine& engine)
{
m_context = context;
m_engine = &engine;
const auto cpu = m_engine->getTargetMachine()->getTargetCPU();
// 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;
}
2019-12-20 19:11:07 +01:00
// Test FMA feature (TODO)
if (cpu == "haswell" ||
cpu == "broadwell" ||
cpu == "skylake" ||
cpu == "bdver2" ||
cpu == "bdver3" ||
cpu == "bdver4" ||
2020-02-29 06:29:28 +01:00
cpu.startswith("znver"))
2019-12-20 19:11:07 +01:00
{
m_use_fma = true;
}
// Test AVX-512 feature (TODO)
if (cpu == "skylake-avx512" ||
cpu == "cascadelake" ||
cpu == "cannonlake" ||
cpu == "cooperlake" ||
cpu == "icelake" ||
cpu == "icelake-client" ||
cpu == "icelake-server" ||
cpu == "tigerlake" ||
cpu == "rocketlake")
2019-12-20 19:11:07 +01:00
{
m_use_fma = true;
m_use_avx512 = true;
2019-12-20 19:11:07 +01:00
}
// Test VNNI feature (TODO)
if (cpu == "cascadelake" ||
cpu == "cooperlake" ||
cpu == "alderlake")
{
m_use_vnni = true;
}
// Test AVX-512_icelake features (TODO)
if (cpu == "icelake" ||
cpu == "icelake-client" ||
cpu == "icelake-server" ||
cpu == "tigerlake" ||
cpu == "rocketlake" ||
cpu == "sapphirerapids")
{
m_use_avx512_icl = true;
m_use_vnni = true;
}
}
2021-04-09 21:12:47 +02:00
llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type) const
{
uint s1 = type->getScalarSizeInBits();
uint s2 = val->getType()->getScalarSizeInBits();
if (type->isVectorTy())
2020-11-02 04:07:58 +01:00
s1 *= llvm::cast<llvm::VectorType>(type)->getNumElements();
if (val->getType()->isVectorTy())
2020-11-02 04:07:58 +01:00
s2 *= llvm::cast<llvm::VectorType>(val->getType())->getNumElements();
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 ensure(llvm::ConstantFoldCastOperand(llvm::Instruction::BitCast, c1, type, m_module->getDataLayout()));
}
2018-01-29 22:31:38 +01:00
return m_ir->CreateBitCast(val, type);
2018-01-29 22:31:38 +01:00
}
template <>
std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32 _pos, u32 _line)
{
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)
{
2021-04-09 21:12:47 +02:00
const auto& cv = ci->getValue();
result._u64[0] = cv.extractBitsAsZExtValue(64, 0);
result._u64[1] = cv.extractBitsAsZExtValue(64, 64);
return {true, result};
}
fmt::throw_exception("[0x%x, %u] Not a vector", _pos, _line);
}
2020-11-02 04:07:58 +01:00
if (auto v = llvm::cast<llvm::VectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
{
fmt::throw_exception("[0x%x, %u] Bad vector size: i%ux%u", _pos, _line, v->getScalarSizeInBits(), v->getNumElements());
}
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(c);
if (!cv)
{
if (llvm::isa<llvm::ConstantAggregateZero>(c))
{
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!", _pos, _line);
}
fmt::throw_exception("[0x%x, %u] Unexpected constant type", _pos, _line);
}
const auto sct = t->getScalarType();
if (sct->isIntegerTy(8))
{
for (u32 i = 0; i < 16; i++)
{
2020-03-04 15:08:40 +01:00
result._u8[i] = static_cast<u8>(cv->getElementAsInteger(i));
}
}
else if (sct->isIntegerTy(16))
{
for (u32 i = 0; i < 8; i++)
{
2020-03-04 15:08:40 +01:00
result._u16[i] = static_cast<u16>(cv->getElementAsInteger(i));
}
}
else if (sct->isIntegerTy(32))
{
for (u32 i = 0; i < 4; i++)
{
2020-03-04 15:08:40 +01:00
result._u32[i] = static_cast<u32>(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", _pos, _line);
}
return {true, result};
}
template <>
llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t, u32 _line)
{
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)));
}
ensure(t->isVectorTy());
ensure(128 == t->getScalarSizeInBits() * llvm::cast<llvm::VectorType>(t)->getNumElements());
const auto sct = t->getScalarType();
if (sct->isIntegerTy(8))
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const u8*>(v._bytes), 16));
}
2021-04-09 21:12:47 +02:00
if (sct->isIntegerTy(16))
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const u16*>(v._bytes), 8));
}
2021-04-09 21:12:47 +02:00
if (sct->isIntegerTy(32))
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const u32*>(v._bytes), 4));
}
2021-04-09 21:12:47 +02:00
if (sct->isIntegerTy(64))
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const u64*>(v._bytes), 2));
}
2021-04-09 21:12:47 +02:00
if (sct->isFloatTy())
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const f32*>(v._bytes), 4));
}
2021-04-09 21:12:47 +02:00
if (sct->isDoubleTy())
{
2019-12-03 23:34:23 +01:00
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const f64*>(v._bytes), 2));
}
fmt::throw_exception("[line %u] No supported constant type", _line);
}
void cpu_translator::replace_intrinsics(llvm::Function& f)
{
for (auto& bb : f)
{
for (auto bit = bb.begin(); bit != bb.end();)
{
if (auto ci = llvm::dyn_cast<llvm::CallInst>(&*bit))
{
if (auto cf = ci->getCalledFunction())
{
if (auto it = m_intrinsics.find(std::string_view(cf->getName().data(), cf->getName().size())); it != m_intrinsics.end())
{
m_ir->SetInsertPoint(ci);
ci->replaceAllUsesWith(it->second(ci));
bit = ci->eraseFromParent();
continue;
}
}
}
++bit;
}
}
}
void cpu_translator::erase_stores(llvm::ArrayRef<llvm::Value*> args)
{
for (auto v : args)
{
for (auto it = v->use_begin(); it != v->use_end(); ++it)
{
llvm::Value* i = *it;
llvm::CastInst* bci = nullptr;
// Walk through bitcasts
while (i && (bci = llvm::dyn_cast<llvm::CastInst>(i)) && bci->getOpcode() == llvm::Instruction::BitCast)
{
i = *bci->use_begin();
}
if (auto si = llvm::dyn_cast_or_null<llvm::StoreInst>(i))
{
si->eraseFromParent();
}
}
}
}
#endif