Update cpu_translator

Add get_const_vector<v128>()
Add make_const_vector<v128>()
Add i2 and i4 types
Add build<>() for vector constants
Fix comparisons, allow EQ/NE for bool/char/i2/i4 types
This commit is contained in:
Nekotekina 2018-06-25 13:58:39 +03:00
parent 6a62de6d68
commit 88d0316aad
2 changed files with 176 additions and 1 deletions

View file

@ -12,4 +12,120 @@ cpu_translator::cpu_translator(llvm::Module* module, bool is_be)
}
#endif
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

View file

@ -26,6 +26,14 @@
#include <array>
#include <vector>
enum class i2 : char
{
};
enum class i4 : char
{
};
template <typename T = void>
struct llvm_value_t
{
@ -77,6 +85,38 @@ struct llvm_value_t<bool> : llvm_value_t<void>
}
};
template <>
struct llvm_value_t<i2> : llvm_value_t<void>
{
using type = i2;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 2;
static constexpr uint is_int = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getIntNTy(context, 2);
}
};
template <>
struct llvm_value_t<i4> : llvm_value_t<void>
{
using type = i4;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 4;
static constexpr uint is_int = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getIntNTy(context, 4);
}
};
template <>
struct llvm_value_t<char> : llvm_value_t<void>
{
@ -753,6 +793,8 @@ struct llvm_icmp_t
UPred == llvm::ICmpInst::ICMP_ULT ? llvm::ICmpInst::ICMP_SLT :
UPred == llvm::ICmpInst::ICMP_ULE ? llvm::ICmpInst::ICMP_SLE : UPred;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || UPred == llvm::ICmpInst::ICMP_EQ || UPred == llvm::ICmpInst::ICMP_NE, "llvm_eq_t<>: invalid type(II)");
static inline llvm::Value* icmp(llvm::IRBuilder<>* ir, llvm::Value* lhs, llvm::Value* rhs)
{
return ir->CreateICmp(pred, lhs, rhs);
@ -1056,6 +1098,17 @@ public:
return result;
}
template <typename T, typename... Args>
auto build(Args... args)
{
using value_type = std::remove_extent_t<T>;
const value_type values[]{static_cast<value_type>(args)...};
static_assert(sizeof(T) / sizeof(value_type) == sizeof...(Args), "build: unexpected number of arguments");
value_t<T> result;
result.value = llvm::ConstantDataVector::get(m_context, values);
return result;
}
template <typename... Types>
llvm::Function* get_intrinsic(llvm::Intrinsic::ID id)
{
@ -1102,6 +1155,12 @@ public:
result.value = m_ir->CreateFCmp(FPred, a.eval(m_ir), b.eval(m_ir));
return result;
}
template <typename R = v128>
R get_const_vector(llvm::Constant*, u32 a, u32 b);
template <typename T = v128>
llvm::Constant* make_const_vector(T, llvm::Type*);
};
#endif