2020-03-04 15:08:40 +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
|
|
|
|
|
2018-05-01 12:21:45 +02:00
|
|
|
|
llvm::LLVMContext g_llvm_ctx;
|
|
|
|
|
|
|
|
|
|
|
|
cpu_translator::cpu_translator(llvm::Module* module, bool is_be)
|
|
|
|
|
|
: m_context(g_llvm_ctx)
|
2018-01-29 22:31:38 +01:00
|
|
|
|
, m_module(module)
|
|
|
|
|
|
, m_is_be(is_be)
|
|
|
|
|
|
{
|
2019-05-05 15:28:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
|
{
|
|
|
|
|
|
m_use_fma = true;
|
|
|
|
|
|
}
|
2019-05-05 15:28:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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()));
|
|
|
|
|
|
}
|
2018-01-29 22:31:38 +01:00
|
|
|
|
|
2019-05-05 15:28:41 +02:00
|
|
|
|
return m_ir->CreateBitCast(val, type);
|
2018-01-29 22:31:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-25 12:58:39 +02:00
|
|
|
|
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++)
|
|
|
|
|
|
{
|
2020-03-04 15:08:40 +01:00
|
|
|
|
result._u8[i] = static_cast<u8>(cv->getElementAsInteger(i));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
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))
|
|
|
|
|
|
{
|
2019-12-03 23:34:23 +01:00
|
|
|
|
return llvm::ConstantDataVector::get(m_context, llvm::makeArrayRef(reinterpret_cast<const u8*>(v._bytes), 16));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
else 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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
else 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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
else 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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
else 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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
else 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));
|
2018-06-25 12:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fmt::raw_error("No supported constant type" HERE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|