llvm::Type * IrTypeSArray::sarray2llvm(Type * t) { assert(t->ty == Tsarray && "not static array type"); TypeSArray* tsa = static_cast<TypeSArray*>(t); uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger()); LLType* elemType = i1ToI8(voidToI8(DtoType(t->nextOf()))); return llvm::ArrayType::get(elemType, dim); }
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) { Logger::println("indexing class field %s:", vd->toPrettyChars()); LOG_SCOPE; if (Logger::enabled()) Logger::cout() << "src: " << *src << '\n'; // make sure class is resolved DtoResolveClass(cd); // vd must be a field IrField* field = vd->ir.irField; assert(field); // get the start pointer LLType* st = DtoType(cd->type); // cast to the struct type src = DtoBitCast(src, st); // gep to the index #if 0 if (Logger::enabled()) { Logger::cout() << "src2: " << *src << '\n'; Logger::cout() << "index: " << field->index << '\n'; Logger::cout() << "srctype: " << *src->getType() << '\n'; } #endif 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; }
IrTypeArray* IrTypeArray::get(Type* dt) { assert(!dt->ctype); assert(dt->ty == Tarray && "not dynamic array type"); LLType* elemType = i1ToI8(voidToI8(DtoType(dt->nextOf()))); // Could have already built the type as part of a struct forward reference, // just as for pointers. if (!dt->ctype) { llvm::Type *types[] = { DtoSize_t(), llvm::PointerType::get(elemType, 0) }; LLType* at = llvm::StructType::get(llvm::getGlobalContext(), types, false); dt->ctype = new IrTypeArray(dt, at); } return dt->ctype->isArray(); }
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; }
IrTypePointer* IrTypePointer::get(Type* dt) { assert(!dt->ctype); assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type"); LLType* elemType; if (dt->ty == Tnull) { elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); } else { elemType = i1ToI8(voidToI8(DtoType(dt->nextOf()))); // DtoType could have already created the same type, e.g. for // dt == Node* in struct Node { Node* n; }. if (dt->ctype) return dt->ctype->isPointer(); } IrTypePointer* t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0)); dt->ctype = t; return t; }
LLType *DtoMemType(Type *t) { return i1ToI8(voidToI8(DtoType(t))); }
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'; } }
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(i1ToI8(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 && gIR->emitArrayBoundsChecks()) { 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); LLValue *moduleInfoSymbol = gIR->func()->decl->getModule()->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); LLValue* args[] = { // module param DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType)), // line param DtoConstUint(loc.linnum) }; // 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); }
static void DtoCreateNestedContextType(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContextType for %s", fd->toChars()); LOG_SCOPE DtoDeclareFunction(fd); if (fd->ir.irFunc->nestedContextCreated) return; fd->ir.irFunc->nestedContextCreated = true; if (fd->nestedVars.empty()) { // fill nestedVars size_t nnest = fd->closureVars.dim; for (size_t i = 0; i < nnest; ++i) { VarDeclaration* vd = static_cast<VarDeclaration*>(fd->closureVars.data[i]); fd->nestedVars.insert(vd); } } // construct nested variables array if (!fd->nestedVars.empty()) { Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached LLStructType* innerFrameType = NULL; unsigned depth = -1; if (!fd->isStatic()) { if (FuncDeclaration* parfd = getParentFunc(fd, true)) { // Make sure the parent has already been analyzed. DtoCreateNestedContextType(parfd); innerFrameType = parfd->ir.irFunc->frameType; if (innerFrameType) depth = parfd->ir.irFunc->depth; } } fd->ir.irFunc->depth = ++depth; Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; typedef std::vector<LLType*> TypeVec; TypeVec types; if (depth != 0) { assert(innerFrameType); // Add frame pointer types for all but last frame if (depth > 1) { for (unsigned i = 0; i < (depth - 1); ++i) { types.push_back(innerFrameType->getElementType(i)); } } // Add frame pointer type for last frame types.push_back(LLPointerType::getUnqual(innerFrameType)); } if (Logger::enabled() && depth != 0) { Logger::println("Frame types: "); LOG_SCOPE; for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) Logger::cout() << **i << '\n'; } // Add the direct nested variables of this function, and update their indices to match. // TODO: optimize ordering for minimal space usage? for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; if (!vd->ir.irLocal) vd->ir.irLocal = new IrLocal(vd); vd->ir.irLocal->nestedIndex = types.size(); vd->ir.irLocal->nestedDepth = depth; if (vd->isParameter()) { // Parameters will have storage associated with them (to handle byref etc.), // so handle those cases specially by storing a pointer instead of a value. const IrParameter* irparam = vd->ir.irParam; const bool refout = vd->storage_class & (STCref | STCout); const bool lazy = vd->storage_class & STClazy; const bool byref = irparam->arg->byref; const bool isVthisPtr = irparam->isVthis && !byref; if (!(refout || (byref && !lazy)) || isVthisPtr) { // This will be copied to the nesting frame. if (lazy) types.push_back(irparam->value->getType()->getContainedType(0)); else types.push_back(i1ToI8(DtoType(vd->type))); } else { types.push_back(irparam->value->getType()); } } else if (isSpecialRefVar(vd)) { types.push_back(DtoType(vd->type->pointerTo())); } else { types.push_back(i1ToI8(DtoType(vd->type))); } if (Logger::enabled()) { Logger::cout() << "Nested var '" << vd->toChars() << "' of type " << *types.back() << "\n"; } } LLStructType* frameType = LLStructType::create(gIR->context(), types, std::string("nest.") + fd->toChars()); Logger::cout() << "frameType = " << *frameType << '\n'; // Store type in IrFunction fd->ir.irFunc->frameType = frameType; } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { // Propagate context arg properties if the context arg is passed on unmodified. DtoCreateNestedContextType(parFunc); fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } }