// // Method: visitAllocaInst() // // Description: // This method instruments an alloca instruction so that it is zero'ed out // before any data is loaded from it. // void InitAllocas::visitAllocaInst (AllocaInst & AI) { // // Scan for a place to insert the instruction to initialize the // allocated memory. // Instruction * InsertPt = getInsertionPoint (AI); // // Zero the alloca with a memset. If this is done more efficiently with stores // SelectionDAG will lower it appropriately based on target information. // const DataLayout & TD = AI.getModule()->getDataLayout(); // // Get various types that we'll need. // Type * Int1Type = IntegerType::getInt1Ty(AI.getContext()); Type * Int8Type = IntegerType::getInt8Ty(AI.getContext()); Type * Int32Type = IntegerType::getInt32Ty(AI.getContext()); Type * VoidPtrType = getVoidPtrType (AI.getContext()); Type * AllocType = AI.getAllocatedType(); // // Create a call to memset. // Module * M = AI.getParent()->getParent()->getParent(); Function * Memset = cast<Function>(M->getFunction ("llvm.memset.p0i8.i32")); std::vector<Value *> args; args.push_back (castTo (&AI, VoidPtrType, AI.getName().str(), InsertPt)); args.push_back (ConstantInt::get(Int8Type, 0)); args.push_back (ConstantInt::get(Int32Type,TD.getTypeAllocSize(AllocType))); args.push_back (ConstantInt::get(Int32Type, TD.getABITypeAlignment(AllocType))); args.push_back (ConstantInt::get(Int1Type, 0)); CallInst::Create (Memset, args, "", InsertPt); // // Update statistics. // ++InitedAllocas; return; }
// // Method: doInitialization() // // Description: // Perform module-level initialization before the pass is run. For this // pass, we need to create a function prototype for the GEP check function. // // Inputs: // M - A reference to the LLVM module to modify. // // Return value: // true - This LLVM module has been modified. // bool InsertGEPChecks::doInitialization (Module & M) { // // Create a function prototype for the function that performs incomplete // pointer arithmetic (GEP) checks. // Type * VoidPtrTy = getVoidPtrType (M.getContext()); Constant * F = M.getOrInsertFunction ("boundscheckui", VoidPtrTy, VoidPtrTy, VoidPtrTy, VoidPtrTy, NULL); // // Mark the function as readonly; that will enable it to be hoisted out of // loops by the standard loop optimization passes. // (cast<Function>(F))->addFnAttr (Attribute::ReadOnly); return true; }
IrTypeDelegate* IrTypeDelegate::get(Type* t) { assert(!t->irtype); assert(t->ty == Tdelegate); assert(t->nextOf()->ty == Tfunction); TypeDelegate *dt = (TypeDelegate*)t; if (!dt->irtype) { TypeFunction* tf = static_cast<TypeFunction*>(dt->nextOf()); llvm::Type* ltf = DtoFunctionType(tf, dt->irFty, NULL, Type::tvoid->pointerTo()); llvm::Type *types[] = { getVoidPtrType(), getPtrToType(ltf) }; LLStructType* lt = LLStructType::get(gIR->context(), types, false); dt->irtype = new IrTypeDelegate(dt, lt); } return dt->irtype->isDelegate(); }
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); #if LDC_LLVM_VER >= 307 return gIR->ir->CreateCall(fn, {lhs, rhs, nbytes}); #else return gIR->ir->CreateCall3(fn, lhs, rhs, nbytes); #endif }
std::vector<llvm::Type*> IrTypeClass::buildVtblType(Type* first, Array* vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; std::vector<llvm::Type*> types; types.reserve(vtbl_array->dim); // first comes the classinfo types.push_back(DtoType(first)); // then come the functions ArrayIter<Dsymbol> it(*vtbl_array); it.index = 1; for (; !it.done(); it.next()) { Dsymbol* dsym = it.get(); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d types.push_back(getVoidPtrType()); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "invalid vtbl entry"); IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); types.push_back(DtoType(fd->type->pointerTo())); } return types; }
LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) { Logger::println("indexing struct field %s:", vd->toPrettyChars()); LOG_SCOPE; DtoResolveStruct(sd); // vd must be a field IrField* field = vd->ir.irField; assert(field); // get the start pointer LLType* st = getPtrToType(DtoType(sd->type)); // cast to the formal struct type src = DtoBitCast(src, st); // gep to the index LLValue* val = DtoGEPi(src, 0, field->index); // do we need to offset further? (union area) if (field->unionOffset) { // cast to void* val = DtoBitCast(val, getVoidPtrType()); // offset val = DtoGEPi1(val, field->unionOffset); } // cast it to the right type val = DtoBitCast(val, getPtrToType(i1ToI8(DtoType(vd->type)))); if (Logger::enabled()) Logger::cout() << "value: " << *val << '\n'; return val; }
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 Tint128: case Tuns128: 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: case Treference: { // CALYPSO 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 Tenum: { Type *bt = t->toBasetype(); assert(bt); if (t == bt) { // This is an enum forward reference that is only legal when referenced // through an indirection (e.g. "enum E; void foo(E* p);"). For lack of a // better choice, make the outer indirection a void pointer. return getVoidPtrType()->getContainedType(0); } return DtoType(bt); } // associative arrays case Taarray: return getVoidPtrType(); case Tvector: { return IrTypeVector::get(t)->getLLType(); } default: llvm_unreachable("Unknown class of D Type!"); } return nullptr; }
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { // void **vptr; // monitor_t monitor; // byte[] initializer; // static initialization data // char[] name; // class name // void *[] vtbl; // Interface[] interfaces; // ClassInfo *base; // base class // void *destructor; // void *invariant; // class invariant // uint flags; // void *deallocator; // OffsetTypeInfo[] offTi; // void *defaultConstructor; // version(D_Version2) // immutable(void)* m_RTInfo; // else // TypeInfo typeinfo; // since dmd 1.045 // } Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* cdty = static_cast<TypeClass*>(cd->type); IrStruct* ir = cd->ir.irStruct; assert(ir); ClassDeclaration* cinfo = ClassDeclaration::classinfo; if (cinfo->fields.dim != 12) { error("object.d ClassInfo class is incorrect"); fatal(); } // use the rtti builder RTTIBuilder b(ClassDeclaration::classinfo); LLConstant* c; LLType* voidPtr = getVoidPtrType(); LLType* voidPtrPtr = getPtrToType(voidPtr); // byte[] init if (cd->isInterfaceDeclaration()) { b.push_null_void_array(); } else { LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType(); size_t initsz = getTypePaddedSize(cd_type); b.push_void_array(initsz, ir->getInitSymbol()); } // class name // code from dmd const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } b.push_string(name); // vtbl array if (cd->isInterfaceDeclaration()) { b.push_array(0, getNullValue(voidPtrPtr)); } else { c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); b.push_array(cd->vtbl.dim, c); } // interfaces array b.push(ir->getClassInfoInterfaces()); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) b.push_classinfo(cd->baseClass); else b.push_null(cinfo->type); // destructor if (cd->isInterfaceDeclaration()) b.push_null_vp(); else b.push(build_class_dtor(cd)); // invariant VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]); b.push_funcptr(cd->inv, invVar->type); // uint flags unsigned flags; if (cd->isInterfaceDeclaration()) flags = 4 | cd->isCOMinterface() | 32; else flags = build_classinfo_flags(cd); b.push_uint(flags); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); // offset typeinfo VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]); #if GENERATE_OFFTI if (cd->isInterfaceDeclaration()) b.push_null(offTiVar->type); else b.push(build_offti_array(cd, DtoType(offTiVar->type))); #else // GENERATE_OFFTI b.push_null(offTiVar->type); #endif // GENERATE_OFFTI // default constructor VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); #if DMDV2 // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (cd->getRTInfo) b.push(cd->getRTInfo->toConstElem(gIR)); else if (flags & 2) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers #else // typeinfo - since 1.045 b.push_typeinfo(cd->type); #endif /*size_t n = inits.size(); for (size_t i=0; i<n; ++i) { Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; }*/ // build the initializer LLType *initType = ir->classInfo->getType()->getContainedType(0); LLConstant* finalinit = b.get_constant(isaStruct(initType)); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; // sanity check assert(finalinit->getType() == initType && "__ClassZ initializer does not match the ClassInfo type"); // return initializer return finalinit; }
static void build_dso_registry_calls(std::string moduleMangle, llvm::Constant *thisModuleInfo) { // Build the ModuleInfo reference and bracketing symbols. llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type); // Order is important here: We must create the symbols in the // bracketing sections right before/after the ModuleInfo reference // so that they end up in the correct order in the object file. auto minfoBeg = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_beg"); minfoBeg->setSection(".minfo_beg"); minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility); std::string thismrefname = "_D"; thismrefname += moduleMangle; thismrefname += "11__moduleRefZ"; auto thismref = new llvm::GlobalVariable( gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname); thismref->setSection(".minfo"); gIR->usedArray.push_back(thismref); auto minfoEnd = new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy, false, // FIXME: mRelocModel != llvm::Reloc::PIC_ llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(moduleInfoPtrTy), "_minfo_end"); minfoEnd->setSection(".minfo_end"); minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility); // Build the ctor to invoke _d_dso_registry. // This is the DSO slot for use by the druntime implementation. auto dsoSlot = new llvm::GlobalVariable(gIR->module, getVoidPtrType(), false, llvm::GlobalValue::LinkOnceODRLinkage, getNullPtr(getVoidPtrType()), "ldc.dso_slot"); dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility); // Okay, so the theory is easy: We want to have one global constructor and // destructor per object (i.e. executable/shared library) that calls // _d_dso_registry with the respective DSO record. However, there are a // couple of issues that make this harder than necessary: // // 1) The natural way to implement the "one-per-image" part would be to // emit a weak reference to a weak function into a .ctors.<somename> // section (llvm.global_ctors doesn't support the necessary // functionality, so we'd use our knowledge of the linker script to work // around that). But as of LLVM 3.4, emitting a symbol both as weak and // into a custom section is not supported by the MC layer. Thus, we have // to use a normal ctor/dtor and manually ensure that we only perform // the call once. This is done by introducing ldc.dso_initialized. // // 2) To make sure the .minfo section isn't removed by the linker when // using --gc-sections, we need to keep a reference to it around in // _every_ object file (as --gc-sections works per object file). The // natural place for this is the ctor, where we just load a reference // on the stack after the DSO record (to ensure LLVM doesn't optimize // it out). However, this way, we need to have at least one ctor // instance per object file be pulled into the final executable. We // do this here by making the module mangle string part of its name, // even thoguht this is slightly wasteful on -singleobj builds. // // It might be a better idea to simply use a custom linker script (using // INSERT AFTER… so as to still keep the default one) to avoid all these // problems. This would mean that it is no longer safe to link D objects // directly using e.g. "g++ dcode.o cppcode.o", though. auto dsoInitialized = new llvm::GlobalVariable( gIR->module, llvm::Type::getInt8Ty(gIR->context()), false, llvm::GlobalValue::LinkOnceODRLinkage, llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0), "ldc.dso_initialized"); dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility); // There is no reason for this cast to void*, other than that removing it // seems to trigger a bug in the llvm::Linker (at least on LLVM 3.4) // causing it to not merge the %object.ModuleInfo types properly. This // manifests itself in a type mismatch assertion being triggered on the // minfoUsedPointer store in the ctor as soon as the optimizer runs. llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType()); std::string ctorName = "ldc.dso_ctor."; ctorName += moduleMangle; llvm::Function *dsoCtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, ctorName, &gIR->module); dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoCtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, false); llvm::appendToGlobalCtors(gIR->module, dsoCtor, 65535); std::string dtorName = "ldc.dso_dtor."; dtorName += moduleMangle; llvm::Function *dsoDtor = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false), llvm::GlobalValue::LinkOnceODRLinkage, dtorName, &gIR->module); dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility); build_dso_ctor_dtor_body(dsoDtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd, minfoRefPtr, true); llvm::appendToGlobalDtors(gIR->module, dsoDtor, 65535); }
llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index) { ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base); if (it != interfaceVtblMap.end()) return it->second; IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", b->base->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not a class aggregate"); FuncDeclarations vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); std::vector<llvm::Constant*> constants; constants.reserve(vtbl_array.dim); if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces // start with the interface info VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); // index into the interfaces array llvm::Constant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(interfaces_index) }; llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr( getInterfaceArraySymbol(), idxs, true); constants.push_back(c); } // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = b->base->vtblOffset(); i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d constants.push_back(getNullValue(getVoidPtrType())); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); LLFunction *fn = fd->ir.irFunc->func; // If the base is a cpp interface, 'this' parameter is a pointer to // the interface not the underlying object as expected. Instead of // the function, we place into the vtable a small wrapper, called thunk, // that casts 'this' to the object and then pass it to the real function. if (b->base->isCPPinterface()) { TypeFunction *f = (TypeFunction*)fd->type->toBasetype(); assert(f->fty.arg_this); // create the thunk function OutBuffer name; name.writestring("Th"); name.printf("%i", b->offset); name.writestring(fd->mangle()); LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)), DtoLinkage(fd), name.toChars(), gIR->module); // create entry and end blocks llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "entry", thunk); llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", thunk); gIR->scopes.push_back(IRScope(beginbb, endbb)); // copy the function parameters, so later we can pass them to the real function std::vector<LLValue*> args; llvm::Function::arg_iterator iarg = thunk->arg_begin(); for (; iarg != thunk->arg_end(); ++iarg) args.push_back(iarg); // cast 'this' to Object LLValue* &thisArg = args[(f->fty.arg_sret == 0) ? 0 : 1]; LLType* thisType = thisArg->getType(); thisArg = DtoBitCast(thisArg, getVoidPtrType()); thisArg = DtoGEP1(thisArg, DtoConstInt(-b->offset)); thisArg = DtoBitCast(thisArg, thisType); // call the real vtbl function. LLValue *retVal = gIR->ir->CreateCall(fn, args); // return from the thunk if (thunk->getReturnType() == LLType::getVoidTy(gIR->context())) llvm::ReturnInst::Create(gIR->context(), beginbb); else llvm::ReturnInst::Create(gIR->context(), retVal, beginbb); // clean up gIR->scopes.pop_back(); thunk->getBasicBlockList().pop_back(); fn = thunk; } constants.push_back(fn); } // build the vtbl constant llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); // create the global variable to hold it llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); std::string mangle("_D"); mangle.append(cd->mangle()); mangle.append("11__interface"); mangle.append(b->base->mangle()); mangle.append("6__vtblZ"); llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc, *gIR->module, vtbl_constant->getType(), true, _linkage, vtbl_constant, mangle ); // insert into the vtbl map interfaceVtblMap.insert(std::make_pair(b->base, GV)); return GV; }
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); }
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) { Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); LOG_SCOPE; //////////////////////////////////// // Locate context value Dsymbol* vdparent = vd->toParent2(); assert(vdparent); IrFunction* irfunc = gIR->func(); // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; while (fd != vdparent) { if (fd->isStatic()) { error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype)))); } fd = getParentFunc(fd, false); assert(fd); } // is the nested variable in this scope? if (vdparent == irfunc->decl) { LLValue* val = vd->ir.getIrValue(); return new DVarValue(astype, vd, val); } LLValue *dwarfValue = 0; std::vector<LLValue*> dwarfAddr; LLType *int64Ty = LLType::getInt64Ty(gIR->context()); // get the nested context LLValue* ctx = 0; if (irfunc->decl->isMember2()) { #if DMDV2 AggregateDeclaration* cd = irfunc->decl->isMember2(); LLValue* val = irfunc->thisArg; if (cd->isClassDeclaration()) val = DtoLoad(val); #else ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); LLValue* val = DtoLoad(irfunc->thisArg); #endif ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } else if (irfunc->nestedVar) { ctx = irfunc->nestedVar; dwarfValue = ctx; } else { ctx = DtoLoad(irfunc->nestArg); dwarfValue = irfunc->nestArg; if (global.params.symdebug) dwarfOpDeref(dwarfAddr); } assert(ctx); DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(vd->ir.irLocal); //////////////////////////////////// // Extract variable from nested context if (nestedCtx == NCArray) { LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); val = DtoAlignedLoad(val); assert(vd->ir.irLocal->value); val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); return new DVarValue(astype, vd, val); } else if (nestedCtx == NCHybrid) { LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); Logger::cout() << "Context: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned funcdepth = irfunc->depth; Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n'; if (vardepth == funcdepth) { // This is not always handled above because functions without // variables accessed by nested functions don't create new frames. Logger::println("Same depth"); } else { // Load frame pointer and index that... if (dwarfValue && global.params.symdebug) { dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); dwarfOpDeref(dwarfAddr); } Logger::println("Lower depth"); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); Logger::cout() << "Frame index: " << *val << '\n'; val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); Logger::cout() << "Frame: " << *val << '\n'; } if (dwarfValue && global.params.symdebug) dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; if (vd->ir.irLocal->byref || byref) { val = DtoAlignedLoad(val); //dwarfOpDeref(dwarfAddr); Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } if (dwarfValue && global.params.symdebug) DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); return new DVarValue(astype, vd, val); } else { assert(0 && "Not implemented yet"); } }
llvm::BasicBlock *ScopeStack::emitLandingPad() { // save and rewrite scope IRScope savedIRScope = irs->scope(); llvm::BasicBlock *beginBB = llvm::BasicBlock::Create(irs->context(), "landingPad", irs->topfunc()); irs->scope() = IRScope(beginBB); llvm::LandingPadInst *landingPad = createLandingPadInst(irs); // Stash away the exception object pointer and selector value into their // stack slots. llvm::Value *ehPtr = DtoExtractValue(landingPad, 0); irs->ir->CreateStore(ehPtr, irs->func()->getOrCreateEhPtrSlot()); llvm::Value *ehSelector = DtoExtractValue(landingPad, 1); if (!irs->func()->ehSelectorSlot) { irs->func()->ehSelectorSlot = DtoRawAlloca(ehSelector->getType(), 0, "eh.selector"); } irs->ir->CreateStore(ehSelector, irs->func()->ehSelectorSlot); // Add landingpad clauses, emit finallys and 'if' chain to catch the // exception. CleanupCursor lastCleanup = currentCleanupScope(); for (auto it = catchScopes.rbegin(), end = catchScopes.rend(); it != end; ++it) { // Insert any cleanups in between the last catch we ran (i.e. tested for // and found that the type does not match) and this one. assert(lastCleanup >= it->cleanupScope); if (lastCleanup > it->cleanupScope) { landingPad->setCleanup(true); llvm::BasicBlock *afterCleanupBB = llvm::BasicBlock::Create( irs->context(), beginBB->getName() + llvm::Twine(".after.cleanup"), irs->topfunc()); runCleanups(lastCleanup, it->cleanupScope, afterCleanupBB); irs->scope() = IRScope(afterCleanupBB); lastCleanup = it->cleanupScope; } // Add the ClassInfo reference to the landingpad instruction so it is // emitted to the EH tables. landingPad->addClause(it->classInfoPtr); llvm::BasicBlock *mismatchBB = llvm::BasicBlock::Create( irs->context(), beginBB->getName() + llvm::Twine(".mismatch"), irs->topfunc()); // "Call" llvm.eh.typeid.for, which gives us the eh selector value to // compare the landing pad selector value with. llvm::Value *ehTypeId = irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for), DtoBitCast(it->classInfoPtr, getVoidPtrType())); // Compare the selector value from the unwinder against the expected // one and branch accordingly. irs->ir->CreateCondBr( irs->ir->CreateICmpEQ(irs->ir->CreateLoad(irs->func()->ehSelectorSlot), ehTypeId), it->bodyBlock, mismatchBB); irs->scope() = IRScope(mismatchBB); } // No catch matched. Execute all finallys and resume unwinding. if (lastCleanup > 0) { landingPad->setCleanup(true); runCleanups(lastCleanup, 0, irs->func()->getOrCreateResumeUnwindBlock()); } else if (!catchScopes.empty()) { // Directly convert the last mismatch branch into a branch to the // unwind resume block. irs->scopebb()->replaceAllUsesWith( irs->func()->getOrCreateResumeUnwindBlock()); irs->scopebb()->eraseFromParent(); } else { irs->ir->CreateBr(irs->func()->getOrCreateResumeUnwindBlock()); } irs->scope() = savedIRScope; return beginBB; }
llvm::BasicBlock * TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope, llvm::BasicBlock *unwindTo) { // a catch switch never needs to be cloned and is an unwind target itself if (isCatchSwitchBlock(cleanupScopes[scope].beginBlock())) return cleanupScopes[scope].beginBlock(); // each cleanup block is bracketed by a pair of cleanuppad/cleanupret // instructions, any unwinding should also just continue at the next // cleanup block, e.g.: // // cleanuppad: // %0 = cleanuppad within %funclet[] // %frame = nullptr // if (!_d_enter_cleanup(%frame)) br label %cleanupret // else br label %copy // // copy: // invoke _dtor to %cleanupret unwind %unwindTo [ "funclet"(token %0) ] // // cleanupret: // _d_leave_cleanup(%frame) // cleanupret %0 unwind %unwindTo // llvm::BasicBlock *cleanupbb = irs.insertBB("cleanuppad"); auto funcletToken = llvm::ConstantTokenNone::get(irs.context()); auto cleanuppad = llvm::CleanupPadInst::Create(funcletToken, {}, "", cleanupbb); llvm::BasicBlock *cleanupret = irs.insertBBAfter(cleanupbb, "cleanupret"); // preparation to allocate some space on the stack where _d_enter_cleanup // can place an exception frame (but not done here) auto frame = getNullPtr(getVoidPtrType()); auto savedInsertBlock = irs.ir->GetInsertBlock(); auto savedInsertPoint = irs.ir->GetInsertPoint(); auto savedDbgLoc = irs.DBuilder.GetCurrentLoc(); auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup"); irs.ir->SetInsertPoint(cleanupret); irs.DBuilder.EmitStopPoint(irs.func()->decl->loc); irs.ir->CreateCall(endFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, ""); llvm::CleanupReturnInst::Create(cleanuppad, unwindTo, cleanupret); auto copybb = cleanupScopes[scope].runCopying(irs, cleanupbb, cleanupret, unwindTo, cleanuppad); auto beginFn = getRuntimeFunction(Loc(), irs.module, "_d_enter_cleanup"); irs.ir->SetInsertPoint(cleanupbb); irs.DBuilder.EmitStopPoint(irs.func()->decl->loc); auto exec = irs.ir->CreateCall( beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, ""); llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb); irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint); irs.DBuilder.EmitStopPoint(savedDbgLoc); return cleanupbb; }
llvm::AllocaInst *TryCatchFinallyScopes::getOrCreateEhPtrSlot() { if (!ehPtrSlot) ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr"); return ehPtrSlot; }
llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { assert(currentCleanupScope() > 0); return emitLandingPadMSVC(currentCleanupScope() - 1); } #endif // save and rewrite scope IRScope savedIRScope = irs.scope(); // insert landing pads at the end of the function, in emission order, // to improve human-readability of the IR llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad"); irs.scope() = IRScope(beginBB); llvm::LandingPadInst *landingPad = createLandingPadInst(irs); // Stash away the exception object pointer and selector value into their // stack slots. llvm::Value *ehPtr = DtoExtractValue(landingPad, 0); irs.ir->CreateStore(ehPtr, getOrCreateEhPtrSlot()); llvm::Value *ehSelector = DtoExtractValue(landingPad, 1); if (!ehSelectorSlot) ehSelectorSlot = DtoRawAlloca(ehSelector->getType(), 0, "eh.selector"); irs.ir->CreateStore(ehSelector, ehSelectorSlot); // Add landingpad clauses, emit finallys and 'if' chain to catch the // exception. CleanupCursor lastCleanup = currentCleanupScope(); for (auto it = tryCatchScopes.rbegin(), end = tryCatchScopes.rend(); it != end; ++it) { const auto &tryCatchScope = *it; // Insert any cleanups in between the previous (inner-more) try-catch scope // and this one. const auto newCleanup = tryCatchScope.getCleanupScope(); assert(lastCleanup >= newCleanup); if (lastCleanup > newCleanup) { landingPad->setCleanup(true); llvm::BasicBlock *afterCleanupBB = irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup")); runCleanups(lastCleanup, newCleanup, afterCleanupBB); irs.scope() = IRScope(afterCleanupBB); lastCleanup = newCleanup; } for (const auto &cb : tryCatchScope.getCatchBlocks()) { // Add the ClassInfo reference to the landingpad instruction so it is // emitted to the EH tables. landingPad->addClause(cb.classInfoPtr); llvm::BasicBlock *mismatchBB = irs.insertBB(beginBB->getName() + llvm::Twine(".mismatch")); // "Call" llvm.eh.typeid.for, which gives us the eh selector value to // compare the landing pad selector value with. llvm::Value *ehTypeId = irs.ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for), DtoBitCast(cb.classInfoPtr, getVoidPtrType())); // Compare the selector value from the unwinder against the expected // one and branch accordingly. irs.ir->CreateCondBr( irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId), cb.bodyBB, mismatchBB, cb.branchWeights); irs.scope() = IRScope(mismatchBB); } } // No catch matched. Execute all finallys and resume unwinding. auto resumeUnwindBlock = getOrCreateResumeUnwindBlock(); if (lastCleanup > 0) { landingPad->setCleanup(true); runCleanups(lastCleanup, 0, resumeUnwindBlock); } else if (!tryCatchScopes.empty()) { // Directly convert the last mismatch branch into a branch to the // unwind resume block. irs.scopebb()->replaceAllUsesWith(resumeUnwindBlock); irs.scopebb()->eraseFromParent(); } else { irs.ir->CreateBr(resumeUnwindBlock); } irs.scope() = savedIRScope; return beginBB; }
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) { assert(catchBlocks.empty()); auto &PGO = irs.funcGen().pgo; const auto entryCount = PGO.setCurrentStmt(stmt); struct CBPrototype { Type *t; llvm::BasicBlock *catchBB; uint64_t catchCount; uint64_t uncaughtCount; }; llvm::SmallVector<CBPrototype, 8> cbPrototypes; cbPrototypes.reserve(stmt->catches->dim); for (auto c : *stmt->catches) { auto catchBB = irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars()); irs.scope() = IRScope(catchBB); irs.DBuilder.EmitBlockStart(c->loc); PGO.emitCounterIncrement(c); bool isCPPclass = false; if (auto lp = c->langPlugin()) // CALYPSO lp->codegen()->toBeginCatch(irs, c); else { const auto cd = c->type->toBasetype()->isClassHandle(); isCPPclass = cd->isCPPclass(); const auto enterCatchFn = getRuntimeFunction( Loc(), irs.module, isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch"); const auto ptr = DtoLoad(ehPtrSlot); const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr); // For catches that use the Throwable object, create storage for it. // We will set it in the code that branches from the landing pads // (there might be more than one) to catchBB. if (c->var) { // This will alloca if we haven't already and take care of nested refs // if there are any. DtoDeclarationExp(c->var); // Copy the exception reference over from the _d_eh_enter_catch return // value. DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)), getIrLocal(c->var)->value); } } // Emit handler, if there is one. The handler is zero, for instance, // when building 'catch { debug foo(); }' in non-debug mode. if (isCPPclass) { // from DMD: /* C++ catches need to end with call to __cxa_end_catch(). * Create: * try { handler } finally { __cxa_end_catch(); } * Note that this is worst case code because it always sets up an * exception handler. At some point should try to do better. */ FuncDeclaration *fdend = FuncDeclaration::genCfunc(nullptr, Type::tvoid, "__cxa_end_catch"); Expression *efunc = VarExp::create(Loc(), fdend); Expression *ecall = CallExp::create(Loc(), efunc); ecall->type = Type::tvoid; Statement *call = ExpStatement::create(Loc(), ecall); Statement *stmt = c->handler ? TryFinallyStatement::create(Loc(), c->handler, call) : call; Statement_toIR(stmt, &irs); } else { if (c->handler) Statement_toIR(c->handler, &irs); } if (!irs.scopereturned()) { // CALYPSO FIXME: _cxa_end_catch won't be called if it has already returned if (auto lp = c->langPlugin()) lp->codegen()->toEndCatch(irs, c); irs.ir->CreateBr(endbb); } irs.DBuilder.EmitBlockEnd(); // PGO information, currently unused auto catchCount = PGO.getRegionCount(c); // uncaughtCount is handled in a separate pass below cbPrototypes.push_back({c->type->toBasetype(), catchBB, catchCount, 0}); // CALYPSO } // Total number of uncaught exceptions is equal to the execution count at // the start of the try block minus the one after the continuation. // uncaughtCount keeps track of the exception type mismatch count while // iterating through the catch block prototypes in reversed order. auto uncaughtCount = entryCount - PGO.getRegionCount(stmt); for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end; ++it) { it->uncaughtCount = uncaughtCount; // Add this catch block's match count to the uncaughtCount, because these // failed to match the remaining (lexically preceding) catch blocks. uncaughtCount += it->catchCount; } catchBlocks.reserve(stmt->catches->dim); auto c_it = stmt->catches->begin(); // CALYPSO for (const auto &p : cbPrototypes) { auto branchWeights = PGO.createProfileWeights(p.catchCount, p.uncaughtCount); LLGlobalVariable *ci; if (auto lp = (*c_it)->langPlugin()) // CALYPSO ci = lp->codegen()->toCatchScopeType(irs, p.t); else { ClassDeclaration *cd = p.t->isClassHandle(); DtoResolveClass(cd); if (cd->isCPPclass()) { const char *name = Target::cppTypeInfoMangle(cd); auto cpp_ti = getOrCreateGlobal( cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true, LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name); // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that // the personality routine may differentiate C++ catch clauses from D ones. OutBuffer mangleBuf; mangleBuf.writestring("_D"); mangleToBuffer(cd, &mangleBuf); mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr"); const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd); RTTIBuilder b(ClassDeclaration::cpp_type_info_ptr); b.push(cpp_ti); auto wrapperType = llvm::cast<llvm::StructType>( static_cast<IrTypeClass*>(ClassDeclaration::cpp_type_info_ptr->type->ctype)->getMemoryLLType()); auto wrapperInit = b.get_constant(wrapperType); ci = getOrCreateGlobal( cd->loc, irs.module, wrapperType, /*isConstant=*/true, LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle); } else { ci = getIrAggr(cd)->getClassInfoSymbol(); } } catchBlocks.push_back({ci, p.catchBB, branchWeights}); c_it++; } }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); const bool isLLConst = isConst() && init; const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string llName(mangle()); // Since the type of a global must exactly match the type of its // initializer, we cannot know the type until after we have emitted the // latter (e.g. in case of unions, …). However, it is legal for the // initializer to refer to the address of the variable. Thus, we first // create a global with the generic type (note the assignment to // this->ir.irGlobal->value!), and in case we also do an initializer // with a different type later, swap it out and replace any existing // uses with bitcasts to the previous type. llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module, i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName, isThreadlocal()); this->ir.irGlobal->value = gvar; // Check if we are defining or just declaring the global in this module. if (!(storage_class & STCextern) && mustDefineSymbol(this)) { // Build the initializer. Might use this->ir.irGlobal->value! LLConstant *initVal = DtoConstInitializer(loc, type, init); // In case of type mismatch, swap out the variable. if (initVal->getType() != gvar->getType()->getElementType()) { llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc, *gIR->module, initVal->getType(), isLLConst, llLinkage, 0, "", // We take on the name of the old global below. isThreadlocal()); newGvar->takeName(gvar); llvm::Constant* newValue = llvm::ConstantExpr::getBitCast(newGvar, gvar->getType()); gvar->replaceAllUsesWith(newValue); gvar->eraseFromParent(); gvar = newGvar; this->ir.irGlobal->value = newGvar; } // Now, set the initializer. assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // Also set up the edbug info. DtoDwarfGlobalVariable(gvar, this); } // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); // If this global is used from a naked function, we need to create an // artificial "use" for it, or it could be removed by the optimizer if // the only reference to it is in inline asm. if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; } }
void RTTIBuilder::push_size_as_vp(uint64_t s) { inits.push_back(llvm::ConstantExpr::getIntToPtr(DtoConstSize_t(s), getVoidPtrType())); }
llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index) { ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base); if (it != interfaceVtblMap.end()) return it->second; IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", b->base->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not a class aggregate"); FuncDeclarations vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); std::vector<llvm::Constant*> constants; constants.reserve(vtbl_array.dim); // start with the interface info VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); // index into the interfaces array llvm::Constant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(interfaces_index) }; llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr( getInterfaceArraySymbol(), idxs, true); constants.push_back(c); // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = 1; i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d constants.push_back(getNullValue(getVoidPtrType())); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); constants.push_back(fd->ir.irFunc->func); } // build the vtbl constant llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); // create the global variable to hold it llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); std::string mangle("_D"); mangle.append(cd->mangle()); mangle.append("11__interface"); mangle.append(b->base->mangle()); mangle.append("6__vtblZ"); llvm::GlobalVariable* GV = new llvm::GlobalVariable( *gIR->module, vtbl_constant->getType(), true, _linkage, vtbl_constant, mangle ); // insert into the vtbl map interfaceVtblMap.insert(std::make_pair(b->base, GV)); return GV; }
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) { Logger::println("DtoNestedContext for %s", sym->toPrettyChars()); LOG_SCOPE; IrFunction* irfunc = gIR->func(); bool fromParent = true; LLValue* val; // if this func has its own vars that are accessed by nested funcs // use its own context if (irfunc->nestedVar) { val = irfunc->nestedVar; fromParent = false; } // otherwise, it may have gotten a context from the caller else if (irfunc->nestArg) val = DtoLoad(irfunc->nestArg); // or just have a this argument else if (irfunc->thisArg) { AggregateDeclaration* ad = irfunc->decl->isMember2(); val = ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg; if (!ad->vthis) { // This is just a plain 'outer' reference of a class nested in a // function (but without any variables in the nested context). return val; } val = DtoLoad(DtoGEPi(val, 0, ad->vthis->ir.irField->index, ".vthis")); } else { // Use null instead of e.g. LLVM's undef to not break bitwise // comparison for instances of nested struct types which don't have any // nested references. return llvm::ConstantPointerNull::get(getVoidPtrType()); } struct FuncDeclaration* fd = 0; if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared. fd = ad->toParent()->isFuncDeclaration(); else if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { // Make sure we've had a chance to analyze nested context usage DtoCreateNestedContextType(symfd); // if this is for a function that doesn't access variables from // enclosing scopes, it doesn't matter what we pass. // Tell LLVM about it by passing an 'undef'. if (symfd && symfd->ir.irFunc->depth == -1) return llvm::UndefValue::get(getVoidPtrType()); // If sym is a nested function, and it's parent context is different than the // one we got, adjust it. fd = getParentFunc(symfd, true); } if (fd) { Logger::println("For nested function, parent is %s", fd->toChars()); FuncDeclaration* ctxfd = irfunc->decl; Logger::println("Current function is %s", ctxfd->toChars()); if (fromParent) { ctxfd = getParentFunc(ctxfd, true); assert(ctxfd && "Context from outer function, but no outer function?"); } Logger::println("Context is from %s", ctxfd->toChars()); unsigned neededDepth = fd->ir.irFunc->depth; unsigned ctxDepth = ctxfd->ir.irFunc->depth; Logger::cout() << "Needed depth: " << neededDepth << '\n'; Logger::cout() << "Context depth: " << ctxDepth << '\n'; if (neededDepth >= ctxDepth) { // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); // fd needs the same context as we do, so all is well Logger::println("Calling sibling function or directly nested function"); } else { val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); val = DtoGEPi(val, 0, neededDepth); val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); } } Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "of type " << *val->getType() << '\n'; return val; }
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::AllocaInst *IrFunction::getOrCreateEhPtrSlot() { if (!ehPtrSlot) { ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr"); } return ehPtrSlot; }
void DtoCreateNestedContext(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContext for %s", fd->toChars()); LOG_SCOPE DtoCreateNestedContextType(fd); // construct nested variables array if (!fd->nestedVars.empty()) { IrFunction* irfunction = fd->ir.irFunc; unsigned depth = irfunction->depth; LLStructType *frameType = irfunction->frameType; // Create frame for current function and append to frames list // FIXME: alignment ? LLValue* frame = 0; if (fd->needsClosure()) frame = DtoGcMalloc(frameType, ".frame"); else frame = DtoRawAlloca(frameType, 0, ".frame"); // copy parent frames into beginning if (depth != 0) { LLValue* src = irfunction->nestArg; if (!src) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); AggregateDeclaration* cd = fd->isMember2(); assert(cd); assert(cd->vthis); Logger::println("Indexing to 'this'"); if (cd->isStructDeclaration()) src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); else src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } if (depth > 1) { src = DtoBitCast(src, getVoidPtrType()); LLValue* dst = DtoBitCast(frame, getVoidPtrType()); DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } // Copy nestArg into framelist; the outer frame is not in the list of pointers src = DtoBitCast(src, frameType->getContainedType(depth-1)); LLValue* gep = DtoGEPi(frame, 0, depth-1); DtoAlignedStore(src, gep); } // store context in IrFunction irfunction->nestedVar = frame; // go through all nested vars and assign addresses where possible. for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); if (vd->isParameter()) { Logger::println("nested param: %s", vd->toChars()); LOG_SCOPE IrParameter* parm = vd->ir.irParam; if (parm->arg->byref) { storeVariable(vd, gep); } else { Logger::println("Copying to nested frame"); // The parameter value is an alloca'd stack slot. // Copy to the nesting frame and leave the alloca for // the optimizers to clean up. DtoStore(DtoLoad(parm->value), gep); gep->takeName(parm->value); parm->value = gep; } } else { Logger::println("nested var: %s", vd->toChars()); assert(!vd->ir.irLocal->value); vd->ir.irLocal->value = gep; } if (global.params.symdebug) { LLSmallVector<LLValue*, 2> addr; dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); DtoDwarfLocalVariable(frame, vd, addr); } } } }
void RTTIBuilder::push_null_vp() { inits.push_back(getNullValue(getVoidPtrType())); }
// // Method: addGetActualValue() // // Description: // Insert a call to the getactualvalue() run-time function to convert the // potentially Out of Bound pointer back into its original value. // // Inputs: // SCI - The instruction that has arguments requiring conversion. // operand - The index of the operand to the instruction that requires // conversion. // void RewriteOOB::addGetActualValue (Instruction *SCI, unsigned operand) { // // Get a reference to the getactualvalue() function. // Module * M = SCI->getParent()->getParent()->getParent(); Type * VoidPtrTy = getVoidPtrType (M->getContext()); Constant * GAVConst = M->getOrInsertFunction ("pchk_getActualValue", VoidPtrTy, VoidPtrTy, VoidPtrTy, NULL); Function * GetActualValue = cast<Function>(GAVConst); // // Get the operand that needs to be replaced. // Value * Operand = SCI->getOperand(operand); // // // Rewrite pointers are generated from calls to the SAFECode run-time // checks. Therefore, constants and return values from allocation // functions are known to be the original value and do not need to be // rewritten back into their orignal values. // // FIXME: // Add a case for calls to heap allocation functions. // Value * PeeledOperand = Operand->stripPointerCasts(); if (isa<Constant>(PeeledOperand) || isa<AllocaInst>(PeeledOperand)) { return; } // // Get the pool handle associated with the pointer. // Value *PH = ConstantPointerNull::get (getVoidPtrType(Operand->getContext())); // // Create a call to getActualValue() to convert the pointer back to its // original value. // // // Update the number of calls to getActualValue() that we inserted. // ++GetActuals; // // Insert the call to getActualValue() // Type * VoidPtrType = getVoidPtrType(Operand->getContext()); Value * OpVptr = castTo (Operand, VoidPtrType, Operand->getName() + ".casted", SCI); std::vector<Value *> args; args.push_back (PH); args.push_back (OpVptr); CallInst *CI = CallInst::Create (GetActualValue, args, "getval", SCI); Instruction *CastBack = castTo (CI, Operand->getType(), Operand->getName()+".castback", SCI); SCI->setOperand (operand, CastBack); return; }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); // not sure why this is only needed for d2 bool _isconst = isConst() && init; Logger::println("Creating global variable"); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string _name(mangle()); LLType *_type = DtoConstInitializerType(type, init); // create the global variable #if LDC_LLVM_VER >= 302 // FIXME: clang uses a command line option for the thread model LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal() ? LLGlobalVariable::GeneralDynamicTLSModel : LLGlobalVariable::NotThreadLocal); #else LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal()); #endif this->ir.irGlobal->value = gvar; // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; // if this global is used from a nested function, this is necessary or // optimization could potentially remove the global (if it's the only use) if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); // assign the initializer if (!(storage_class & STCextern) && mustDefineSymbol(this)) { if (Logger::enabled()) { Logger::println("setting initializer"); Logger::cout() << "global: " << *gvar << '\n'; #if 0 Logger::cout() << "init: " << *initVal << '\n'; #endif } // build the initializer LLConstant *initVal = DtoConstInitializer(loc, type, init); // set the initializer assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // do debug info DtoDwarfGlobalVariable(gvar, this); } } }
// // Method: registerAllocaInst() // // Description: // Register a single alloca instruction. // // Inputs: // AI - The alloca which requires registration. // // Return value: // NULL - The alloca was not registered. // Otherwise, the call to poolregister() is returned. // CallInst * RegisterStackObjPass::registerAllocaInst (AllocaInst *AI) { // // Determine if any use (direct or indirect) escapes this function. If // not, then none of the checks will consult the MetaPool, and we can // forego registering the alloca. // #if 0 bool MustRegisterAlloca = false; #else // // FIXME: For now, register all allocas. The reason is that this // optimization requires that other optimizations be executed, and those are // not integrated into LLVM yet. // bool MustRegisterAlloca = true; #endif std::vector<Value *> AllocaWorkList; AllocaWorkList.push_back (AI); while ((!MustRegisterAlloca) && (AllocaWorkList.size())) { Value * V = AllocaWorkList.back(); AllocaWorkList.pop_back(); Value::use_iterator UI = V->use_begin(); for (; UI != V->use_end(); ++UI) { // We cannot handle PHI nodes or Select instructions if (isa<PHINode>(*UI) || isa<SelectInst>(*UI)) { MustRegisterAlloca = true; continue; } // The pointer escapes if it's stored to memory somewhere. StoreInst * SI; if ((SI = dyn_cast<StoreInst>(*UI)) && (SI->getOperand(0) == V)) { MustRegisterAlloca = true; continue; } // GEP instructions are okay, but need to be added to the worklist if (isa<GetElementPtrInst>(*UI)) { AllocaWorkList.push_back (*UI); continue; } // Cast instructions are okay as long as they cast to another pointer // type if (CastInst * CI = dyn_cast<CastInst>(*UI)) { if (isa<PointerType>(CI->getType())) { AllocaWorkList.push_back (*UI); continue; } else { MustRegisterAlloca = true; continue; } } #if 0 if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(*UI)) { if (cExpr->getOpcode() == Instruction::Cast) { AllocaWorkList.push_back (*UI); continue; } else { MustRegisterAlloca = true; continue; } } #endif CallInst * CI1; if ((CI1 = dyn_cast<CallInst>(*UI))) { if (!(CI1->getCalledFunction())) { MustRegisterAlloca = true; continue; } std::string FuncName = CI1->getCalledFunction()->getName(); if (FuncName == "exactcheck3") { AllocaWorkList.push_back (*UI); continue; } else if ((FuncName == "llvm.memcpy.i32") || (FuncName == "llvm.memcpy.i64") || (FuncName == "llvm.memset.i32") || (FuncName == "llvm.memset.i64") || (FuncName == "llvm.memmove.i32") || (FuncName == "llvm.memmove.i64") || (FuncName == "llva_memcpy") || (FuncName == "llva_memset") || (FuncName == "llva_strncpy") || (FuncName == "llva_invokememcpy") || (FuncName == "llva_invokestrncpy") || (FuncName == "llva_invokememset") || (FuncName == "memcmp")) { continue; } else { MustRegisterAlloca = true; continue; } } } } if (!MustRegisterAlloca) { ++SavedRegAllocs; return 0; } // // Insert the alloca registration. // // // Create an LLVM Value for the allocation size. Insert a multiplication // instruction if the allocation allocates an array. // Type * Int32Type = IntegerType::getInt32Ty(AI->getContext()); unsigned allocsize = TD->getTypeAllocSize(AI->getAllocatedType()); Value *AllocSize = ConstantInt::get (AI->getOperand(0)->getType(), allocsize); if (AI->isArrayAllocation()) { Value * Operand = AI->getOperand(0); AllocSize = BinaryOperator::Create(Instruction::Mul, AllocSize, Operand, "sizetmp", AI); } AllocSize = castTo (AllocSize, Int32Type, "sizetmp", AI); // // Attempt to insert the call to register the alloca'ed object after all of // the alloca instructions in the basic block. // Instruction *iptI = AI; BasicBlock::iterator InsertPt = AI; iptI = ++InsertPt; if (AI->getParent() == (&(AI->getParent()->getParent()->getEntryBlock()))) { InsertPt = AI->getParent()->begin(); while (&(*(InsertPt)) != AI) ++InsertPt; while (isa<AllocaInst>(InsertPt)) ++InsertPt; iptI = InsertPt; } // // Insert a call to register the object. // PointerType * VoidPtrTy = getVoidPtrType(AI->getContext()); Instruction *Casted = castTo (AI, VoidPtrTy, AI->getName()+".casted", iptI); Value * CastedPH = ConstantPointerNull::get (VoidPtrTy); std::vector<Value *> args; args.push_back (CastedPH); args.push_back (Casted); args.push_back (AllocSize); // Update statistics ++StackRegisters; return CallInst::Create (PoolRegister, args, "", iptI); }
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 Tint128: case Tuns128: 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 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; }
// // Function: insertPoolFrees() // // Description: // This function takes a list of alloca instructions and inserts code to // unregister them at every unwind and return instruction. // // Inputs: // PoolRegisters - The list of calls to poolregister() inserted for stack // objects. // ExitPoints - The list of instructions that can cause the function to // return. // Context - The LLVM Context in which to insert instructions. // void RegisterStackObjPass::insertPoolFrees (const std::vector<CallInst *> & PoolRegisters, const std::vector<Instruction *> & ExitPoints, LLVMContext * Context) { // List of alloca instructions we create to store the pointers to be // deregistered. std::vector<AllocaInst *> PtrList; // List of pool handles; this is a parallel array to PtrList std::vector<Value *> PHList; // The infamous void pointer type PointerType * VoidPtrTy = getVoidPtrType(*Context); // // Create alloca instructions for every registered alloca. These will hold // a pointer to the registered stack objects and will be referenced by // poolunregister(). // for (unsigned index = 0; index < PoolRegisters.size(); ++index) { // // Take the first element off of the worklist. // CallInst * CI = PoolRegisters[index]; CallSite CS(CI); // // Get the pool handle and allocated pointer from the poolregister() call. // Value * PH = CS.getArgument(0); Value * Ptr = CS.getArgument(1); // // Create a place to store the pointer returned from alloca. Initialize it // with a null pointer. // BasicBlock & EntryBB = CI->getParent()->getParent()->getEntryBlock(); Instruction * InsertPt = &(EntryBB.front()); AllocaInst * PtrLoc = new AllocaInst (VoidPtrTy, Ptr->getName() + ".st", InsertPt); Value * NullPointer = ConstantPointerNull::get(VoidPtrTy); new StoreInst (NullPointer, PtrLoc, InsertPt); // // Store the registered pointer into the memory we allocated in the entry // block. // new StoreInst (Ptr, PtrLoc, CI); // // Record the alloca that stores the pointer to deregister. // Record the pool handle with it. // PtrList.push_back (PtrLoc); PHList.push_back (PH); } // // For each point where the function can exit, insert code to deregister all // stack objects. // for (unsigned index = 0; index < ExitPoints.size(); ++index) { // // Take the first element off of the worklist. // Instruction * Return = ExitPoints[index]; // // Deregister each registered stack object. // for (unsigned i = 0; i < PtrList.size(); ++i) { // // Get the location holding the pointer and the pool handle associated // with it. // AllocaInst * PtrLoc = PtrList[i]; Value * PH = PHList[i]; // // Generate a load instruction to get the registered pointer. // LoadInst * Ptr = new LoadInst (PtrLoc, "", Return); // // Create the call to poolunregister(). // std::vector<Value *> args; args.push_back (PH); args.push_back (Ptr); CallInst::Create (StackFree, args, "", Return); } } // // Lastly, promote the allocas we created into LLVM virtual registers. // PromoteMemToReg(PtrList, *DT); }