//===-- irtype.cpp --------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irtype.h" #include "dmd/expression.h" #include "dmd/mtype.h" #include "dmd/target.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" // These functions use getGlobalContext() as they are invoked before gIR // is set. IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) { assert(dt && "null D Type"); assert(lt && "null LLVM Type"); assert(!getIrType(dt) && "already has IrType"); } IrFuncTy &IrType::getIrFuncTy() { llvm_unreachable("cannot get IrFuncTy from non lazy/function/delegate"); } ////////////////////////////////////////////////////////////////////////////// IrTypeBasic::IrTypeBasic(Type *dt) : IrType(dt, basic2llvm(dt)) {} IrTypeBasic *IrTypeBasic::get(Type *dt) { auto t = new IrTypeBasic(dt); getIrType(dt) = t; return t; } LLType *IrTypeBasic::getComplexType(llvm::LLVMContext &ctx, LLType *type) { llvm::Type *types[] = {type, type}; return llvm::StructType::get(ctx, types, false); } llvm::Type *IrTypeBasic::basic2llvm(Type *t) { llvm::LLVMContext &ctx = getGlobalContext(); switch (t->ty) { case TY::Tvoid: case TY::Tnoreturn: return llvm::Type::getVoidTy(ctx); case TY::Tint8: case TY::Tuns8: case TY::Tchar: return llvm::Type::getInt8Ty(ctx); case TY::Tint16: case TY::Tuns16: case TY::Twchar: return llvm::Type::getInt16Ty(ctx); case TY::Tint32: case TY::Tuns32: case TY::Tdchar: return llvm::Type::getInt32Ty(ctx); case TY::Tint64: case TY::Tuns64: return llvm::Type::getInt64Ty(ctx); case TY::Tint128: case TY::Tuns128: return llvm::IntegerType::get(ctx, 128); case TY::Tfloat32: case TY::Timaginary32: return llvm::Type::getFloatTy(ctx); case TY::Tfloat64: case TY::Timaginary64: return llvm::Type::getDoubleTy(ctx); case TY::Tfloat80: case TY::Timaginary80: return target.realType; case TY::Tcomplex32: return getComplexType(ctx, llvm::Type::getFloatTy(ctx)); case TY::Tcomplex64: return getComplexType(ctx, llvm::Type::getDoubleTy(ctx)); case TY::Tcomplex80: return getComplexType(ctx, target.realType); case TY::Tbool: return llvm::Type::getInt1Ty(ctx); default: llvm_unreachable("Unknown basic type."); } } ////////////////////////////////////////////////////////////////////////////// IrTypePointer::IrTypePointer(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypePointer *IrTypePointer::get(Type *dt) { assert((dt->ty == TY::Tpointer || dt->ty == TY::Tnull) && "not pointer/null type"); auto &ctype = getIrType(dt); assert(!ctype); unsigned addressSpace = dt->ty == TY::Tpointer && dt->nextOf()->ty == TY::Tfunction ? gDataLayout->getProgramAddressSpace() : 0; auto t = new IrTypePointer(dt, getOpaquePtrType(addressSpace)); ctype = t; return t; } ////////////////////////////////////////////////////////////////////////////// IrTypeSArray::IrTypeSArray(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypeSArray *IrTypeSArray::get(Type *dt) { assert(dt->ty == TY::Tsarray && "not static array type"); auto &ctype = getIrType(dt); assert(!ctype); LLType *elemType = DtoMemType(dt->nextOf()); // We might have already built the type during DtoMemType e.g. as part of a // forward reference in a struct. if (!ctype) { TypeSArray *tsa = static_cast(dt); uint64_t dim = static_cast(tsa->dim->toUInteger()); ctype = new IrTypeSArray(dt, llvm::ArrayType::get(elemType, dim)); } return ctype->isSArray(); } ////////////////////////////////////////////////////////////////////////////// IrTypeArray::IrTypeArray(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypeArray *IrTypeArray::get(Type *dt) { assert(dt->ty == TY::Tarray && "not dynamic array type"); auto &ctype = getIrType(dt); assert(!ctype); llvm::Type *types[] = {DtoSize_t(), getOpaquePtrType()}; LLType *at = llvm::StructType::get(getGlobalContext(), types, false); ctype = new IrTypeArray(dt, at); return ctype->isArray(); } ////////////////////////////////////////////////////////////////////////////// IrTypeVector::IrTypeVector(Type *dt, llvm::Type *lt) : IrType(dt, lt) {} IrTypeVector *IrTypeVector::get(Type *dt) { TypeVector *tv = dt->isTypeVector(); assert(tv && "not vector type"); auto &ctype = getIrType(dt); assert(!ctype); TypeSArray *tsa = tv->basetype->isTypeSArray(); assert(tsa); LLType *elemType = DtoMemType(tsa->next); // Could have already built the type as part of a struct forward reference, // just as for pointers and arrays. if (!ctype) { LLType *lt = llvm::VectorType::get(elemType, tsa->dim->toUInteger(), /*Scalable=*/false); ctype = new IrTypeVector(dt, lt); } return ctype->isVector(); } ////////////////////////////////////////////////////////////////////////////// IrType *&getIrType(Type *t, bool create) { // See remark in DtoType(). assert( (t->ty != TY::Tstruct || t == static_cast(t)->sym->type) && "use sd->type for structs"); assert((t->ty != TY::Tclass || t == static_cast(t)->sym->type) && "use cd->type for classes"); t = stripModifiers(t); if (create) { DtoType(t); assert(t->ctype); } return t->ctype; }