void DtoMemSet(LLValue* dst, LLValue* val, LLValue* nbytes) { dst = DtoBitCast(dst,getVoidPtrType()); LLType* intTy = DtoSize_t(); LLType *VoidPtrTy = getVoidPtrType(); LLType *Tys[2] ={VoidPtrTy, intTy}; llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, llvm::Intrinsic::memset, llvm::makeArrayRef(Tys, 2)); gIR->ir->CreateCall5(fn, dst, val, nbytes, DtoConstUint(1), DtoConstBool(false), ""); }
void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes, unsigned align) { dst = DtoBitCast(dst,getVoidPtrType()); src = DtoBitCast(src,getVoidPtrType()); LLType* intTy = DtoSize_t(); LLType *VoidPtrTy = getVoidPtrType(); LLType *Tys[3] ={VoidPtrTy, VoidPtrTy, intTy}; llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, llvm::Intrinsic::memcpy, llvm::makeArrayRef(Tys, 3)); gIR->ir->CreateCall5(fn, dst, src, nbytes, DtoConstUint(align), DtoConstBool(false), ""); }
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->CreateCall(fn, {lhs, rhs, nbytes}); }
llvm::Type * IrTypeArray::array2llvm(Type * t) { assert(t->ty == Tarray && "not dynamic array type"); // get .ptr type LLType* elemType = DtoType(t->nextOf()); if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext())) elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); elemType = llvm::PointerType::get(elemType, 0); // create struct type llvm::SmallVector<LLType*, 2> types; types.push_back(DtoSize_t()); types.push_back(elemType); LLType* at = llvm::StructType::get(llvm::getGlobalContext(), types/*, t->toChars()*/); return at; }
IrTypeArray* IrTypeArray::get(Type* dt) { assert(!dt->ctype); assert(dt->ty == Tarray && "not dynamic array type"); LLType* elemType = i1ToI8(voidToI8(DtoType(dt->nextOf()))); // Could have already built the type as part of a struct forward reference, // just as for pointers. if (!dt->ctype) { llvm::Type *types[] = { DtoSize_t(), llvm::PointerType::get(elemType, 0) }; LLType* at = llvm::StructType::get(llvm::getGlobalContext(), types, false); dt->ctype = new IrTypeArray(dt, at); } return dt->ctype->isArray(); }
IrTypeArray* IrTypeArray::get(Type* dt) { assert(!dt->irtype); assert(dt->ty == Tarray && "not dynamic array type"); LLType* elemType = DtoTypeNotVoid(dt->nextOf()); // Could have already built the type as part of a struct forward reference, // just as for pointers. if (!dt->irtype) { llvm::SmallVector<LLType*, 2> types; types.push_back(DtoSize_t()); types.push_back(llvm::PointerType::get(elemType, 0)); LLType* at = llvm::StructType::get(llvm::getGlobalContext(), types/*, t->toChars()*/); dt->irtype = new IrTypeArray(dt, at); } return dt->irtype->isArray(); }
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<LLType*> params(3); params[0] = getVoidPtrType(); params[1] = getVoidPtrType(); params[2] = DtoSize_t(); LLFunctionType* fty = LLFunctionType::get(LLType::getInt32Ty(gIR->context()), 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 emitCoverageLinecountInc(Loc &loc) { // Only emit coverage increment for locations in the source of the current // module // (for example, 'inlined' methods from other source files should be skipped). if (!global.params.cov || !loc.linnum || !loc.filename || strcmp(gIR->dmodule->srcfile->name->toChars(), loc.filename) != 0) { return; } const unsigned line = loc.linnum - 1; // convert to 0-based line# index assert(line < gIR->dmodule->numlines); IF_LOG Logger::println("Coverage: increment _d_cover_data[%d]", line); LOG_SCOPE; // Get GEP into _d_cover_data array LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(line)}; LLValue *ptr = llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 LLArrayType::get(LLType::getInt32Ty(gIR->context()), gIR->dmodule->numlines), #endif gIR->dmodule->d_cover_data, idxs, true); // Do an atomic increment, so this works when multiple threads are executed. gIR->ir->CreateAtomicRMW(llvm::AtomicRMWInst::Add, ptr, DtoConstUint(1), #if LDC_LLVM_VER >= 309 llvm::AtomicOrdering::Monotonic #else llvm::Monotonic #endif ); unsigned num_sizet_bits = gDataLayout->getTypeSizeInBits(DtoSize_t()); unsigned idx = line / num_sizet_bits; unsigned bitidx = line % num_sizet_bits; IF_LOG Logger::println("_d_cover_valid[%d] |= (1 << %d)", idx, bitidx); gIR->dmodule->d_cover_valid_init[idx] |= (size_t(1) << bitidx); }
DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { Type *lhsType = lhs->type->toBasetype(); Type *rhsType = rhs->type->toBasetype(); if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { Logger::println("Subtracting integer from pointer"); return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs); } auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) { LLValue *l = DtoRVal(rvals.lhs); LLValue *r = DtoRVal(rvals.rhs); LLType *llSizeT = DtoSize_t(); l = gIR->ir->CreatePtrToInt(l, llSizeT); r = gIR->ir->CreatePtrToInt(r, llSizeT); LLValue *diff = gIR->ir->CreateSub(l, r); LLType *llType = DtoType(type); if (diff->getType() != llType) diff = gIR->ir->CreateIntToPtr(diff, llType); return new DImValue(type, diff); } if (type->ty == Tnull) return DtoNullValue(type, loc); if (type->iscomplex()) return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); if (auto aa = isAssociativeArrayAndNull(type, l, r)) return aa; LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r) : gIR->ir->CreateSub(l, r)); return new DImValue(type, res); }
LLStructType* DtoInterfaceInfoType() { if (gIR->interfaceInfoType) return gIR->interfaceInfoType; // build interface info type LLSmallVector<LLType*, 3> types; // ClassInfo classinfo ClassDeclaration* cd2 = ClassDeclaration::classinfo; 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; }
llvm::ConstantInt* DtoConstSize_t(uint64_t i) { return LLConstantInt::get(DtoSize_t(), i, false); }
DValue* DtoCastClass(Loc& loc, DValue* val, Type* _to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars()); LOG_SCOPE; Type* to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType* tolltype = DtoType(_to); LLValue* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } // class -> bool else if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue* llval = val->getRVal(); LLValue* zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer else if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue* v = val->getRVal(); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // must be class/interface assert(to->ty == Tclass); TypeClass* tc = static_cast<TypeClass*>(to); // from type Type* from = val->getType()->toBasetype(); TypeClass* fc = static_cast<TypeClass*>(from); // x -> interface if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) { Logger::println("to interface"); // interface -> interface if (fc->sym->isInterfaceDeclaration()) { Logger::println("from interface"); return DtoDynamicCastInterface(loc, val, _to); } // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrTypeClass* typeclass = stripModifiers(fc)->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL && "requesting interface that is not implemented by this class"); // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; v = DtoGEPi(v, 0, i_index); LLType* ifType = DtoType(_to); IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); // return r-value return new DImValue(_to, v); }
static void buildRuntimeModule() { Logger::println("building runtime module"); M = new llvm::Module("ldc internal runtime", gIR->context()); Type *voidTy = Type::tvoid; Type *boolTy = Type::tbool; Type *ubyteTy = Type::tuns8; Type *intTy = Type::tint32; Type *uintTy = Type::tuns32; Type *ulongTy = Type::tuns64; Type *sizeTy = Type::tsize_t; Type *dcharTy = Type::tdchar; Type *voidPtrTy = Type::tvoidptr; Type *voidArrayTy = Type::tvoid->arrayOf(); Type *voidArrayPtrTy = voidArrayTy->pointerTo(); Type *stringTy = Type::tchar->arrayOf(); Type *wstringTy = Type::twchar->arrayOf(); Type *dstringTy = Type::tdchar->arrayOf(); // Ensure that the declarations exist before creating llvm types for them. ensureDecl(ClassDeclaration::object, "Object"); ensureDecl(Type::typeinfoclass, "TypeInfo_Class"); ensureDecl(Type::dtypeinfo, "DTypeInfo"); ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray"); ensureDecl(Module::moduleinfo, "ModuleInfo"); Type *objectTy = ClassDeclaration::object->type; Type *classInfoTy = Type::typeinfoclass->type; Type *typeInfoTy = Type::dtypeinfo->type; Type *aaTypeInfoTy = Type::typeinfoassociativearray->type; Type *moduleInfoPtrTy = Module::moduleinfo->type->pointerTo(); // The AA type is a struct that only contains a ptr Type *aaTy = voidPtrTy; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Construct some attribute lists used below (possibly multiple times) AttrSet NoAttrs, Attr_NoAlias(NoAttrs, 0, llvm::Attribute::NoAlias), Attr_NoUnwind(NoAttrs, ~0U, llvm::Attribute::NoUnwind), Attr_ReadOnly(NoAttrs, ~0U, llvm::Attribute::ReadOnly), Attr_ReadOnly_NoUnwind(Attr_ReadOnly, ~0U, llvm::Attribute::NoUnwind), Attr_ReadOnly_1_NoCapture(Attr_ReadOnly, 1, llvm::Attribute::NoCapture), Attr_ReadOnly_1_3_NoCapture(Attr_ReadOnly_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_ReadOnly_NoUnwind_1_NoCapture(Attr_ReadOnly_1_NoCapture, ~0U, llvm::Attribute::NoUnwind), Attr_ReadNone(NoAttrs, ~0U, llvm::Attribute::ReadNone), Attr_1_NoCapture(NoAttrs, 1, llvm::Attribute::NoCapture), Attr_NoAlias_1_NoCapture(Attr_1_NoCapture, 0, llvm::Attribute::NoAlias), Attr_1_2_NoCapture(Attr_1_NoCapture, 2, llvm::Attribute::NoCapture), Attr_1_3_NoCapture(Attr_1_NoCapture, 3, llvm::Attribute::NoCapture), Attr_1_4_NoCapture(Attr_1_NoCapture, 4, llvm::Attribute::NoCapture); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_assert(string file, uint line) // void _d_arraybounds(string file, uint line) createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"}, {stringTy, uintTy}); // void _d_assert_msg(string msg, string file, uint line) createFwdDecl(LINKc, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy}); // void _d_assertm(immutable(ModuleInfo)* m, uint line) // void _d_array_bounds(immutable(ModuleInfo)* m, uint line) // void _d_switch_error(immutable(ModuleInfo)* m, uint line) createFwdDecl(LINKc, voidTy, {"_d_assertm", "_d_array_bounds", "_d_switch_error"}, {moduleInfoPtrTy, uintTy}, {STCimmutable, 0}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void* _d_allocmemory(size_t sz) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemory"}, {sizeTy}, {}, Attr_NoAlias); // void* _d_allocmemoryT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}, {}, Attr_NoAlias); // void[] _d_newarrayT (const TypeInfo ti, size_t length) // void[] _d_newarrayiT(const TypeInfo ti, size_t length) // void[] _d_newarrayU (const TypeInfo ti, size_t length) createFwdDecl(LINKc, voidArrayTy, {"_d_newarrayT", "_d_newarrayiT", "_d_newarrayU"}, {typeInfoTy, sizeTy}, {STCconst, 0}); // void[] _d_newarraymTX (const TypeInfo ti, size_t[] dims) // void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) createFwdDecl(LINKc, voidArrayTy, {"_d_newarraymTX", "_d_newarraymiTX"}, {typeInfoTy, sizeTy->arrayOf()}, {STCconst, 0}); // void[] _d_arraysetlengthT (const TypeInfo ti, size_t newlength, void[]* p) // void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) createFwdDecl(LINKc, voidArrayTy, {"_d_arraysetlengthT", "_d_arraysetlengthiT"}, {typeInfoTy, sizeTy, voidArrayPtrTy}, {STCconst, 0, 0}); // byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcTX"}, {typeInfoTy, voidArrayTy, sizeTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, STCref, 0}); // void[] _d_arrayappendcd(ref byte[] x, dchar c) // void[] _d_arrayappendwd(ref byte[] x, dchar c) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayappendcd", "_d_arrayappendwd"}, {voidArrayTy, dcharTy}, {STCref, 0}); // byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatT"}, {typeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); // void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs) createFwdDecl(LINKc, voidArrayTy, {"_d_arraycatnTX"}, {typeInfoTy, voidArrayTy->arrayOf()}, {STCconst, 0}); // Object _d_newclass(const ClassInfo ci) createFwdDecl(LINKc, objectTy, {"_d_newclass"}, {classInfoTy}, {STCconst}, Attr_NoAlias); // void* _d_newitemT (TypeInfo ti) // void* _d_newitemiT(TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_newitemT", "_d_newitemiT"}, {typeInfoTy}, {0}, Attr_NoAlias); // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) createFwdDecl(LINKc, voidTy, {"_d_delarray_t"}, {voidArrayPtrTy, Type::typeinfostruct->type}, {0, STCconst}); // void _d_delmemory(void** p) // void _d_delinterface(void** p) createFwdDecl(LINKc, voidTy, {"_d_delmemory", "_d_delinterface"}, {voidPtrTy->pointerTo()}); // void _d_callfinalizer(void* p) createFwdDecl(LINKc, voidTy, {"_d_callfinalizer"}, {voidPtrTy}); // D2: void _d_delclass(Object* p) createFwdDecl(LINKc, voidTy, {"_d_delclass"}, {objectTy->pointerTo()}); // void _d_delstruct(void** p, TypeInfo_Struct inf) createFwdDecl(LINKc, voidTy, {"_d_delstruct"}, {voidPtrTy->pointerTo(), Type::typeinfostruct->type}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // array slice copy when assertions are on! // void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t // srclen) createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"}, {voidPtrTy, sizeTy, voidPtrTy, sizeTy}, {}, Attr_1_3_NoCapture); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // int _aApplycd1(in char[] aa, dg_t dg) // int _aApplyRcd1(in char[] aa, dg_t dg) #define STR_APPLY1(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '1', fname2 = prefix + (b) + '1', \ fname3 = prefix + 'R' + (a) + '1', \ fname4 = prefix + 'R' + (b) + '1'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg1()}); \ } STR_APPLY1(stringTy, "cw", "cd") STR_APPLY1(wstringTy, "wc", "wd") STR_APPLY1(dstringTy, "dc", "dw") #undef STR_APPLY1 // int _aApplycd2(in char[] aa, dg2_t dg) // int _aApplyRcd2(in char[] aa, dg2_t dg) #define STR_APPLY2(TY, a, b) \ { \ const std::string prefix = "_aApply"; \ std::string fname1 = prefix + (a) + '2', fname2 = prefix + (b) + '2', \ fname3 = prefix + 'R' + (a) + '2', \ fname4 = prefix + 'R' + (b) + '2'; \ createFwdDecl(LINKc, sizeTy, {fname1, fname2, fname3, fname4}, \ {TY, rt_dg2()}); \ } STR_APPLY2(stringTy, "cw", "cd") STR_APPLY2(wstringTy, "wc", "wd") STR_APPLY2(dstringTy, "dc", "dw") #undef STR_APPLY2 ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // fixes the length for dynamic array casts // size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz) createFwdDecl(LINKc, sizeTy, {"_d_array_cast_len"}, {sizeTy, sizeTy, sizeTy}, {}, Attr_ReadNone); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) // void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayassign_l", "_d_arrayassign_r"}, {typeInfoTy, voidArrayTy, voidArrayTy, voidPtrTy}); // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) createFwdDecl(LINKc, voidArrayTy, {"_d_arrayctor"}, {typeInfoTy, voidArrayTy, voidArrayTy}); // void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) // void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti) createFwdDecl(LINKc, voidPtrTy, {"_d_arraysetassign", "_d_arraysetctor"}, {voidPtrTy, voidPtrTy, intTy, typeInfoTy}, {}, Attr_NoAlias); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // cast interface // void* _d_interface_cast(void* p, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_interface_cast"}, {voidPtrTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); // dynamic cast // void* _d_dynamic_cast(Object o, ClassInfo c) createFwdDecl(LINKc, voidPtrTy, {"_d_dynamic_cast"}, {objectTy, classInfoTy}, {}, Attr_ReadOnly_NoUnwind); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // char[] _adReverseChar(char[] a) // char[] _adSortChar(char[] a) createFwdDecl(LINKc, stringTy, {"_adReverseChar", "_adSortChar"}, {stringTy}); // wchar[] _adReverseWchar(wchar[] a) // wchar[] _adSortWchar(wchar[] a) createFwdDecl(LINKc, wstringTy, {"_adReverseWchar", "_adSortWchar"}, {wstringTy}); // void[] _adReverse(void[] a, size_t szelem) createFwdDecl(LINKc, wstringTy, {"_adReverse"}, {voidArrayTy, sizeTy}, {}, Attr_NoUnwind); // int _adEq2(void[] a1, void[] a2, TypeInfo ti) // int _adCmp2(void[] a1, void[] a2, TypeInfo ti) createFwdDecl(LINKc, intTy, {"_adEq2", "_adCmp2"}, {voidArrayTy, voidArrayTy, typeInfoTy}, {}, Attr_ReadOnly); // int _adCmpChar(void[] a1, void[] a2) createFwdDecl(LINKc, intTy, {"_adCmpChar"}, {voidArrayTy, voidArrayTy}, {}, Attr_ReadOnly_NoUnwind); // void[] _adSort(void[] a, TypeInfo ti) createFwdDecl(LINKc, voidArrayTy, {"_adSort"}, {voidArrayTy, typeInfoTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // size_t _aaLen(in AA aa) createFwdDecl(LINKc, sizeTy, {"_aaLen"}, {aaTy}, {STCin}, Attr_ReadOnly_NoUnwind_1_NoCapture); // void* _aaGetY(AA* aa, const TypeInfo aati, in size_t valuesize, // in void* pkey) createFwdDecl(LINKc, voidPtrTy, {"_aaGetY"}, {aaTy->pointerTo(), aaTypeInfoTy, sizeTy, voidPtrTy}, {0, STCconst, STCin, STCin}, Attr_1_4_NoCapture); // inout(void)* _aaInX(inout AA aa, in TypeInfo keyti, in void* pkey) // FIXME: "inout" storageclass is not applied to return type createFwdDecl(LINKc, voidPtrTy, {"_aaInX"}, {aaTy, typeInfoTy, voidPtrTy}, {STCin | STCout, STCin, STCin}, Attr_ReadOnly_1_3_NoCapture); // bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey) createFwdDecl(LINKc, boolTy, {"_aaDelX"}, {aaTy, typeInfoTy, voidPtrTy}, {0, STCin, STCin}, Attr_1_3_NoCapture); // inout(void[]) _aaValues(inout AA aa, in size_t keysize, // in size_t valuesize, const TypeInfo tiValueArray) createFwdDecl( LINKc, voidArrayTy, {"_aaValues"}, {aaTy, sizeTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCin, STCconst}, Attr_ReadOnly_1_3_NoCapture); // void* _aaRehash(AA* paa, in TypeInfo keyti) createFwdDecl(LINKc, voidPtrTy, {"_aaRehash"}, {aaTy->pointerTo(), typeInfoTy}, {0, STCin}); // inout(void[]) _aaKeys(inout AA aa, in size_t keysize, // const TypeInfo tiKeyArray) createFwdDecl(LINKc, voidArrayTy, {"_aaKeys"}, {aaTy, sizeTy, typeInfoTy}, {STCin | STCout, STCin, STCconst}, Attr_NoAlias_1_NoCapture); // int _aaApply(AA aa, in size_t keysize, dg_t dg) createFwdDecl(LINKc, intTy, {"_aaApply"}, {aaTy, sizeTy, rt_dg1()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaApply2(AA aa, in size_t keysize, dg2_t dg) createFwdDecl(LINKc, intTy, {"_aaApply2"}, {aaTy, sizeTy, rt_dg2()}, {0, STCin, 0}, Attr_1_NoCapture); // int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2) createFwdDecl(LINKc, intTy, {"_aaEqual"}, {typeInfoTy, aaTy, aaTy}, {STCin, STCin, STCin}, Attr_1_2_NoCapture); // AA _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, // void[] keys, void[] values) createFwdDecl(LINKc, aaTy, {"_d_assocarrayliteralTX"}, {aaTypeInfoTy, voidArrayTy, voidArrayTy}, {STCconst, 0, 0}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _moduleCtor() // void _moduleDtor() createFwdDecl(LINKc, voidTy, {"_moduleCtor", "_moduleDtor"}, {}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void _d_throw_exception(Object e) createFwdDecl(LINKc, voidTy, {"_d_throw_exception"}, {objectTy}); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_switch_string(char[][] table, char[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_string"}, {stringTy->arrayOf(), stringTy}, {}, Attr_ReadOnly); // int _d_switch_ustring(wchar[][] table, wchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_ustring"}, {wstringTy->arrayOf(), wstringTy}, {}, Attr_ReadOnly); // int _d_switch_dstring(dchar[][] table, dchar[] ca) createFwdDecl(LINKc, intTy, {"_d_switch_dstring"}, {dstringTy->arrayOf(), dstringTy}, {}, Attr_ReadOnly); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // int _d_eh_personality(...) { if (global.params.targetTriple.isWindowsMSVCEnvironment()) { // (ptr ExceptionRecord, ptr EstablisherFrame, ptr ContextRecord, // ptr DispatcherContext) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy}); } else if (global.params.targetTriple.getArch() == llvm::Triple::arm) { // (int state, ptr ucb, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, voidPtrTy, voidPtrTy}); } else { // (int ver, int actions, ulong eh_class, ptr eh_info, ptr context) createFwdDecl(LINKc, intTy, {"_d_eh_personality"}, {intTy, intTy, ulongTy, voidPtrTy, voidPtrTy}); } } // void _d_eh_resume_unwind(ptr) createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy}); // Object _d_eh_enter_catch(ptr) createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {}, Attr_NoUnwind); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // void invariant._d_invariant(Object o) createFwdDecl( LINKd, voidTy, {gABI->mangleForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)}, {objectTy}); // void _d_dso_registry(CompilerDSOData* data) llvm::StringRef fname("_d_dso_registry"); LLType *LLvoidTy = LLType::getVoidTy(gIR->context()); LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy)); LLType *moduleInfoPtrPtrTy = getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type))); llvm::StructType *dsoDataTy = llvm::StructType::get(DtoSize_t(), // version LLvoidPtrPtrTy, // slot moduleInfoPtrPtrTy, // _minfo_beg moduleInfoPtrPtrTy, // _minfo_end NULL); llvm::Type *types[] = {getPtrToType(dsoDataTy)}; llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false); llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // extern (C) void _d_cover_register2(string filename, size_t[] valid, // uint[] data, ubyte minPercent) if (global.params.cov) { createFwdDecl(LINKc, voidTy, {"_d_cover_register2"}, {stringTy, sizeTy->arrayOf(), uintTy->arrayOf(), ubyteTy}); } }
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(), _to->toChars()); LOG_SCOPE; Type *to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType *tolltype = DtoType(_to); LLValue *rval = DtoBitCast(DtoRVal(val), tolltype); return new DImValue(_to, rval); } // class -> bool if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue *llval = DtoRVal(val); LLValue *zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue *v = DtoRVal(val); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // class -> typeof(null) if (to->ty == Tnull) { IF_LOG Logger::println("to %s", to->toChars()); return new DImValue(_to, LLConstant::getNullValue(DtoType(_to))); } // must be class/interface assert(to->ty == Tclass); TypeClass *tc = static_cast<TypeClass *>(to); // from type Type *from = val->type->toBasetype(); TypeClass *fc = static_cast<TypeClass *>(from); // copy DMD logic: // if to isBaseOf from with offset: (to ? to + offset : null) // else if from is C++ and to is C++: to // else if from is C++ and to is D: null // else if from is interface: _d_interface_cast(to) // else if from is class: _d_dynamic_cast(to) LLType *toType = DtoType(_to); int offset = 0; if (tc->sym->isBaseOf(fc->sym, &offset)) { Logger::println("static down cast"); // interface types don't cover the full object in case of multiple inheritence // so GEP on the original type is inappropriate // offset pointer LLValue *orig = DtoRVal(val); LLValue *v = orig; if (offset != 0) { v = DtoBitCast(v, getVoidPtrType()); LLValue *off = LLConstantInt::get(LLType::getInt32Ty(gIR->context()), offset); v = gIR->ir->CreateGEP(v, off); } IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *toType << std::endl; } v = DtoBitCast(v, toType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was // null. LLValue *isNull = gIR->ir->CreateICmpEQ( orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(toType), v, ".interface"); // return r-value return new DImValue(_to, v); }
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.os == OSWindows) { 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) std::vector<LLType*> rtl_types; rtl_types.push_back(VoidPtrTy); // Pointer to DebugInfo rtl_types.push_back(Int32Ty); // LockCount rtl_types.push_back(Int32Ty); // RecursionCount rtl_types.push_back(VoidPtrTy); // Handle of OwningThread rtl_types.push_back(VoidPtrTy); // Handle of LockSemaphore rtl_types.push_back(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"); std::vector<LLType*> types; types.push_back(getPtrToType(mutex)); types.push_back(rtl); mutex->setBody(types); // Cache type gIR->mutexType = mutex; return mutex; } // FreeBSD else if (global.params.os == OSFreeBSD) { // Just a pointer return LLStructType::get(gIR->context(), DtoSize_t()); } // pthread_fastlock std::vector<LLType*> types2; types2.push_back(DtoSize_t()); types2.push_back(LLType::getInt32Ty(gIR->context())); LLStructType* fastlock = LLStructType::get(gIR->context(), types2); // pthread_mutex std::vector<LLType*> types1; types1.push_back(LLType::getInt32Ty(gIR->context())); types1.push_back(LLType::getInt32Ty(gIR->context())); types1.push_back(getVoidPtrType()); types1.push_back(LLType::getInt32Ty(gIR->context())); types1.push_back(fastlock); LLStructType* pmutex = LLStructType::get(gIR->context(), types1); // D_CRITICAL_SECTION LLStructType* mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION"); std::vector<LLType*> types; types.push_back(getPtrToType(mutex)); types.push_back(pmutex); mutex->setBody(types); // Cache type gIR->mutexType = mutex; return pmutex; }