LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r) { Type* t = l->getType()->toBasetype(); assert(t == r->getType()->toBasetype() && "aa equality is only defined for aas of same type"); #if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEqual"); LLFunctionType* funcTy = func->getFunctionType(); LLValue* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1)); LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2)); LLValue* aaTypeInfo = DtoTypeInfoOf(t); LLValue* res = gIR->CreateCallOrInvoke3(func, aaTypeInfo, aaval, abval, "aaEqRes").getInstruction(); #else llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaEq"); LLFunctionType* funcTy = func->getFunctionType(); LLValue* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(0)); LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(1)); LLValue* aaTypeInfo = DtoTypeInfoOf(t); LLValue* res = gIR->CreateCallOrInvoke3(func, aaval, abval, aaTypeInfo, "aaEqRes").getInstruction(); #endif res = gIR->ir->CreateICmpNE(res, DtoConstInt(0), "tmp"); if (op == TOKnotequal) res = gIR->ir->CreateNot(res, "tmp"); return res; }
DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key) { // D1: // call: // extern(C) void _aaDel(AA aa, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) // first get the runtime function #if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDelX"); #else llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDel"); #endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) Logger::cout() << "_aaDel = " << *func << '\n'; // aa param LLValue* aaval = aa->getRVal(); if (Logger::enabled()) { Logger::cout() << "aaval: " << *aaval << '\n'; Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n'; } aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param #if DMDV2 LLValue* keyti = to_keyti(aa); #else LLValue* keyti = to_keyti(key); #endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue* pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(2)); // build arg vector LLSmallVector<LLValue*, 3> args; args.push_back(aaval); args.push_back(keyti); args.push_back(pkey); // call runtime LLCallSite call = gIR->CreateCallOrInvoke(func, args); #if DMDV2 return new DImValue(Type::tbool, call.getInstruction()); #else return NULL; #endif }
DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key) { // D1: // call: // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function #if DMDV2 llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaInX"); #else llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaIn"); #endif LLFunctionType* funcTy = func->getFunctionType(); if (Logger::enabled()) Logger::cout() << "_aaIn = " << *func << '\n'; // aa param LLValue* aaval = aa->getRVal(); if (Logger::enabled()) { Logger::cout() << "aaval: " << *aaval << '\n'; Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n'; } aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param #if DMDV2 LLValue* keyti = to_keyti(aa); #else LLValue* keyti = to_keyti(key); #endif keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue* pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, getVoidPtrType()); // call runtime LLValue* ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.in").getInstruction(); // cast return value LLType* targettype = DtoType(type); if (ret->getType() != targettype) ret = DtoBitCast(ret, targettype); return new DImValue(type, ret); }
DValue* DtoDynamicCastInterface(DValue* val, Type* _to) { // call: // Object _d_interface_cast(void* p, ClassInfo c) ClassDeclaration::object->codegen(Type::sir); ClassDeclaration::classinfo->codegen(Type::sir); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast"); LLFunctionType* funcTy = func->getFunctionType(); std::vector<LLValue*> args; // void* p LLValue* ptr = val->getRVal(); ptr = DtoBitCast(ptr, funcTy->getParamType(0)); // ClassInfo c TypeClass* to = static_cast<TypeClass*>(_to->toBasetype()); to->sym->codegen(Type::sir); LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); // call it LLValue* ret = gIR->CreateCallOrInvoke2(func, ptr, cinfo, "tmp").getInstruction(); // cast return value ret = DtoBitCast(ret, DtoType(_to)); return new DImValue(_to, ret); }
/// Builds the body for the ldc.dso_ctor and ldc.dso_dtor functions. /// /// Pseudocode: /// if (dsoInitialized == executeWhenInitialized) { /// dsoInitialized = !executeWhenInitialized; /// auto record = {1, dsoSlot, minfoBeg, minfoEnd, minfoUsedPointer}; /// _d_dso_registry(cast(CompilerDSOData*)&record); /// } static void build_dso_ctor_dtor_body( llvm::Function* targetFunc, llvm::Value* dsoInitialized, llvm::Value* dsoSlot, llvm::Value* minfoBeg, llvm::Value* minfoEnd, llvm::Value* minfoUsedPointer, bool executeWhenInitialized ) { llvm::Function* const dsoRegistry = LLVM_D_GetRuntimeFunction(Loc(), gIR->module, "_d_dso_registry"); llvm::Type* const recordPtrTy = dsoRegistry->getFunctionType()->getContainedType(1); llvm::BasicBlock* const entryBB = llvm::BasicBlock::Create(gIR->context(), "", targetFunc); llvm::BasicBlock* const initBB = llvm::BasicBlock::Create(gIR->context(), "init", targetFunc); llvm::BasicBlock* const endBB = llvm::BasicBlock::Create(gIR->context(), "end", targetFunc); { IRBuilder<> b(entryBB); llvm::Value* condEval = b.CreateICmp(executeWhenInitialized ? llvm::ICmpInst::ICMP_NE : llvm::ICmpInst::ICMP_EQ, b.CreateLoad(dsoInitialized), b.getInt8(0)); b.CreateCondBr(condEval, initBB, endBB); } { IRBuilder<> b(initBB); b.CreateStore(b.getInt8(!executeWhenInitialized), dsoInitialized); llvm::Constant* version = DtoConstSize_t(1); llvm::Type* memberTypes[] = { version->getType(), dsoSlot->getType(), minfoBeg->getType(), minfoEnd->getType(), minfoUsedPointer->getType() }; llvm::Value* record = b.CreateAlloca( llvm::StructType::get(gIR->context(), memberTypes, false)); b.CreateStore(version, b.CreateStructGEP(record, 0)); // version b.CreateStore(dsoSlot, b.CreateStructGEP(record, 1)); // slot b.CreateStore(minfoBeg, b.CreateStructGEP(record, 2)); b.CreateStore(minfoEnd, b.CreateStructGEP(record, 3)); b.CreateStore(minfoUsedPointer, b.CreateStructGEP(record, 4)); b.CreateCall(dsoRegistry, b.CreateBitCast(record, recordPtrTy)); b.CreateBr(endBB); } { IRBuilder<> b(endBB); b.CreateRetVoid(); } }
void DtoFinalizeClass(LLValue* inst) { // get runtime function llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_callfinalizer"); // build args LLSmallVector<LLValue*,1> arg; arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); // call gIR->CreateCallOrInvoke(fn, arg, ""); }
void DtoFinalizeClass(Loc& loc, LLValue* inst) { // get runtime function llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_callfinalizer"); // build args LLValue* arg[] = { DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp") }; // call gIR->CreateCallOrInvoke(fn, arg, ""); }
DValue* DtoCastInterfaceToObject(DValue* val, Type* to) { // call: // Object _d_toObject(void* p) llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject"); LLFunctionType* funcTy = func->getFunctionType(); // void* p LLValue* tmp = val->getRVal(); tmp = DtoBitCast(tmp, funcTy->getParamType(0)); // call it LLValue* ret = gIR->CreateCallOrInvoke(func, tmp, "tmp").getInstruction(); // cast return value if (to != NULL) ret = DtoBitCast(ret, DtoType(to)); else to = ClassDeclaration::object->type; return new DImValue(to, ret); }
DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) { // D1: // call: // extern(C) void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) // or // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) // or // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGetX":"_aaInX"); LLFunctionType* funcTy = func->getFunctionType(); // aa param LLValue* aaval = lvalue ? aa->getLVal() : aa->getRVal(); aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param LLValue* keyti = to_keyti(aa); keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue* pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2)); // call runtime LLValue* ret; if (lvalue) { // valuesize param LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type))); ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction(); } else { ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction(); } // cast return value LLType* targettype = getPtrToType(DtoType(type)); if (ret->getType() != targettype) ret = DtoBitCast(ret, targettype); // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. if (!lvalue && global.params.useArrayBounds) { llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* failbb = llvm::BasicBlock::Create(gIR->context(), "aaboundscheckfail", gIR->topfunc(), oldend); llvm::BasicBlock* okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc(), oldend); LLValue* nullaa = LLConstant::getNullValue(ret->getType()); LLValue* cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck"); gIR->ir->CreateCondBr(cond, okbb, failbb); // set up failbb to call the array bounds error runtime function gIR->scope() = IRScope(failbb, okbb); std::vector<LLValue*> args; // module param LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); args.push_back(DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType))); // line param LLConstant* c = DtoConstUint(loc.linnum); args.push_back(c); // call llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_array_bounds"); gIR->CreateCallOrInvoke(errorfn, args); // the function does not return gIR->ir->CreateUnreachable(); // if ok, proceed in okbb gIR->scope() = IRScope(okbb, oldend); } return new DVarValue(type, ret); }
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { // save and rewrite scope IRScope savedscope = gIR->scope(); gIR->scope() = IRScope(inBB,savedscope.end); // eh_ptr = llvm.eh.exception(); llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); // build selector arguments LLSmallVector<LLValue*, 6> selectorargs; // put in classinfos in the right order bool hasFinally = false; bool hasCatch = false; std::deque<IRLandingPadInfo>::iterator it = infos.begin(), end = infos.end(); for(; it != end; ++it) { if(it->finallyBody) hasFinally = true; else { hasCatch = true; assert(it->catchType); assert(it->catchType->ir.irStruct); selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol()); } } // if there's a finally, the eh table has to have a 0 action if(hasFinally) selectorargs.push_back(DtoConstUint(0)); // personality fn llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::getInt8Ty(gIR->context()))); selectorargs.insert(selectorargs.begin(), personality_fn_arg); // eh storage target selectorargs.insert(selectorargs.begin(), eh_ptr); // if there is a catch and some catch allocated storage, store exception object if(hasCatch && catch_var) { const LLType* objectTy = DtoType(ClassDeclaration::object->type); gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); } // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>); llvm::Function* eh_selector_fn = GET_INTRINSIC_DECL(eh_selector); LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end()); // emit finallys and 'if' chain to catch the exception llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for); std::deque<IRLandingPadInfo> infos = this->infos; std::stack<size_t> nInfos = this->nInfos; std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); for(rit = infos.rbegin(); rit != rend; ++rit) { // if it's a finally, emit its code if(rit->finallyBody) { size_t n = this->nInfos.top(); this->infos.resize(n); this->nInfos.pop(); rit->finallyBody->toIR(gIR); } // otherwise it's a catch and we'll add a if-statement else { llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend()); LLValue *classInfo = DtoBitCast(rit->catchType->ir.irStruct->getClassInfoSymbol(), getPtrToType(DtoType(Type::tint8))); LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo); gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next); gIR->scope() = IRScope(next, gIR->scopeend()); } } // restore landing pad infos this->infos = infos; this->nInfos = nInfos; // no catch matched and all finallys executed - resume unwind llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); gIR->ir->CreateUnreachable(); gIR->scope() = savedscope; }
DValue* DtoNewClass(Loc& loc, TypeClass* tc, NewExp* newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue* mem; if (newexp->onstack) { // FIXME align scope class to its largest member mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, getIrFunc(newexp->allocator)->func); DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass"); LLConstant* ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; DValue* thisval = toElem(newexp->thisexp); unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue* src = thisval->getRVal(); LLValue* dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, getIrFunc(newexp->member)->func, mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } // return default constructed class return new DImValue(tc, mem); }
void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { // save and rewrite scope IRScope savedscope = gIR->scope(); gIR->scope() = IRScope(inBB,savedscope.end); // personality fn llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); // create landingpad LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()), LLType::getInt32Ty(gIR->context()), NULL); llvm::LandingPadInst *landingPad = gIR->ir->CreateLandingPad(retType, personality_fn, 0); LLValue* eh_ptr = DtoExtractValue(landingPad, 0); LLValue* eh_sel = DtoExtractValue(landingPad, 1); // add landingpad clauses, emit finallys and 'if' chain to catch the exception llvm::Function* eh_typeid_for_fn = GET_INTRINSIC_DECL(eh_typeid_for); std::deque<IRLandingPadInfo> infos = this->infos; std::stack<size_t> nInfos = this->nInfos; std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); bool isFirstCatch = true; for(rit = infos.rbegin(); rit != rend; ++rit) { // if it's a finally, emit its code if(rit->finallyBody) { size_t n = this->nInfos.top(); this->infos.resize(n); this->nInfos.pop(); rit->finallyBody->toIR(gIR); landingPad->setCleanup(true); } // otherwise it's a catch and we'll add a if-statement else { // if it is a first catch and some catch allocated storage, store exception object if(isFirstCatch && catch_var) { LLType* objectTy = DtoType(ClassDeclaration::object->type); gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); isFirstCatch = false; } // create next block llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend()); // get class info symbol LLValue *classInfo = rit->catchType->ir.irStruct->getClassInfoSymbol(); // add that symbol as landing pad clause landingPad->addClause(classInfo); // call llvm.eh.typeid.for to get class info index in the exception table classInfo = DtoBitCast(classInfo, getPtrToType(DtoType(Type::tint8))); LLValue *eh_id = gIR->ir->CreateCall(eh_typeid_for_fn, classInfo); // check exception selector (eh_sel) against the class info index gIR->ir->CreateCondBr(gIR->ir->CreateICmpEQ(eh_sel, eh_id), rit->target, next); gIR->scope() = IRScope(next, gIR->scopeend()); } } // restore landing pad infos this->infos = infos; this->nInfos = nInfos; // no catch matched and all finallys executed - resume unwind llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); gIR->ir->CreateUnreachable(); // restore scope gIR->scope() = savedscope; }
LLConstant * IrStruct::getVtblInit() { if (constVtbl) return constVtbl; IF_LOG Logger::println("Building vtbl initializer"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not class"); std::vector<llvm::Constant*> constants; constants.reserve(cd->vtbl.dim); // start with the classinfo llvm::Constant* c = getClassInfoSymbol(); c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); constants.push_back(c); // add virtual function pointers size_t n = cd->vtbl.dim; for (size_t i = 1; i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(cd->vtbl.data[i]); assert(dsym && "null vtbl member"); FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) { c = getNullValue(DtoType(fd->type->pointerTo())); } else { fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; #if DMDV2 if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < n; j++) { if (j == i) continue; FuncDeclaration *fd2 = static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { if (global.params.warnings) { TypeFunction *tf = static_cast<TypeFunction *>(fd->type); if (tf->ty == Tfunction) error("%s%s is hidden by %s\n", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars()); else error("%s is hidden by %s\n", fd->toPrettyChars(), toChars()); } c = DtoBitCast(LLVM_D_GetRuntimeFunction(gIR->module, "_d_hidden_func"), c->getType()); break; } } } #endif } constants.push_back(c); } // build the constant struct LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); #if 0 IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; IF_LOG Logger::cout() << "vtbl type: " << *stripModifiers(type)->irtype->isClass()->getVtbl() << std::endl; #endif #if 0 size_t nc = constants.size(); for (size_t i = 0; i < nc; ++i) { if (constVtbl->getOperand(i)->getType() != vtblTy->getContainedType(i)) { Logger::cout() << "type mismatch for entry # " << i << " in vtbl initializer" << std::endl; constVtbl->getOperand(i)->dump(); vtblTy->getContainedType(i)->dump(); } } #endif assert(constVtbl->getType() == stripModifiers(type)->irtype->isClass()->getVtbl() && "vtbl initializer type mismatch"); return constVtbl; }