LLConstant* DtoConstStringPtr(const char* str, const char* section) { llvm::StringRef s(str); LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true); llvm::GlobalVariable* gvar = new llvm::GlobalVariable( *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str"); if (section) gvar->setSection(section); gvar->setUnnamedAddr(true); LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) }; return llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true); }
void RTTIBuilder::finalize(IrGlobal* tid) { // create the inititalizer LLConstant* tiInit = LLConstantStruct::get(gIR->context(), &inits[0], inits.size(), false); // refine global type llvm::cast<llvm::OpaqueType>(tid->type.get())->refineAbstractTypeTo(tiInit->getType()); // set the initializer isaGlobalVar(tid->value)->setInitializer(tiInit); }
LLConstant* DtoConstString(const char* str) { llvm::StringRef s(str ? str : ""); LLConstant* init = llvm::ConstantDataArray::getString(gIR->context(), s, true); llvm::GlobalVariable* gvar = new llvm::GlobalVariable( *gIR->module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, ".str"); gvar->setUnnamedAddr(true); LLConstant* idxs[] = { DtoConstUint(0), DtoConstUint(0) }; return DtoConstSlice( DtoConstSize_t(s.size()), llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true), Type::tchar->arrayOf() ); }
void visit(VarExp *e) override { IF_LOG Logger::print("VarExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars()); LOG_SCOPE; if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) { // this seems to be the static initialiser for structs Type *sdecltype = sdecl->type->toBasetype(); IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct *ts = static_cast<TypeStruct *>(sdecltype); DtoResolveStruct(ts->sym); result = getIrAggr(ts->sym)->getDefaultInit(); return; } if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) { LLType *vartype = DtoType(e->type); result = DtoTypeInfoOf(ti->tinfo, false); if (result->getType() != getPtrToType(vartype)) { result = llvm::ConstantExpr::getBitCast(result, vartype); } return; } VarDeclaration *vd = e->var->isVarDeclaration(); if (vd && vd->isConst() && vd->_init) { if (vd->inuse) { e->error("recursive reference %s", e->toChars()); result = llvm::UndefValue::get(DtoType(e->type)); } else { vd->inuse++; // return the initializer result = DtoConstInitializer(e->loc, e->type, vd->_init); vd->inuse--; } } // fail else { e->error("non-constant expression %s", e->toChars()); result = llvm::UndefValue::get(DtoType(e->type)); } }
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; }
std::vector<LLConstant*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<LLConstant*>& inits) { // get arrays size_t nvars = sd->fields.dim; VarDeclaration** vars = (VarDeclaration**)sd->fields.data; assert(inits.size() == nvars); // first locate all explicit initializers std::vector<VarDeclaration*> explicitInits; for (size_t i=0; i < nvars; i++) { if (inits[i]) { explicitInits.push_back(vars[i]); } } // vector of values to build aggregate from std::vector<LLConstant*> values; // offset trackers size_t lastoffset = 0; size_t lastsize = 0; // index of next explicit init size_t exidx = 0; // number of explicit inits size_t nex = explicitInits.size(); // for through each field and build up the struct, padding with zeros size_t i; for (i=0; i<nvars; i++) { VarDeclaration* var = vars[i]; // get var info size_t os = var->offset; size_t sz = var->type->size(); // get next explicit VarDeclaration* nextVar = NULL; size_t nextOs = 0; if (exidx < nex) { nextVar = explicitInits[exidx]; nextOs = nextVar->offset; } // none, rest is defaults else { break; } // not explicit initializer, default initialize if there is room, otherwise skip if (!inits[i]) { // default init if there is room // (past current offset) and (small enough to fit before next explicit) if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) { // add any 0 padding needed before this field if (os > lastoffset + lastsize) { //printf("1added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); } // get field default init IrField* f = var->ir.irField; assert(f); values.push_back(f->getDefaultInit()); lastoffset = os; lastsize = sz; //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); } // skip continue; } assert(nextVar == var); LLConstant* init = FillSArrayDims(var->type, inits[i]); values.push_back(init); // update offsets lastoffset = os; // sometimes size of the initializer is less than size of the variable, // so make sure that lastsize is correct if (inits[i]->getType()->isSized()) sz = ceil(gDataLayout->getTypeSizeInBits(init->getType()) / 8.0); lastsize = sz; // go to next explicit init exidx++; //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); } // fill out rest with default initializers LLType* structtype = DtoType(sd->type); size_t structsize = getTypePaddedSize(structtype); // FIXME: this could probably share some code with the above if (structsize > lastoffset+lastsize) { for (/*continue from first loop*/; i < nvars; i++) { VarDeclaration* var = vars[i]; // get var info size_t os = var->offset; size_t sz = var->type->size(); // skip? if (os < lastoffset + lastsize) continue; // add any 0 padding needed before this field if (os > lastoffset + lastsize) { //printf("2added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); } // get field default init IrField* f = var->ir.irField; assert(f); values.push_back(f->getDefaultInit()); lastoffset = os; lastsize = sz; //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); } } // add any 0 padding needed at the end of the literal if (structsize > lastoffset+lastsize) { //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); add_zeros(values, structsize - lastoffset - lastsize); } return values; }
void visit(AddrExp *e) override { IF_LOG Logger::println("AddrExp::toConstElem: %s @ %s", e->toChars(), e->type->toChars()); LOG_SCOPE; // FIXME: this should probably be generalized more so we don't // need to have a case for each thing we can take the address of // address of global variable if (e->e1->op == TOKvar) { VarExp *vexp = static_cast<VarExp *>(e->e1); LLConstant *c = DtoConstSymbolAddress(e->loc, vexp->var); result = c ? DtoBitCast(c, DtoType(e->type)) : nullptr; } // address of indexExp else if (e->e1->op == TOKindex) { IndexExp *iexp = static_cast<IndexExp *>(e->e1); // indexee must be global static array var assert(iexp->e1->op == TOKvar); VarExp *vexp = static_cast<VarExp *>(iexp->e1); VarDeclaration *vd = vexp->var->isVarDeclaration(); assert(vd); assert(vd->type->toBasetype()->ty == Tsarray); DtoResolveVariable(vd); assert(isIrGlobalCreated(vd)); // get index LLConstant *index = toConstElem(iexp->e2); assert(index->getType() == DtoSize_t()); // gep LLConstant *idxs[2] = {DtoConstSize_t(0), index}; LLConstant *val = isaConstant(getIrGlobal(vd)->value); val = DtoBitCast(val, DtoType(vd->type->pointerTo())); #if LDC_LLVM_VER >= 307 LLConstant *gep = llvm::ConstantExpr::getGetElementPtr( isaPointer(val)->getElementType(), val, idxs, true); #else LLConstant *gep = llvm::ConstantExpr::getGetElementPtr(val, idxs, true); #endif // bitcast to requested type assert(e->type->toBasetype()->ty == Tpointer); result = DtoBitCast(gep, DtoType(e->type)); } else if (e->e1->op == TOKstructliteral) { StructLiteralExp *se = static_cast<StructLiteralExp *>(e->e1); if (se->globalVar) { IF_LOG Logger::cout() << "Returning existing global: " << *se->globalVar << '\n'; result = se->globalVar; return; } se->globalVar = new llvm::GlobalVariable( p->module, DtoType(e->e1->type), false, llvm::GlobalValue::InternalLinkage, nullptr, ".structliteral"); llvm::Constant *constValue = toConstElem(se); if (constValue->getType() != se->globalVar->getType()->getContainedType(0)) { auto finalGlobalVar = new llvm::GlobalVariable( p->module, constValue->getType(), false, llvm::GlobalValue::InternalLinkage, nullptr, ".structliteral"); se->globalVar->replaceAllUsesWith( DtoBitCast(finalGlobalVar, se->globalVar->getType())); se->globalVar->eraseFromParent(); se->globalVar = finalGlobalVar; } se->globalVar->setInitializer(constValue); se->globalVar->setAlignment(DtoAlignment(se->type)); result = se->globalVar; } else if (e->e1->op == TOKslice) { e->error("non-constant expression '%s'", e->toChars()); if (!global.gag) { fatal(); } result = llvm::UndefValue::get(DtoType(e->type)); } // not yet supported else { e->error("constant expression '%s' not yet implemented", e->toChars()); fatal(); } }
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'; } }