mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 02:45:25 +03:00

LP64 defines a C environment with 64bit pointers and char/short/int/long are 8/16/32/64bit. char/short/int/long have defined sizes in D. We need to look only at the pointer size. There are now 64bit environments with 32bit pointers. Examples are x32 in Intel and N32 on MIPS64. For these environments D_LP64 should not defined but the global.param.is64bit is still true. The definition of size_t is also affected. If only 32bit are addressable then size_t should also be a 32bit type. (This is not required by C standard but common practize.) The net result is that not only the definition of D_LP64 must be changed but also DtoSize_t().
889 lines
24 KiB
C++
889 lines
24 KiB
C++
//===-- tollvm.cpp --------------------------------------------------------===//
|
||
//
|
||
// LDC – the LLVM D compiler
|
||
//
|
||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||
// file for details.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "gen/tollvm.h"
|
||
#include "aggregate.h"
|
||
#include "declaration.h"
|
||
#include "dsymbol.h"
|
||
#include "id.h"
|
||
#include "init.h"
|
||
#include "module.h"
|
||
#include "gen/abi.h"
|
||
#include "gen/arrays.h"
|
||
#include "gen/classes.h"
|
||
#include "gen/complex.h"
|
||
#include "gen/dvalue.h"
|
||
#include "gen/functions.h"
|
||
#include "gen/irstate.h"
|
||
#include "gen/linkage.h"
|
||
#include "gen/llvm.h"
|
||
#include "gen/llvmhelpers.h"
|
||
#include "gen/logger.h"
|
||
#include "gen/pragma.h"
|
||
#include "gen/runtime.h"
|
||
#include "gen/structs.h"
|
||
#include "gen/typeinf.h"
|
||
#include "ir/irtype.h"
|
||
#include "ir/irtypeclass.h"
|
||
#include "ir/irtypefunction.h"
|
||
#include "ir/irtypestruct.h"
|
||
|
||
bool DtoIsPassedByRef(Type* type)
|
||
{
|
||
Type* typ = type->toBasetype();
|
||
TY t = typ->ty;
|
||
return (t == Tstruct || t == Tsarray);
|
||
}
|
||
|
||
RET retStyle(TypeFunction *tf)
|
||
{
|
||
bool sret = gABI->returnInArg(tf);
|
||
return sret ? RETstack : RETregs;
|
||
}
|
||
|
||
bool DtoIsReturnInArg(CallExp *ce)
|
||
{
|
||
TypeFunction *tf = static_cast<TypeFunction *>(ce->e1->type->toBasetype());
|
||
if (tf->ty == Tfunction && (!ce->f || ce->f->llvmInternal != LLVMintrinsic))
|
||
return retStyle(tf) == RETstack;
|
||
return false;
|
||
}
|
||
|
||
AttrBuilder::A DtoShouldExtend(Type* type)
|
||
{
|
||
type = type->toBasetype();
|
||
if (type->isintegral())
|
||
{
|
||
switch(type->ty)
|
||
{
|
||
case Tint8:
|
||
case Tint16:
|
||
return LDC_ATTRIBUTE(SExt);
|
||
|
||
case Tuns8:
|
||
case Tuns16:
|
||
return LDC_ATTRIBUTE(ZExt);
|
||
|
||
default:
|
||
// Do not extend.
|
||
break;
|
||
}
|
||
}
|
||
|
||
return LDC_ATTRIBUTE(None);
|
||
}
|
||
|
||
LLType* DtoType(Type* t)
|
||
{
|
||
t = stripModifiers( t );
|
||
|
||
if (t->ctype)
|
||
{
|
||
return t->ctype->getLLType();
|
||
}
|
||
|
||
IF_LOG Logger::println("Building type: %s", t->toChars());
|
||
LOG_SCOPE;
|
||
|
||
assert(t);
|
||
switch (t->ty)
|
||
{
|
||
// basic types
|
||
case Tvoid:
|
||
case Tint8:
|
||
case Tuns8:
|
||
case Tint16:
|
||
case Tuns16:
|
||
case Tint32:
|
||
case Tuns32:
|
||
case Tint64:
|
||
case Tuns64:
|
||
case Tfloat32:
|
||
case Tfloat64:
|
||
case Tfloat80:
|
||
case Timaginary32:
|
||
case Timaginary64:
|
||
case Timaginary80:
|
||
case Tcomplex32:
|
||
case Tcomplex64:
|
||
case Tcomplex80:
|
||
//case Tbit:
|
||
case Tbool:
|
||
case Tchar:
|
||
case Twchar:
|
||
case Tdchar:
|
||
{
|
||
return IrTypeBasic::get(t)->getLLType();
|
||
}
|
||
|
||
// pointers
|
||
case Tnull:
|
||
case Tpointer:
|
||
{
|
||
return IrTypePointer::get(t)->getLLType();
|
||
}
|
||
|
||
// arrays
|
||
case Tarray:
|
||
{
|
||
return IrTypeArray::get(t)->getLLType();
|
||
}
|
||
|
||
case Tsarray:
|
||
{
|
||
return IrTypeSArray::get(t)->getLLType();
|
||
}
|
||
|
||
// aggregates
|
||
case Tstruct:
|
||
{
|
||
TypeStruct* ts = static_cast<TypeStruct*>(t);
|
||
if (ts->sym->type->ctype)
|
||
{
|
||
// This should not happen, but the frontend seems to be buggy. Not
|
||
// sure if this is the best way to handle the situation, but we
|
||
// certainly don't want to override ts->sym->type->ctype.
|
||
IF_LOG Logger::cout() << "Struct with multiple Types detected: " <<
|
||
ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl;
|
||
return ts->sym->type->ctype->getLLType();
|
||
}
|
||
return IrTypeStruct::get(ts->sym)->getLLType();
|
||
}
|
||
case Tclass:
|
||
{
|
||
TypeClass* tc = static_cast<TypeClass*>(t);
|
||
if (tc->sym->type->ctype)
|
||
{
|
||
// See Tstruct case.
|
||
IF_LOG Logger::cout() << "Class with multiple Types detected: " <<
|
||
tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl;
|
||
return tc->sym->type->ctype->getLLType();
|
||
}
|
||
return IrTypeClass::get(tc->sym)->getLLType();
|
||
}
|
||
|
||
// functions
|
||
case Tfunction:
|
||
{
|
||
return IrTypeFunction::get(t)->getLLType();
|
||
}
|
||
|
||
// delegates
|
||
case Tdelegate:
|
||
{
|
||
return IrTypeDelegate::get(t)->getLLType();
|
||
}
|
||
|
||
// typedefs
|
||
// enum
|
||
|
||
// FIXME: maybe just call toBasetype first ?
|
||
case Ttypedef:
|
||
case Tenum:
|
||
{
|
||
Type* bt = t->toBasetype();
|
||
assert(bt);
|
||
return DtoType(bt);
|
||
}
|
||
|
||
// associative arrays
|
||
case Taarray:
|
||
return getVoidPtrType();
|
||
|
||
case Tvector:
|
||
{
|
||
return IrTypeVector::get(t)->getLLType();
|
||
}
|
||
|
||
/*
|
||
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 = static_cast<TypeTuple*>(t);
|
||
return DtoStructTypeFromArguments(ttupl->arguments);
|
||
}
|
||
*/
|
||
|
||
default:
|
||
llvm_unreachable("Unknown class of D Type!");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
/*
|
||
LLType* DtoStructTypeFromArguments(Arguments* arguments)
|
||
{
|
||
if (!arguments)
|
||
return LLType::getVoidTy(gIR->context());
|
||
|
||
std::vector<LLType*> types;
|
||
for (size_t i = 0; i < arguments->dim; i++)
|
||
{
|
||
Argument *arg = (*arguments)[i];
|
||
assert(arg && arg->type);
|
||
|
||
types.push_back(DtoType(arg->type));
|
||
}
|
||
return LLStructType::get(types);
|
||
}
|
||
*/
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLType* voidToI8(LLType* t)
|
||
{
|
||
if (t == LLType::getVoidTy(gIR->context()))
|
||
return LLType::getInt8Ty(gIR->context());
|
||
return t;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLType* i1ToI8(LLType* t)
|
||
{
|
||
if (t == LLType::getInt1Ty(gIR->context()))
|
||
return LLType::getInt8Ty(gIR->context());
|
||
return t;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
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);
|
||
|
||
l = gIR->ir->CreateExtractValue(lhs, 1);
|
||
r = gIR->ir->CreateExtractValue(rhs, 1);
|
||
b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r);
|
||
|
||
LLValue* b = gIR->ir->CreateAnd(b1,b2);
|
||
|
||
if (op == TOKnotequal || op == TOKnotidentity)
|
||
return gIR->ir->CreateNot(b);
|
||
|
||
return b;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
llvm::GlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||
{
|
||
if (DtoIsTemplateInstance(sym))
|
||
return templateLinkage;
|
||
return llvm::GlobalValue::ExternalLinkage;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLIntegerType* DtoSize_t()
|
||
{
|
||
// the type of size_t does not change once set
|
||
static LLIntegerType* t = NULL;
|
||
if (t == NULL)
|
||
t = (global.params.isLP64) ? LLType::getInt64Ty(gIR->context()) : LLType::getInt32Ty(gIR->context());
|
||
return t;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoGEP1(LLValue* ptr, LLValue* i0, const char* var, llvm::BasicBlock* bb)
|
||
{
|
||
LLPointerType* p = isaPointer(ptr);
|
||
assert(p && "GEP expects a pointer type");
|
||
return llvm::GetElementPtrInst::Create(
|
||
#if LDC_LLVM_VER >= 307
|
||
p->getElementType(),
|
||
#endif
|
||
ptr, i0, var, bb ? bb : gIR->scopebb());
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const char* var, llvm::BasicBlock* bb)
|
||
{
|
||
LLPointerType* p = isaPointer(ptr);
|
||
assert(p && "GEP expects a pointer type");
|
||
LLValue* v[] = { i0, i1 };
|
||
return llvm::GetElementPtrInst::Create(
|
||
#if LDC_LLVM_VER >= 307
|
||
p->getElementType(),
|
||
#endif
|
||
ptr, v, var, bb ? bb : gIR->scopebb());
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoGEPi1(LLValue* ptr, unsigned i, const char* var, llvm::BasicBlock* bb)
|
||
{
|
||
LLPointerType* p = isaPointer(ptr);
|
||
assert(p && "GEP expects a pointer type");
|
||
return llvm::GetElementPtrInst::Create(
|
||
#if LDC_LLVM_VER >= 307
|
||
p->getElementType(),
|
||
#endif
|
||
ptr, DtoConstUint(i), var, bb ? bb : gIR->scopebb());
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb)
|
||
{
|
||
LLPointerType* p = isaPointer(ptr);
|
||
assert(p && "GEP expects a pointer type");
|
||
LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) };
|
||
return llvm::GetElementPtrInst::Create(
|
||
#if LDC_LLVM_VER >= 307
|
||
p->getElementType(),
|
||
#endif
|
||
ptr, v, var, bb ? bb : gIR->scopebb());
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLConstant* DtoGEPi(LLConstant* ptr, unsigned i0, unsigned i1)
|
||
{
|
||
LLPointerType* p = isaPointer(ptr);
|
||
assert(p && "GEP expects a pointer type");
|
||
LLValue* v[] = { DtoConstUint(i0), DtoConstUint(i1) };
|
||
return llvm::ConstantExpr::getGetElementPtr(
|
||
#if LDC_LLVM_VER >= 307
|
||
p->getElementType(),
|
||
#endif
|
||
ptr, v, true);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void DtoMemSet(LLValue* dst, LLValue* val, LLValue* nbytes)
|
||
{
|
||
LLType* VoidPtrTy = getVoidPtrType();
|
||
|
||
dst = DtoBitCast(dst, VoidPtrTy);
|
||
|
||
gIR->ir->CreateMemSet(dst, val, nbytes, 1 /*Align*/, false /*isVolatile*/);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void DtoMemSetZero(LLValue* dst, LLValue* nbytes)
|
||
{
|
||
DtoMemSet(dst, DtoConstUbyte(0), nbytes);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes, unsigned align)
|
||
{
|
||
LLType* VoidPtrTy = getVoidPtrType();
|
||
|
||
dst = DtoBitCast(dst, VoidPtrTy);
|
||
src = DtoBitCast(src, VoidPtrTy);
|
||
|
||
gIR->ir->CreateMemCpy(dst, src, nbytes, align, false /*isVolatile*/);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoMemCmp(LLValue* lhs, LLValue* rhs, LLValue* nbytes)
|
||
{
|
||
// int memcmp ( const void * ptr1, const void * ptr2, size_t num );
|
||
|
||
LLType* VoidPtrTy = getVoidPtrType();
|
||
LLFunction* fn = gIR->module->getFunction("memcmp");
|
||
if (!fn)
|
||
{
|
||
LLType* Tys[] = { VoidPtrTy, VoidPtrTy, DtoSize_t() };
|
||
LLFunctionType* fty = LLFunctionType::get(LLType::getInt32Ty(gIR->context()),
|
||
Tys, false);
|
||
fn = LLFunction::Create(fty, LLGlobalValue::ExternalLinkage, "memcmp", gIR->module);
|
||
}
|
||
|
||
lhs = DtoBitCast(lhs, VoidPtrTy);
|
||
rhs = DtoBitCast(rhs, VoidPtrTy);
|
||
|
||
return gIR->ir->CreateCall3(fn, lhs, rhs, nbytes);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
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));
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
llvm::ConstantInt* DtoConstSize_t(uint64_t i)
|
||
{
|
||
return LLConstantInt::get(DtoSize_t(), i, false);
|
||
}
|
||
llvm::ConstantInt* DtoConstUint(unsigned i)
|
||
{
|
||
return LLConstantInt::get(LLType::getInt32Ty(gIR->context()), i, false);
|
||
}
|
||
llvm::ConstantInt* DtoConstInt(int i)
|
||
{
|
||
return LLConstantInt::get(LLType::getInt32Ty(gIR->context()), i, true);
|
||
}
|
||
LLConstant* DtoConstBool(bool b)
|
||
{
|
||
return LLConstantInt::get(LLType::getInt1Ty(gIR->context()), b, false);
|
||
}
|
||
llvm::ConstantInt* DtoConstUbyte(unsigned char i)
|
||
{
|
||
return LLConstantInt::get(LLType::getInt8Ty(gIR->context()), i, false);
|
||
}
|
||
|
||
LLConstant* DtoConstFP(Type* t, longdouble value)
|
||
{
|
||
LLType* llty = DtoType(t);
|
||
assert(llty->isFloatingPointTy());
|
||
|
||
if(llty == LLType::getFloatTy(gIR->context()) || llty == LLType::getDoubleTy(gIR->context()))
|
||
return LLConstantFP::get(llty, value);
|
||
else if(llty == LLType::getX86_FP80Ty(gIR->context())) {
|
||
uint64_t bits[] = { 0, 0 };
|
||
bits[0] = *reinterpret_cast<uint64_t*>(&value);
|
||
bits[1] = *reinterpret_cast<uint16_t*>(reinterpret_cast<uint64_t*>(&value) + 1);
|
||
#if LDC_LLVM_VER >= 303
|
||
return LLConstantFP::get(gIR->context(), APFloat(APFloat::x87DoubleExtended, APInt(80, 2, bits)));
|
||
#else
|
||
return LLConstantFP::get(gIR->context(), APFloat(APInt(80, 2, bits)));
|
||
#endif
|
||
} else if(llty == LLType::getPPC_FP128Ty(gIR->context())) {
|
||
uint64_t bits[] = {0, 0};
|
||
bits[0] = *reinterpret_cast<uint64_t*>(&value);
|
||
bits[1] = *reinterpret_cast<uint16_t*>(reinterpret_cast<uint64_t*>(&value) + 1);
|
||
#if LDC_LLVM_VER >= 303
|
||
return LLConstantFP::get(gIR->context(), APFloat(APFloat::PPCDoubleDouble, APInt(128, 2, bits)));
|
||
#else
|
||
return LLConstantFP::get(gIR->context(), APFloat(APInt(128, 2, bits)));
|
||
#endif
|
||
}
|
||
|
||
llvm_unreachable("Unknown floating point type encountered");
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLConstant* DtoConstString(const char* str)
|
||
{
|
||
llvm::StringRef s(str ? str : "");
|
||
llvm::GlobalVariable* gvar = (gIR->stringLiteral1ByteCache.find(s) ==
|
||
gIR->stringLiteral1ByteCache.end())
|
||
? 0 : gIR->stringLiteral1ByteCache[s];
|
||
if (gvar == 0)
|
||
{
|
||
llvm::Constant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true);
|
||
gvar = new llvm::GlobalVariable(*gIR->module, init->getType(), true,
|
||
llvm::GlobalValue::PrivateLinkage, init, ".str");
|
||
gvar->setUnnamedAddr(true);
|
||
gIR->stringLiteral1ByteCache[s] = gvar;
|
||
}
|
||
LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) };
|
||
return DtoConstSlice(
|
||
DtoConstSize_t(s.size()),
|
||
llvm::ConstantExpr::getGetElementPtr(
|
||
#if LDC_LLVM_VER >= 307
|
||
gvar->getInitializer()->getType(),
|
||
#endif
|
||
gvar, idxs, true),
|
||
Type::tchar->arrayOf()
|
||
);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoLoad(LLValue* src, const char* name)
|
||
{
|
||
// if (Logger::enabled())
|
||
// Logger::cout() << "loading " << *src << '\n';
|
||
llvm::LoadInst* ld = gIR->ir->CreateLoad(src, name);
|
||
//ld->setVolatile(gIR->func()->inVolatile);
|
||
return ld;
|
||
}
|
||
|
||
// Like DtoLoad, but the pointer is guaranteed to be aligned appropriately for the type.
|
||
LLValue* DtoAlignedLoad(LLValue* src, const char* name)
|
||
{
|
||
llvm::LoadInst* ld = gIR->ir->CreateLoad(src, name);
|
||
ld->setAlignment(getABITypeAlign(ld->getType()));
|
||
return ld;
|
||
}
|
||
|
||
|
||
void DtoStore(LLValue* src, LLValue* dst)
|
||
{
|
||
assert(src->getType() != llvm::Type::getInt1Ty(gIR->context()) &&
|
||
"Should store bools as i8 instead of i1.");
|
||
gIR->ir->CreateStore(src,dst);
|
||
}
|
||
|
||
void DtoStoreZextI8(LLValue* src, LLValue* dst)
|
||
{
|
||
if (src->getType() == llvm::Type::getInt1Ty(gIR->context()))
|
||
{
|
||
llvm::Type* i8 = llvm::Type::getInt8Ty(gIR->context());
|
||
assert(dst->getType()->getContainedType(0) == i8);
|
||
src = gIR->ir->CreateZExt(src, i8);
|
||
}
|
||
gIR->ir->CreateStore(src, dst);
|
||
}
|
||
|
||
// Like DtoStore, but the pointer is guaranteed to be aligned appropriately for the type.
|
||
void DtoAlignedStore(LLValue* src, LLValue* dst)
|
||
{
|
||
assert(src->getType() != llvm::Type::getInt1Ty(gIR->context()) &&
|
||
"Should store bools as i8 instead of i1.");
|
||
llvm::StoreInst* st = gIR->ir->CreateStore(src,dst);
|
||
st->setAlignment(getABITypeAlign(src->getType()));
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoBitCast(LLValue* v, LLType* t, const char* name)
|
||
{
|
||
if (v->getType() == t)
|
||
return v;
|
||
assert(!isaStruct(t));
|
||
return gIR->ir->CreateBitCast(v, t, name);
|
||
}
|
||
|
||
LLConstant* DtoBitCast(LLConstant* v, LLType* t)
|
||
{
|
||
if (v->getType() == t)
|
||
return v;
|
||
return llvm::ConstantExpr::getBitCast(v, t);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoInsertValue(LLValue* aggr, LLValue* v, unsigned idx, const char* name)
|
||
{
|
||
return gIR->ir->CreateInsertValue(aggr, v, idx, name);
|
||
}
|
||
|
||
LLValue* DtoExtractValue(LLValue* aggr, unsigned idx, const char* name)
|
||
{
|
||
return gIR->ir->CreateExtractValue(aggr, idx, name);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoInsertElement(LLValue* vec, LLValue* v, LLValue *idx, const char* name)
|
||
{
|
||
return gIR->ir->CreateInsertElement(vec, v, idx, name);
|
||
}
|
||
|
||
LLValue* DtoExtractElement(LLValue* vec, LLValue *idx, const char* name)
|
||
{
|
||
return gIR->ir->CreateExtractElement(vec, idx, name);
|
||
}
|
||
|
||
LLValue* DtoInsertElement(LLValue* vec, LLValue* v, unsigned idx, const char* name)
|
||
{
|
||
return DtoInsertElement(vec, v, DtoConstUint(idx), name);
|
||
}
|
||
|
||
LLValue* DtoExtractElement(LLValue* vec, unsigned idx, const char* name)
|
||
{
|
||
return DtoExtractElement(vec, DtoConstUint(idx), name);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLPointerType* isaPointer(LLValue* v)
|
||
{
|
||
return llvm::dyn_cast<LLPointerType>(v->getType());
|
||
}
|
||
|
||
LLPointerType* isaPointer(LLType* t)
|
||
{
|
||
return llvm::dyn_cast<LLPointerType>(t);
|
||
}
|
||
|
||
LLArrayType* isaArray(LLValue* v)
|
||
{
|
||
return llvm::dyn_cast<LLArrayType>(v->getType());
|
||
}
|
||
|
||
LLArrayType* isaArray(LLType* t)
|
||
{
|
||
return llvm::dyn_cast<LLArrayType>(t);
|
||
}
|
||
|
||
LLStructType* isaStruct(LLValue* v)
|
||
{
|
||
return llvm::dyn_cast<LLStructType>(v->getType());
|
||
}
|
||
|
||
LLStructType* isaStruct(LLType* t)
|
||
{
|
||
return llvm::dyn_cast<LLStructType>(t);
|
||
}
|
||
|
||
LLFunctionType* isaFunction(LLValue* v)
|
||
{
|
||
return llvm::dyn_cast<LLFunctionType>(v->getType());
|
||
}
|
||
|
||
LLFunctionType* isaFunction(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);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLPointerType* getPtrToType(LLType* t)
|
||
{
|
||
if (t == LLType::getVoidTy(gIR->context()))
|
||
t = LLType::getInt8Ty(gIR->context());
|
||
return LLPointerType::get(t, 0);
|
||
}
|
||
|
||
LLPointerType* getVoidPtrType()
|
||
{
|
||
return getPtrToType(LLType::getInt8Ty(gIR->context()));
|
||
}
|
||
|
||
llvm::ConstantPointerNull* getNullPtr(LLType* t)
|
||
{
|
||
LLPointerType* pt = llvm::cast<LLPointerType>(t);
|
||
return llvm::ConstantPointerNull::get(pt);
|
||
}
|
||
|
||
LLConstant* getNullValue(LLType* t)
|
||
{
|
||
return LLConstant::getNullValue(t);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
size_t getTypeBitSize(LLType* t)
|
||
{
|
||
return gDataLayout->getTypeSizeInBits(t);
|
||
}
|
||
|
||
size_t getTypeStoreSize(LLType* t)
|
||
{
|
||
return gDataLayout->getTypeStoreSize(t);
|
||
}
|
||
|
||
size_t getTypePaddedSize(LLType* t)
|
||
{
|
||
size_t sz = gDataLayout->getTypeAllocSize(t);
|
||
//Logger::cout() << "abi type size of: " << *t << " == " << sz << '\n';
|
||
return sz;
|
||
}
|
||
|
||
size_t getTypeAllocSize(LLType* t)
|
||
{
|
||
return gDataLayout->getTypeAllocSize(t);
|
||
}
|
||
|
||
unsigned char getABITypeAlign(LLType* t)
|
||
{
|
||
return gDataLayout->getABITypeAlignment(t);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLStructType* DtoInterfaceInfoType()
|
||
{
|
||
if (gIR->interfaceInfoType)
|
||
return gIR->interfaceInfoType;
|
||
|
||
// build interface info type
|
||
LLSmallVector<LLType*, 3> types;
|
||
// ClassInfo classinfo
|
||
ClassDeclaration* cd2 = Type::typeinfoclass;
|
||
DtoResolveClass(cd2);
|
||
types.push_back(DtoType(cd2->type));
|
||
// void*[] vtbl
|
||
LLSmallVector<LLType*, 2> vtbltypes;
|
||
vtbltypes.push_back(DtoSize_t());
|
||
LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::getInt8Ty(gIR->context())));
|
||
vtbltypes.push_back(byteptrptrty);
|
||
types.push_back(LLStructType::get(gIR->context(), vtbltypes));
|
||
// int offset
|
||
types.push_back(LLType::getInt32Ty(gIR->context()));
|
||
// create type
|
||
gIR->interfaceInfoType = LLStructType::get(gIR->context(), types);
|
||
|
||
return gIR->interfaceInfoType;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLStructType* DtoMutexType()
|
||
{
|
||
if (gIR->mutexType)
|
||
return gIR->mutexType;
|
||
|
||
// The structures defined here must be the same as in druntime/src/rt/critical.c
|
||
|
||
// Windows
|
||
if (global.params.targetTriple.isOSWindows())
|
||
{
|
||
llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(gIR->context());
|
||
llvm::Type *Int32Ty = llvm::Type::getInt32Ty(gIR->context());
|
||
|
||
// Build RTL_CRITICAL_SECTION; size is 24 (32bit) or 40 (64bit)
|
||
LLType *rtl_types[] = {
|
||
VoidPtrTy, // Pointer to DebugInfo
|
||
Int32Ty, // LockCount
|
||
Int32Ty, // RecursionCount
|
||
VoidPtrTy, // Handle of OwningThread
|
||
VoidPtrTy, // Handle of LockSemaphore
|
||
VoidPtrTy // SpinCount
|
||
};
|
||
LLStructType* rtl = LLStructType::create(gIR->context(), rtl_types, "RTL_CRITICAL_SECTION");
|
||
|
||
// Build D_CRITICAL_SECTION; size is 28 (32bit) or 48 (64bit)
|
||
LLStructType *mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION");
|
||
LLType *types[] = { getPtrToType(mutex), rtl };
|
||
mutex->setBody(types);
|
||
|
||
// Cache type
|
||
gIR->mutexType = mutex;
|
||
|
||
return mutex;
|
||
}
|
||
|
||
// FreeBSD
|
||
else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) {
|
||
// Just a pointer
|
||
return LLStructType::get(gIR->context(), DtoSize_t());
|
||
}
|
||
|
||
// pthread_fastlock
|
||
LLType *types2[] = {
|
||
DtoSize_t(),
|
||
LLType::getInt32Ty(gIR->context())
|
||
};
|
||
LLStructType* fastlock = LLStructType::get(gIR->context(), types2, false);
|
||
|
||
// pthread_mutex
|
||
LLType *types1[] = {
|
||
LLType::getInt32Ty(gIR->context()),
|
||
LLType::getInt32Ty(gIR->context()),
|
||
getVoidPtrType(),
|
||
LLType::getInt32Ty(gIR->context()),
|
||
fastlock
|
||
};
|
||
LLStructType* pmutex = LLStructType::get(gIR->context(), types1, false);
|
||
|
||
// D_CRITICAL_SECTION
|
||
LLStructType* mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION");
|
||
LLType *types[] = { getPtrToType(mutex), pmutex };
|
||
mutex->setBody(types);
|
||
|
||
// Cache type
|
||
gIR->mutexType = mutex;
|
||
|
||
return pmutex;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLStructType* DtoModuleReferenceType()
|
||
{
|
||
if (gIR->moduleRefType)
|
||
return gIR->moduleRefType;
|
||
|
||
// this is a recursive type so start out with a struct without body
|
||
LLStructType* st = LLStructType::create(gIR->context(), "ModuleReference");
|
||
|
||
// add members
|
||
LLType *types[] = {
|
||
getPtrToType(st),
|
||
DtoType(Module::moduleinfo->type->pointerTo())
|
||
};
|
||
|
||
// resolve type
|
||
st->setBody(types);
|
||
|
||
// done
|
||
gIR->moduleRefType = st;
|
||
return st;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLValue* DtoAggrPair(LLType* type, LLValue* V1, LLValue* V2, const char* name)
|
||
{
|
||
LLValue* res = llvm::UndefValue::get(type);
|
||
res = gIR->ir->CreateInsertValue(res, V1, 0);
|
||
return gIR->ir->CreateInsertValue(res, V2, 1, name);
|
||
}
|
||
|
||
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name)
|
||
{
|
||
LLType *types[] = { V1->getType(), V2->getType() };
|
||
LLType *t = LLStructType::get(gIR->context(), types, false);
|
||
return DtoAggrPair(t, V1, V2, name);
|
||
}
|
||
|
||
LLValue* DtoAggrPaint(LLValue* aggr, LLType* as)
|
||
{
|
||
if (aggr->getType() == as)
|
||
return aggr;
|
||
|
||
LLValue* res = llvm::UndefValue::get(as);
|
||
|
||
LLValue* V = gIR->ir->CreateExtractValue(aggr, 0);
|
||
V = DtoBitCast(V, as->getContainedType(0));
|
||
res = gIR->ir->CreateInsertValue(res, V, 0);
|
||
|
||
V = gIR->ir->CreateExtractValue(aggr, 1);
|
||
V = DtoBitCast(V, as->getContainedType(1));
|
||
return gIR->ir->CreateInsertValue(res, V, 1);
|
||
}
|