mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 08:01:11 +03:00

Applied patch from ticket #129 to compile against latest LLVM. Thanks Frits van Bommel. Fixed implicit return by asm block at the end of a function on x86-32. Other architectures will produce an error at the moment. Adding support for new targets is fairly simple. Fixed return calling convention for complex numbers, ST and ST(1) were switched around. Added some testcases. I've run a dstress test and there are no regressions. However, the runtime does not seem to compile with symbolic debug information. -O3 -release -inline works well and is what I used for the dstress run. Tango does not compile, a small workaround is needed in tango.io.digest.Digest.Digest.hexDigest. See ticket #206 .
887 lines
24 KiB
C++
887 lines
24 KiB
C++
#include <iostream>
|
|
|
|
#include "gen/llvm.h"
|
|
|
|
#include "dsymbol.h"
|
|
#include "aggregate.h"
|
|
#include "declaration.h"
|
|
#include "init.h"
|
|
#include "module.h"
|
|
|
|
#include "gen/tollvm.h"
|
|
#include "gen/irstate.h"
|
|
#include "gen/logger.h"
|
|
#include "gen/runtime.h"
|
|
#include "gen/arrays.h"
|
|
#include "gen/dvalue.h"
|
|
#include "gen/functions.h"
|
|
#include "gen/structs.h"
|
|
#include "gen/classes.h"
|
|
#include "gen/typeinf.h"
|
|
#include "gen/complex.h"
|
|
#include "gen/llvmhelpers.h"
|
|
|
|
bool DtoIsPassedByRef(Type* type)
|
|
{
|
|
Type* typ = type->toBasetype();
|
|
TY t = typ->ty;
|
|
return (t == Tstruct || t == Tsarray);
|
|
}
|
|
|
|
bool DtoIsReturnedInArg(Type* type)
|
|
{
|
|
Type* typ = type->toBasetype();
|
|
TY t = typ->ty;
|
|
return (t == Tstruct || t == Tsarray);
|
|
}
|
|
|
|
unsigned DtoShouldExtend(Type* type)
|
|
{
|
|
type = type->toBasetype();
|
|
if (type->isintegral())
|
|
{
|
|
switch(type->ty)
|
|
{
|
|
case Tint8:
|
|
case Tint16:
|
|
return llvm::Attribute::SExt;
|
|
|
|
case Tuns8:
|
|
case Tuns16:
|
|
return llvm::Attribute::ZExt;
|
|
}
|
|
}
|
|
return llvm::Attribute::None;
|
|
}
|
|
|
|
const LLType* DtoType(Type* t)
|
|
{
|
|
assert(t);
|
|
switch (t->ty)
|
|
{
|
|
// integers
|
|
case Tint8:
|
|
case Tuns8:
|
|
case Tchar:
|
|
return (const LLType*)LLType::Int8Ty;
|
|
case Tint16:
|
|
case Tuns16:
|
|
case Twchar:
|
|
return (const LLType*)LLType::Int16Ty;
|
|
case Tint32:
|
|
case Tuns32:
|
|
case Tdchar:
|
|
return (const LLType*)LLType::Int32Ty;
|
|
case Tint64:
|
|
case Tuns64:
|
|
return (const LLType*)LLType::Int64Ty;
|
|
|
|
case Tbool:
|
|
return (const LLType*)llvm::ConstantInt::getTrue()->getType();
|
|
|
|
// floats
|
|
case Tfloat32:
|
|
case Timaginary32:
|
|
return LLType::FloatTy;
|
|
case Tfloat64:
|
|
case Timaginary64:
|
|
return LLType::DoubleTy;
|
|
case Tfloat80:
|
|
case Timaginary80:
|
|
if (global.params.cpu == ARCHx86 || global.params.cpu == ARCHx86_64)
|
|
return LLType::X86_FP80Ty;
|
|
else
|
|
return LLType::DoubleTy;
|
|
|
|
// complex
|
|
case Tcomplex32:
|
|
case Tcomplex64:
|
|
case Tcomplex80:
|
|
return DtoComplexType(t);
|
|
|
|
// pointers
|
|
case Tpointer:
|
|
// getPtrToType checks for void itself
|
|
return getPtrToType(DtoType(t->nextOf()));
|
|
|
|
// arrays
|
|
case Tarray:
|
|
return DtoArrayType(t);
|
|
case Tsarray:
|
|
return DtoStaticArrayType(t);
|
|
|
|
// void
|
|
case Tvoid:
|
|
return LLType::VoidTy;
|
|
|
|
// aggregates
|
|
case Tstruct: {
|
|
#if DMDV2
|
|
TypeStruct* ts = (TypeStruct*)t->mutableOf();
|
|
#else
|
|
TypeStruct* ts = (TypeStruct*)t;
|
|
#endif
|
|
assert(ts->sym);
|
|
DtoResolveDsymbol(ts->sym);
|
|
return ts->ir.type->get();
|
|
}
|
|
|
|
case Tclass: {
|
|
#if DMDV2
|
|
TypeClass* tc = (TypeClass*)t->mutableOf();
|
|
#else
|
|
TypeClass* tc = (TypeClass*)t;
|
|
#endif
|
|
assert(tc->sym);
|
|
DtoResolveDsymbol(tc->sym);
|
|
return getPtrToType(tc->ir.type->get());
|
|
}
|
|
|
|
// functions
|
|
case Tfunction:
|
|
{
|
|
if (!t->ir.type || *t->ir.type == NULL) {
|
|
return DtoFunctionType(t,NULL,NULL);
|
|
}
|
|
else {
|
|
return t->ir.type->get();
|
|
}
|
|
}
|
|
|
|
// delegates
|
|
case Tdelegate:
|
|
{
|
|
if (!t->ir.type || *t->ir.type == NULL) {
|
|
return DtoDelegateType(t);
|
|
}
|
|
else {
|
|
return t->ir.type->get();
|
|
}
|
|
}
|
|
|
|
// typedefs
|
|
// enum
|
|
case Ttypedef:
|
|
case Tenum:
|
|
{
|
|
Type* bt = t->toBasetype();
|
|
assert(bt);
|
|
return DtoType(bt);
|
|
}
|
|
|
|
// associative arrays
|
|
case Taarray:
|
|
#if 1
|
|
return getVoidPtrType();
|
|
#else
|
|
{
|
|
TypeAArray* taa = (TypeAArray*)t;
|
|
// aa key/val can't be void
|
|
return getPtrToType(LLStructType::get(DtoType(taa->key), DtoType(taa->next), 0));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
Not needed atm as VarDecls for tuples are rewritten as a string of
|
|
VarDecls for the fields (u -> _u_field_0, ...)
|
|
|
|
case Ttuple:
|
|
{
|
|
TypeTuple* ttupl = (TypeTuple*)t;
|
|
return DtoStructTypeFromArguments(ttupl->arguments);
|
|
}
|
|
*/
|
|
|
|
default:
|
|
printf("trying to convert unknown type '%s' with value %d\n", t->toChars(), t->ty);
|
|
assert(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
const LLType* DtoStructTypeFromArguments(Arguments* arguments)
|
|
{
|
|
if (!arguments)
|
|
return LLType::VoidTy;
|
|
|
|
std::vector<const LLType*> types;
|
|
for (size_t i = 0; i < arguments->dim; i++)
|
|
{
|
|
Argument *arg = (Argument *)arguments->data[i];
|
|
assert(arg && arg->type);
|
|
|
|
types.push_back(DtoType(arg->type));
|
|
}
|
|
return LLStructType::get(types);
|
|
}
|
|
*/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLType* DtoTypeNotVoid(Type* t)
|
|
{
|
|
const LLType* lt = DtoType(t);
|
|
if (lt == LLType::VoidTy)
|
|
return LLType::Int8Ty;
|
|
return lt;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLStructType* DtoDelegateType(Type* t)
|
|
{
|
|
assert(t->ty == Tdelegate);
|
|
const LLType* i8ptr = getVoidPtrType();
|
|
const LLType* func = DtoFunctionType(t->nextOf(), NULL, i8ptr);
|
|
const LLType* funcptr = getPtrToType(func);
|
|
return LLStructType::get(i8ptr, funcptr, NULL);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoDelegateEquals(TOK op, LLValue* lhs, LLValue* rhs)
|
|
{
|
|
Logger::println("Doing delegate equality");
|
|
llvm::Value *b1, *b2;
|
|
if (rhs == NULL)
|
|
{
|
|
rhs = LLConstant::getNullValue(lhs->getType());
|
|
}
|
|
|
|
LLValue* l = gIR->ir->CreateExtractValue(lhs, 0);
|
|
LLValue* r = gIR->ir->CreateExtractValue(rhs, 0);
|
|
b1 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
|
|
|
|
l = gIR->ir->CreateExtractValue(lhs, 1);
|
|
r = gIR->ir->CreateExtractValue(rhs, 1);
|
|
b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
|
|
|
|
LLValue* b = gIR->ir->CreateAnd(b1,b2,"tmp");
|
|
|
|
if (op == TOKnotequal || op == TOKnotidentity)
|
|
return gIR->ir->CreateNot(b,"tmp");
|
|
|
|
return b;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
|
{
|
|
// global variable
|
|
if (VarDeclaration* vd = sym->isVarDeclaration())
|
|
{
|
|
// template
|
|
if (needsTemplateLinkage(sym))
|
|
return TEMPLATE_LINKAGE_TYPE;
|
|
// local static
|
|
else if (sym->parent && sym->parent->isFuncDeclaration())
|
|
return llvm::GlobalValue::InternalLinkage;
|
|
}
|
|
// function
|
|
else if (FuncDeclaration* fdecl = sym->isFuncDeclaration())
|
|
{
|
|
assert(fdecl->type->ty == Tfunction);
|
|
TypeFunction* ft = (TypeFunction*)fdecl->type;
|
|
|
|
// array operations are always internal
|
|
if (fdecl->isArrayOp)
|
|
return llvm::GlobalValue::InternalLinkage;
|
|
// intrinsics are always external
|
|
if (fdecl->llvmInternal == LLVMintrinsic)
|
|
return llvm::GlobalValue::ExternalLinkage;
|
|
// template instances should have weak linkage
|
|
// but only if there's a body, and it's not naked
|
|
// otherwise we make it external
|
|
else if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked)
|
|
return TEMPLATE_LINKAGE_TYPE;
|
|
// extern(C) functions are always external
|
|
else if (ft->linkage == LINKc)
|
|
return llvm::GlobalValue::ExternalLinkage;
|
|
}
|
|
// class
|
|
else if (ClassDeclaration* cd = sym->isClassDeclaration())
|
|
{
|
|
// template
|
|
if (needsTemplateLinkage(cd))
|
|
return TEMPLATE_LINKAGE_TYPE;
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "not global/function");
|
|
}
|
|
|
|
// default to external linkage
|
|
return llvm::GlobalValue::ExternalLinkage;
|
|
}
|
|
|
|
llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym)
|
|
{
|
|
if (needsTemplateLinkage(sym))
|
|
return TEMPLATE_LINKAGE_TYPE;
|
|
else
|
|
return llvm::GlobalValue::InternalLinkage;
|
|
}
|
|
|
|
llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym)
|
|
{
|
|
if (needsTemplateLinkage(sym))
|
|
return TEMPLATE_LINKAGE_TYPE;
|
|
else
|
|
return llvm::GlobalValue::ExternalLinkage;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoPointedType(LLValue* ptr, LLValue* val)
|
|
{
|
|
const LLType* ptrTy = ptr->getType()->getContainedType(0);
|
|
const LLType* valTy = val->getType();
|
|
// ptr points to val's type
|
|
if (ptrTy == valTy)
|
|
{
|
|
return val;
|
|
}
|
|
// ptr is integer pointer
|
|
else if (ptrTy->isInteger())
|
|
{
|
|
// val is integer
|
|
assert(valTy->isInteger());
|
|
const LLIntegerType* pt = llvm::cast<const LLIntegerType>(ptrTy);
|
|
const LLIntegerType* vt = llvm::cast<const LLIntegerType>(valTy);
|
|
if (pt->getBitWidth() < vt->getBitWidth()) {
|
|
return new llvm::TruncInst(val, pt, "tmp", gIR->scopebb());
|
|
}
|
|
else
|
|
assert(0);
|
|
}
|
|
// something else unsupported
|
|
else
|
|
{
|
|
if (Logger::enabled())
|
|
Logger::cout() << *ptrTy << '|' << *valTy << '\n';
|
|
assert(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLType* DtoSize_t()
|
|
{
|
|
// the type of size_t does not change once set
|
|
static const LLType* t = NULL;
|
|
if (t == NULL)
|
|
t = (global.params.is64bit) ? LLType::Int64Ty : LLType::Int32Ty;
|
|
return t;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoGEP1(LLValue* ptr, LLValue* i0, const char* var, llvm::BasicBlock* bb)
|
|
{
|
|
return llvm::GetElementPtrInst::Create(ptr, i0, var?var:"tmp", bb?bb:gIR->scopebb());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const char* var, llvm::BasicBlock* bb)
|
|
{
|
|
LLSmallVector<LLValue*,2> v(2);
|
|
v[0] = i0;
|
|
v[1] = i1;
|
|
return llvm::GetElementPtrInst::Create(ptr, v.begin(), v.end(), var?var:"tmp", bb?bb:gIR->scopebb());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoGEPi1(LLValue* ptr, unsigned i, const char* var, llvm::BasicBlock* bb)
|
|
{
|
|
return llvm::GetElementPtrInst::Create(ptr, DtoConstUint(i), var?var:"tmp", bb?bb:gIR->scopebb());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb)
|
|
{
|
|
LLSmallVector<LLValue*,2> v(2);
|
|
v[0] = DtoConstUint(i0);
|
|
v[1] = DtoConstUint(i1);
|
|
return llvm::GetElementPtrInst::Create(ptr, v.begin(), v.end(), var?var:"tmp", bb?bb:gIR->scopebb());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoMemSetZero(LLValue* dst, LLValue* nbytes)
|
|
{
|
|
dst = DtoBitCast(dst,getVoidPtrType());
|
|
|
|
const LLType* intTy = DtoSize_t();
|
|
llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module,
|
|
llvm::Intrinsic::memset, &intTy, 1);
|
|
|
|
gIR->ir->CreateCall4(fn, dst, DtoConstUbyte(0), nbytes, DtoConstUint(0), "");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes)
|
|
{
|
|
dst = DtoBitCast(dst,getVoidPtrType());
|
|
src = DtoBitCast(src,getVoidPtrType());
|
|
|
|
const LLType* intTy = DtoSize_t();
|
|
llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module,
|
|
llvm::Intrinsic::memcpy, &intTy, 1);
|
|
|
|
gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(0), "");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoMemCmp(LLValue* lhs, LLValue* rhs, LLValue* nbytes)
|
|
{
|
|
// int memcmp ( const void * ptr1, const void * ptr2, size_t num );
|
|
|
|
LLFunction* fn = gIR->module->getFunction("memcmp");
|
|
if (!fn)
|
|
{
|
|
std::vector<const LLType*> params(3);
|
|
params[0] = getVoidPtrType();
|
|
params[1] = getVoidPtrType();
|
|
params[2] = DtoSize_t();
|
|
const LLFunctionType* fty = LLFunctionType::get(LLType::Int32Ty, params, false);
|
|
fn = LLFunction::Create(fty, LLGlobalValue::ExternalLinkage, "memcmp", gIR->module);
|
|
}
|
|
|
|
lhs = DtoBitCast(lhs,getVoidPtrType());
|
|
rhs = DtoBitCast(rhs,getVoidPtrType());
|
|
|
|
return gIR->ir->CreateCall3(fn, lhs, rhs, nbytes, "tmp");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoAggrZeroInit(LLValue* v)
|
|
{
|
|
uint64_t n = getTypeStoreSize(v->getType()->getContainedType(0));
|
|
DtoMemSetZero(v, DtoConstSize_t(n));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoAggrCopy(LLValue* dst, LLValue* src)
|
|
{
|
|
uint64_t n = getTypeStoreSize(dst->getType()->getContainedType(0));
|
|
DtoMemCpy(dst, src, DtoConstSize_t(n));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoMemoryBarrier(bool ll, bool ls, bool sl, bool ss, bool device)
|
|
{
|
|
llvm::Function* fn = GET_INTRINSIC_DECL(memory_barrier);
|
|
assert(fn != NULL);
|
|
|
|
LLSmallVector<LLValue*, 5> llargs;
|
|
llargs.push_back(DtoConstBool(ll));
|
|
llargs.push_back(DtoConstBool(ls));
|
|
llargs.push_back(DtoConstBool(sl));
|
|
llargs.push_back(DtoConstBool(ss));
|
|
llargs.push_back(DtoConstBool(device));
|
|
|
|
llvm::CallInst::Create(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
llvm::ConstantInt* DtoConstSize_t(size_t i)
|
|
{
|
|
return llvm::ConstantInt::get(DtoSize_t(), i, false);
|
|
}
|
|
llvm::ConstantInt* DtoConstUint(unsigned i)
|
|
{
|
|
return llvm::ConstantInt::get(LLType::Int32Ty, i, false);
|
|
}
|
|
llvm::ConstantInt* DtoConstInt(int i)
|
|
{
|
|
return llvm::ConstantInt::get(LLType::Int32Ty, i, true);
|
|
}
|
|
LLConstant* DtoConstBool(bool b)
|
|
{
|
|
return llvm::ConstantInt::get(LLType::Int1Ty, b, false);
|
|
}
|
|
llvm::ConstantInt* DtoConstUbyte(unsigned char i)
|
|
{
|
|
return llvm::ConstantInt::get(LLType::Int8Ty, i, false);
|
|
}
|
|
|
|
llvm::ConstantFP* DtoConstFP(Type* t, long double value)
|
|
{
|
|
const LLType* llty = DtoType(t);
|
|
assert(llty->isFloatingPoint());
|
|
|
|
if(llty == LLType::FloatTy || llty == LLType::DoubleTy)
|
|
return LLConstantFP::get(llty, value);
|
|
else if(llty == LLType::X86_FP80Ty) {
|
|
uint64_t bits[] = {0, 0};
|
|
bits[1] = *(uint16_t*)&value;
|
|
bits[0] = *(uint64_t*)((uint16_t*)&value + 1);
|
|
return LLConstantFP::get(APFloat(APInt(80, 2, bits)));
|
|
} else {
|
|
assert(0 && "Unknown floating point type encountered");
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLConstant* DtoConstString(const char* str)
|
|
{
|
|
std::string s(str?str:"");
|
|
LLConstant* init = llvm::ConstantArray::get(s, true);
|
|
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
|
|
init->getType(), true,llvm::GlobalValue::InternalLinkage, init, ".str", gIR->module);
|
|
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
|
return DtoConstSlice(
|
|
DtoConstSize_t(s.length()),
|
|
llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2)
|
|
);
|
|
}
|
|
LLConstant* DtoConstStringPtr(const char* str, const char* section)
|
|
{
|
|
std::string s(str);
|
|
LLConstant* init = llvm::ConstantArray::get(s, true);
|
|
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
|
|
init->getType(), true,llvm::GlobalValue::InternalLinkage, init, ".str", gIR->module);
|
|
if (section) gvar->setSection(section);
|
|
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
|
|
return llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoLoad(LLValue* src, const char* name)
|
|
{
|
|
// if (Logger::enabled())
|
|
// Logger::cout() << "loading " << *src << '\n';
|
|
LLValue* ld = gIR->ir->CreateLoad(src, name ? name : "tmp");
|
|
//ld->setVolatile(gIR->func()->inVolatile);
|
|
return ld;
|
|
}
|
|
|
|
void DtoStore(LLValue* src, LLValue* dst)
|
|
{
|
|
// if (Logger::enabled())
|
|
// Logger::cout() << "storing " << *src << " into " << *dst << '\n';
|
|
LLValue* st = gIR->ir->CreateStore(src,dst);
|
|
//st->setVolatile(gIR->func()->inVolatile);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoBitCast(LLValue* v, const LLType* t, const char* name)
|
|
{
|
|
if (v->getType() == t)
|
|
return v;
|
|
assert(!(isaStruct(t) || isaStruct(v->getType())));
|
|
return gIR->ir->CreateBitCast(v, t, name ? name : "tmp");
|
|
}
|
|
|
|
LLConstant* DtoBitCast(LLConstant* v, const LLType* t)
|
|
{
|
|
if (v->getType() == t)
|
|
return v;
|
|
return llvm::ConstantExpr::getBitCast(v, t);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLPointerType* isaPointer(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<LLPointerType>(v->getType());
|
|
}
|
|
|
|
const LLPointerType* isaPointer(const LLType* t)
|
|
{
|
|
return llvm::dyn_cast<LLPointerType>(t);
|
|
}
|
|
|
|
const LLArrayType* isaArray(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<LLArrayType>(v->getType());
|
|
}
|
|
|
|
const LLArrayType* isaArray(const LLType* t)
|
|
{
|
|
return llvm::dyn_cast<LLArrayType>(t);
|
|
}
|
|
|
|
const LLStructType* isaStruct(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<LLStructType>(v->getType());
|
|
}
|
|
|
|
const LLStructType* isaStruct(const LLType* t)
|
|
{
|
|
return llvm::dyn_cast<LLStructType>(t);
|
|
}
|
|
|
|
const LLFunctionType* isaFunction(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<LLFunctionType>(v->getType());
|
|
}
|
|
|
|
const LLFunctionType* isaFunction(const LLType* t)
|
|
{
|
|
return llvm::dyn_cast<LLFunctionType>(t);
|
|
}
|
|
|
|
LLConstant* isaConstant(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<llvm::Constant>(v);
|
|
}
|
|
|
|
llvm::ConstantInt* isaConstantInt(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<llvm::ConstantInt>(v);
|
|
}
|
|
|
|
llvm::Argument* isaArgument(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<llvm::Argument>(v);
|
|
}
|
|
|
|
llvm::GlobalVariable* isaGlobalVar(LLValue* v)
|
|
{
|
|
return llvm::dyn_cast<llvm::GlobalVariable>(v);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLPointerType* getPtrToType(const LLType* t)
|
|
{
|
|
if (t == LLType::VoidTy)
|
|
t = LLType::Int8Ty;
|
|
return LLPointerType::get(t, 0);
|
|
}
|
|
|
|
const LLPointerType* getVoidPtrType()
|
|
{
|
|
return getPtrToType(LLType::Int8Ty);
|
|
}
|
|
|
|
llvm::ConstantPointerNull* getNullPtr(const LLType* t)
|
|
{
|
|
const LLPointerType* pt = llvm::cast<LLPointerType>(t);
|
|
return llvm::ConstantPointerNull::get(pt);
|
|
}
|
|
|
|
LLConstant* getNullValue(const LLType* t)
|
|
{
|
|
return LLConstant::getNullValue(t);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t getTypeBitSize(const LLType* t)
|
|
{
|
|
return gTargetData->getTypeSizeInBits(t);
|
|
}
|
|
|
|
size_t getTypeStoreSize(const LLType* t)
|
|
{
|
|
return gTargetData->getTypeStoreSize(t);
|
|
}
|
|
|
|
size_t getTypePaddedSize(const LLType* t)
|
|
{
|
|
size_t sz = gTargetData->getTypePaddedSize(t);
|
|
//Logger::cout() << "abi type size of: " << *t << " == " << sz << '\n';
|
|
return sz;
|
|
}
|
|
|
|
unsigned char getABITypeAlign(const LLType* t)
|
|
{
|
|
return gTargetData->getABITypeAlignment(t);
|
|
}
|
|
|
|
unsigned char getPrefTypeAlign(const LLType* t)
|
|
{
|
|
return gTargetData->getPrefTypeAlignment(t);
|
|
}
|
|
|
|
const LLType* getBiggestType(const LLType** begin, size_t n)
|
|
{
|
|
const LLType* bigTy = 0;
|
|
size_t bigSize = 0;
|
|
size_t bigAlign = 0;
|
|
|
|
const LLType** end = begin+n;
|
|
while (begin != end)
|
|
{
|
|
const LLType* T = *begin;
|
|
|
|
size_t sz = getTypePaddedSize(T);
|
|
size_t ali = getABITypeAlign(T);
|
|
if (sz > bigSize || (sz == bigSize && ali > bigAlign))
|
|
{
|
|
bigTy = T;
|
|
bigSize = sz;
|
|
bigAlign = ali;
|
|
}
|
|
|
|
++begin;
|
|
}
|
|
|
|
// will be null for n==0
|
|
return bigTy;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLStructType* DtoInterfaceInfoType()
|
|
{
|
|
if (gIR->interfaceInfoType)
|
|
return gIR->interfaceInfoType;
|
|
|
|
// build interface info type
|
|
std::vector<const LLType*> types;
|
|
// ClassInfo classinfo
|
|
ClassDeclaration* cd2 = ClassDeclaration::classinfo;
|
|
DtoResolveClass(cd2);
|
|
types.push_back(getPtrToType(cd2->type->ir.type->get()));
|
|
// void*[] vtbl
|
|
std::vector<const LLType*> vtbltypes;
|
|
vtbltypes.push_back(DtoSize_t());
|
|
const LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::Int8Ty));
|
|
vtbltypes.push_back(byteptrptrty);
|
|
types.push_back(LLStructType::get(vtbltypes));
|
|
// int offset
|
|
types.push_back(LLType::Int32Ty);
|
|
// create type
|
|
gIR->interfaceInfoType = LLStructType::get(types);
|
|
|
|
return gIR->interfaceInfoType;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLStructType* DtoMutexType()
|
|
{
|
|
if (gIR->mutexType)
|
|
return gIR->mutexType;
|
|
|
|
// win32
|
|
if (global.params.os == OSWindows)
|
|
{
|
|
// CRITICAL_SECTION.sizeof == 68
|
|
std::vector<const LLType*> types(17, LLType::Int32Ty);
|
|
return LLStructType::get(types);
|
|
}
|
|
|
|
// FreeBSD
|
|
else if (global.params.os == OSFreeBSD) {
|
|
// Just a pointer
|
|
return LLStructType::get(DtoSize_t(), NULL);
|
|
}
|
|
|
|
// pthread_fastlock
|
|
std::vector<const LLType*> types2;
|
|
types2.push_back(DtoSize_t());
|
|
types2.push_back(LLType::Int32Ty);
|
|
const LLStructType* fastlock = LLStructType::get(types2);
|
|
|
|
// pthread_mutex
|
|
std::vector<const LLType*> types1;
|
|
types1.push_back(LLType::Int32Ty);
|
|
types1.push_back(LLType::Int32Ty);
|
|
types1.push_back(getVoidPtrType());
|
|
types1.push_back(LLType::Int32Ty);
|
|
types1.push_back(fastlock);
|
|
const LLStructType* pmutex = LLStructType::get(types1);
|
|
|
|
// D_CRITICAL_SECTION
|
|
LLOpaqueType* opaque = LLOpaqueType::get();
|
|
std::vector<const LLType*> types;
|
|
types.push_back(getPtrToType(opaque));
|
|
types.push_back(pmutex);
|
|
|
|
// resolve type
|
|
pmutex = LLStructType::get(types);
|
|
LLPATypeHolder pa(pmutex);
|
|
opaque->refineAbstractTypeTo(pa.get());
|
|
pmutex = isaStruct(pa.get());
|
|
|
|
gIR->mutexType = pmutex;
|
|
gIR->module->addTypeName("D_CRITICAL_SECTION", pmutex);
|
|
return pmutex;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const LLStructType* DtoModuleReferenceType()
|
|
{
|
|
if (gIR->moduleRefType)
|
|
return gIR->moduleRefType;
|
|
|
|
// this is a recursive type so start out with the opaque
|
|
LLOpaqueType* opaque = LLOpaqueType::get();
|
|
|
|
// add members
|
|
std::vector<const LLType*> types;
|
|
types.push_back(getPtrToType(opaque));
|
|
types.push_back(DtoType(Module::moduleinfo->type));
|
|
|
|
// resolve type
|
|
const LLStructType* st = LLStructType::get(types);
|
|
LLPATypeHolder pa(st);
|
|
opaque->refineAbstractTypeTo(pa.get());
|
|
st = isaStruct(pa.get());
|
|
|
|
// done
|
|
gIR->moduleRefType = st;
|
|
gIR->module->addTypeName("ModuleReference", st);
|
|
return st;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLValue* DtoAggrPair(const LLType* type, LLValue* V1, LLValue* V2, const char* name)
|
|
{
|
|
LLValue* res = llvm::UndefValue::get(type);
|
|
res = gIR->ir->CreateInsertValue(res, V1, 0, "tmp");
|
|
return gIR->ir->CreateInsertValue(res, V2, 1, name?name:"tmp");
|
|
}
|
|
|
|
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name)
|
|
{
|
|
const LLType* t = LLStructType::get(V1->getType(), V2->getType(), NULL);
|
|
return DtoAggrPair(t, V1, V2, name);
|
|
}
|
|
|
|
LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as)
|
|
{
|
|
if (aggr->getType() == as)
|
|
return aggr;
|
|
|
|
LLValue* res = llvm::UndefValue::get(as);
|
|
|
|
LLValue* V = gIR->ir->CreateExtractValue(aggr, 0, "tmp");;
|
|
V = DtoBitCast(V, as->getContainedType(0));
|
|
res = gIR->ir->CreateInsertValue(res, V, 0, "tmp");
|
|
|
|
V = gIR->ir->CreateExtractValue(aggr, 1, "tmp");;
|
|
V = DtoBitCast(V, as->getContainedType(1));
|
|
return gIR->ir->CreateInsertValue(res, V, 1, "tmp");
|
|
}
|
|
|
|
LLValue* DtoAggrPairSwap(LLValue* aggr)
|
|
{
|
|
Logger::println("swapping aggr pair");
|
|
LLValue* r = gIR->ir->CreateExtractValue(aggr, 0);
|
|
LLValue* i = gIR->ir->CreateExtractValue(aggr, 1);
|
|
return DtoAggrPair(i, r, "swapped");
|
|
}
|