lindquist@1: // Backend stubs lindquist@1: lindquist@1: /* DMDFE backend stubs lindquist@1: * This file contains the implementations of the backend routines. lindquist@1: * For dmdfe these do nothing but print a message saying the module lindquist@1: * has been parsed. Substitute your own behaviors for these routimes. lindquist@1: */ lindquist@1: lindquist@1: #include lindquist@1: #include lindquist@1: #include lindquist@1: #include lindquist@1: #include lindquist@1: lindquist@40: #include "gen/llvm.h" lindquist@1: lindquist@132: #include "attrib.h" lindquist@1: #include "total.h" lindquist@1: #include "init.h" lindquist@1: #include "mtype.h" ChristianK@321: #include "template.h" lindquist@1: #include "hdrgen.h" lindquist@1: #include "port.h" kamm@594: #include "mem.h" lindquist@4: lindquist@4: #include "gen/irstate.h" lindquist@4: #include "gen/logger.h" lindquist@4: #include "gen/tollvm.h" lindquist@244: #include "gen/llvmhelpers.h" lindquist@4: #include "gen/runtime.h" lindquist@4: #include "gen/arrays.h" lindquist@88: #include "gen/structs.h" lindquist@100: #include "gen/classes.h" lindquist@102: #include "gen/typeinf.h" lindquist@104: #include "gen/complex.h" lindquist@86: #include "gen/dvalue.h" lindquist@109: #include "gen/aa.h" lindquist@131: #include "gen/functions.h" lindquist@244: #include "gen/todebug.h" lindquist@86: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DeclarationExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("DeclarationExp::toElem: %s | T=%s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: kamm@433: return DtoDeclarationExp(declaration); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* VarExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("VarExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@1: assert(var); lindquist@1: if (VarDeclaration* vd = var->isVarDeclaration()) lindquist@1: { tomas@763: Logger::println("VarDeclaration ' %s ' of type ' %s '", vd->toChars(), vd->type->toChars()); lindquist@50: lindquist@57: // _arguments tomas@464: if (vd->ident == Id::_arguments && p->func()->_arguments) lindquist@57: { lindquist@72: Logger::println("Id::_arguments"); lindquist@363: LLValue* v = p->func()->_arguments; tomas@585: return new DVarValue(type, vd, v); lindquist@57: } lindquist@57: // _argptr tomas@464: else if (vd->ident == Id::_argptr && p->func()->_argptr) lindquist@57: { lindquist@72: Logger::println("Id::_argptr"); lindquist@363: LLValue* v = p->func()->_argptr; tomas@585: return new DVarValue(type, vd, v); lindquist@57: } lindquist@67: // _dollar lindquist@67: else if (vd->ident == Id::dollar) lindquist@67: { lindquist@72: Logger::println("Id::dollar"); lindquist@67: assert(!p->arrays.empty()); lindquist@213: LLValue* tmp = DtoArrayLen(p->arrays.back()); tomas@585: return new DImValue(type, tmp); lindquist@67: } lindquist@67: // typeinfo lindquist@67: else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) lindquist@1: { lindquist@1: Logger::println("TypeInfoDeclaration"); lindquist@102: DtoForceDeclareDsymbol(tid); ChristianK@173: assert(tid->ir.getIrValue()); lindquist@213: const LLType* vartype = DtoType(type); tomas@585: LLValue* m = tid->ir.getIrValue(); tomas@585: if (m->getType() != getPtrToType(vartype)) tomas@585: m = p->ir->CreateBitCast(m, vartype, "tmp"); tomas@585: return new DImValue(type, m); lindquist@1: } lindquist@100: // classinfo lindquist@100: else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration()) lindquist@100: { lindquist@100: Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars()); ChristianK@367: DtoForceDeclareDsymbol(cid->cd); ChristianK@173: assert(cid->cd->ir.irStruct->classInfo); tomas@585: return new DVarValue(type, vd, cid->cd->ir.irStruct->classInfo); lindquist@100: } lindquist@67: // nested variable tomas@758: #if DMDV2 tomas@758: else if (vd->nestedrefs.dim) { tomas@758: #else lindquist@67: else if (vd->nestedref) { tomas@758: #endif lindquist@72: Logger::println("nested variable"); tomas@486: return DtoNestedVariable(loc, type, vd); lindquist@1: } lindquist@1: // function parameter lindquist@67: else if (vd->isParameter()) { lindquist@1: Logger::println("function param"); tomas@719: Logger::println("type: %s", vd->type->toChars()); lindquist@339: FuncDeclaration* fd = vd->toParent2()->isFuncDeclaration(); lindquist@339: if (fd && fd != p->func()->decl) { lindquist@339: Logger::println("nested parameter"); tomas@486: return DtoNestedVariable(loc, type, vd); lindquist@339: } tomas@719: else if (vd->storage_class & STClazy) { tomas@719: Logger::println("lazy parameter"); tomas@719: assert(type->ty == Tdelegate); tomas@719: return new DVarValue(type, vd->ir.getIrValue()); tomas@719: } lindquist@339: else if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa(vd->ir.getIrValue())) { tomas@585: return new DVarValue(type, vd, vd->ir.getIrValue()); lindquist@1: } ChristianK@173: else if (llvm::isa(vd->ir.getIrValue())) { ChristianK@173: return new DImValue(type, vd->ir.getIrValue()); lindquist@1: } lindquist@82: else assert(0); lindquist@1: } lindquist@1: else { tomas@585: Logger::println("a normal variable"); tomas@797: lindquist@67: // take care of forward references of global variables lindquist@100: if (vd->isDataseg() || (vd->storage_class & STCextern)) { lindquist@336: vd->toObjFile(0); // TODO: multiobj lindquist@100: } tomas@797: tomas@797: LLValue* val; tomas@797: tomas@797: if (!vd->ir.isSet() || !(val = vd->ir.getIrValue())) { tomas@656: error("variable %s not resolved", vd->toChars()); tomas@622: if (Logger::enabled()) tomas@656: Logger::cout() << "unresolved variable had type: " << *DtoType(vd->type) << '\n'; kamm@397: fatal(); lindquist@88: } tomas@797: kamm@628: if (vd->isDataseg() || (vd->storage_class & STCextern)) { kamm@628: DtoConstInitGlobal(vd); tomas@797: val = DtoBitCast(val, DtoType(type->pointerTo())); kamm@628: } tomas@797: tomas@797: return new DVarValue(type, vd, val); lindquist@1: } lindquist@1: } lindquist@1: else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) lindquist@1: { lindquist@1: Logger::println("FuncDeclaration"); tomas@384: LLValue* func = 0; tomas@384: if (fdecl->llvmInternal != LLVMva_arg) { lindquist@102: DtoForceDeclareDsymbol(fdecl); tomas@384: func = fdecl->ir.irFunc->func; lindquist@102: } tomas@384: return new DFuncValue(fdecl, func); lindquist@1: } lindquist@1: else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration()) lindquist@1: { lindquist@1: // this seems to be the static initialiser for structs tomas@486: Type* sdecltype = sdecl->type->toBasetype(); lindquist@40: Logger::print("Sym: type=%s\n", sdecltype->toChars()); lindquist@40: assert(sdecltype->ty == Tstruct); lindquist@40: TypeStruct* ts = (TypeStruct*)sdecltype; lindquist@121: assert(ts->sym); lindquist@162: DtoForceConstInitDsymbol(ts->sym); ChristianK@173: assert(ts->sym->ir.irStruct->init); tomas@585: return new DVarValue(type, ts->sym->ir.irStruct->init); lindquist@1: } lindquist@1: else lindquist@1: { lindquist@1: assert(0 && "Unimplemented VarExp type"); lindquist@1: } lindquist@1: lindquist@86: return 0; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@213: LLConstant* VarExp::toConstElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("VarExp::toConstElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@40: if (SymbolDeclaration* sdecl = var->isSymbolDeclaration()) lindquist@40: { lindquist@40: // this seems to be the static initialiser for structs tomas@486: Type* sdecltype = sdecl->type->toBasetype(); lindquist@40: Logger::print("Sym: type=%s\n", sdecltype->toChars()); lindquist@40: assert(sdecltype->ty == Tstruct); lindquist@40: TypeStruct* ts = (TypeStruct*)sdecltype; lindquist@102: DtoForceConstInitDsymbol(ts->sym); ChristianK@173: assert(ts->sym->ir.irStruct->constInit); ChristianK@173: return ts->sym->ir.irStruct->constInit; lindquist@40: } lindquist@132: else if (TypeInfoDeclaration* ti = var->isTypeInfoDeclaration()) lindquist@132: { lindquist@213: const LLType* vartype = DtoType(type); lindquist@275: LLConstant* m = DtoTypeInfoOf(ti->tinfo, false); lindquist@275: if (m->getType() != getPtrToType(vartype)) lindquist@132: m = llvm::ConstantExpr::getBitCast(m, vartype); lindquist@132: return m; lindquist@132: } lindquist@132: assert(0 && "Unsupported const VarExp kind"); lindquist@40: return NULL; lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@86: DValue* IntegerExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@213: LLConstant* c = toConstElem(p); lindquist@86: return new DConstValue(type, c); lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@213: LLConstant* IntegerExp::toConstElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("IntegerExp::toConstElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@213: const LLType* t = DtoType(type); lindquist@96: if (isaPointer(t)) { lindquist@88: Logger::println("pointer"); lindquist@213: LLConstant* i = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)value,false); lindquist@40: return llvm::ConstantExpr::getIntToPtr(i, t); lindquist@1: } lindquist@244: assert(llvm::isa(t)); lindquist@213: LLConstant* c = llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned()); lindquist@88: assert(c); tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "value = " << *c << '\n'; lindquist@88: return c; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* RealExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@213: LLConstant* c = toConstElem(p); lindquist@86: return new DConstValue(type, c); lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@213: LLConstant* RealExp::toConstElem(IRState* p) lindquist@40: { kamm@643: Logger::print("RealExp::toConstElem: %s | %s | %LX\n", toChars(), type->toChars(), value); lindquist@40: LOG_SCOPE; tomas@486: Type* t = type->toBasetype(); lindquist@104: return DtoConstFP(t, value); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* NullExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars()); lindquist@1: LOG_SCOPE; lindquist@213: LLConstant* c = toConstElem(p); lindquist@86: return new DNullValue(type, c); lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@213: LLConstant* NullExp::toConstElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("NullExp::toConstElem(type=%s): %s\n", type->toChars(),toChars()); lindquist@40: LOG_SCOPE; lindquist@213: const LLType* t = DtoType(type); lindquist@28: if (type->ty == Tarray) { lindquist@96: assert(isaStruct(t)); lindquist@40: return llvm::ConstantAggregateZero::get(t); lindquist@28: } lindquist@40: else { lindquist@40: return llvm::Constant::getNullValue(t); lindquist@40: } lindquist@40: assert(0); lindquist@40: return NULL; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@90: DValue* ComplexExp::toElem(IRState* p) lindquist@90: { lindquist@90: Logger::print("ComplexExp::toElem(): %s | %s\n", toChars(), type->toChars()); lindquist@90: LOG_SCOPE; lindquist@213: LLConstant* c = toConstElem(p); tomas@585: LLValue* res; lindquist@104: lindquist@104: if (c->isNullValue()) { tomas@486: Type* t = type->toBasetype(); lindquist@104: if (t->ty == Tcomplex32) lindquist@104: c = DtoConstFP(Type::tfloat32, 0); tomas@445: else if (t->ty == Tcomplex64) tomas@445: c = DtoConstFP(Type::tfloat64, 0); tomas@445: else if (t->ty == Tcomplex80) tomas@445: c = DtoConstFP(Type::tfloat80, 0); lindquist@104: else tomas@445: assert(0); tomas@585: res = DtoAggrPair(DtoType(type), c, c); lindquist@104: } tomas@585: else { tomas@585: res = DtoAggrPair(DtoType(type), c->getOperand(0), c->getOperand(1)); tomas@585: } tomas@585: tomas@585: return new DImValue(type, res); lindquist@90: } lindquist@90: lindquist@90: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@90: lindquist@213: LLConstant* ComplexExp::toConstElem(IRState* p) lindquist@90: { lindquist@90: Logger::print("ComplexExp::toConstElem(): %s | %s\n", toChars(), type->toChars()); lindquist@90: LOG_SCOPE; lindquist@104: return DtoConstComplex(type, value.re, value.im); lindquist@90: } lindquist@90: lindquist@90: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@90: lindquist@86: DValue* StringExp::toElem(IRState* p) lindquist@1: { lindquist@52: Logger::print("StringExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: tomas@486: Type* dtype = type->toBasetype(); tomas@758: Type* cty = dtype->nextOf()->toBasetype(); lindquist@1: lindquist@328: const LLType* ct = DtoTypeNotVoid(cty); tomas@758: //printf("ct = %s\n", type->nextOf()->toChars()); lindquist@244: const LLArrayType* at = LLArrayType::get(ct,len+1); lindquist@1: lindquist@213: LLConstant* _init; lindquist@183: if (cty->size() == 1) { lindquist@86: uint8_t* str = (uint8_t*)string; lindquist@86: std::string cont((char*)str, len); lindquist@86: _init = llvm::ConstantArray::get(cont,true); lindquist@86: } lindquist@183: else if (cty->size() == 2) { lindquist@86: uint16_t* str = (uint16_t*)string; lindquist@213: std::vector vals; lindquist@86: for(size_t i=0; isize() == 4) { lindquist@86: uint32_t* str = (uint32_t*)string; lindquist@213: std::vector vals; lindquist@86: for(size_t i=0; imodule); lindquist@1: lindquist@244: llvm::ConstantInt* zero = llvm::ConstantInt::get(LLType::Int32Ty, 0, false); lindquist@213: LLConstant* idxs[2] = { zero, zero }; lindquist@213: LLConstant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); lindquist@1: lindquist@40: if (dtype->ty == Tarray) { lindquist@213: LLConstant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false); tomas@720: return new DImValue(type, DtoConstSlice(clen, arrptr)); lindquist@1: } lindquist@40: else if (dtype->ty == Tsarray) { lindquist@244: const LLType* dstType = getPtrToType(LLArrayType::get(ct, len)); lindquist@213: LLValue* emem = (gvar->getType() == dstType) ? gvar : DtoBitCast(gvar, dstType); tomas@585: return new DVarValue(type, emem); lindquist@21: } lindquist@40: else if (dtype->ty == Tpointer) { lindquist@86: return new DImValue(type, arrptr); lindquist@1: } lindquist@1: lindquist@86: assert(0); lindquist@86: return 0; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@213: LLConstant* StringExp::toConstElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("StringExp::toConstElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@40: tomas@486: Type* t = type->toBasetype(); tomas@758: Type* cty = t->nextOf()->toBasetype(); lindquist@176: lindquist@176: bool nullterm = (t->ty != Tsarray); lindquist@176: size_t endlen = nullterm ? len+1 : len; lindquist@176: lindquist@213: const LLType* ct = DtoType(cty); lindquist@244: const LLArrayType* at = LLArrayType::get(ct,endlen); lindquist@176: lindquist@213: LLConstant* _init; lindquist@183: if (cty->size() == 1) { lindquist@176: uint8_t* str = (uint8_t*)string; lindquist@176: std::string cont((char*)str, len); lindquist@176: _init = llvm::ConstantArray::get(cont, nullterm); lindquist@58: } lindquist@183: else if (cty->size() == 2) { lindquist@176: uint16_t* str = (uint16_t*)string; lindquist@213: std::vector vals; lindquist@176: for(size_t i=0; isize() == 4) { lindquist@176: uint32_t* str = (uint32_t*)string; lindquist@213: std::vector vals; lindquist@176: for(size_t i=0; ity == Tsarray) lindquist@178: { lindquist@178: return _init; lindquist@178: } lindquist@178: lindquist@40: llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage; tomas@797: llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_init->getType(),true,_linkage,_init,".str",gIR->module); lindquist@40: lindquist@244: llvm::ConstantInt* zero = llvm::ConstantInt::get(LLType::Int32Ty, 0, false); lindquist@213: LLConstant* idxs[2] = { zero, zero }; lindquist@213: LLConstant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); lindquist@40: lindquist@40: if (t->ty == Tpointer) { lindquist@40: return arrptr; lindquist@40: } lindquist@178: else if (t->ty == Tarray) { lindquist@213: LLConstant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false); lindquist@81: return DtoConstSlice(clen, arrptr); lindquist@40: } lindquist@40: lindquist@40: assert(0); lindquist@40: return NULL; lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@86: DValue* AssignExp::toElem(IRState* p) lindquist@1: { tomas@467: Logger::print("AssignExp::toElem: %s | (%s)(%s = %s)\n", toChars(), type->toChars(), e1->type->toChars(), e2->type ? e2->type->toChars() : 0); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@335: if (e1->op == TOKarraylength) lindquist@335: { lindquist@335: Logger::println("performing array.length assignment"); lindquist@335: ArrayLengthExp *ale = (ArrayLengthExp *)e1; lindquist@335: DValue* arr = ale->e1->toElem(p); tomas@585: DVarValue arrval(ale->e1->type, arr->getLVal()); lindquist@335: DValue* newlen = e2->toElem(p); lindquist@335: DSliceValue* slice = DtoResizeDynArray(arrval.getType(), &arrval, newlen); kamm@399: DtoAssign(loc, &arrval, slice); lindquist@335: return newlen; lindquist@335: } lindquist@335: lindquist@335: Logger::println("performing normal assignment"); lindquist@335: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); kamm@399: DtoAssign(loc, l, r); lindquist@92: tomas@585: if (l->isSlice()) lindquist@108: return l; lindquist@109: tomas@468: return r; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* AddExp::toElem(IRState* p) lindquist@1: { lindquist@23: Logger::print("AddExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@1: tomas@486: Type* t = type->toBasetype(); tomas@486: Type* e1type = e1->type->toBasetype(); tomas@758: Type* e1next = e1type->nextOf() ? e1type->nextOf()->toBasetype() : NULL; tomas@486: Type* e2type = e2->type->toBasetype(); lindquist@40: lindquist@40: if (e1type != e2type) { tomas@705: if (e1type->ty == Tpointer) { lindquist@94: Logger::println("add to pointer"); lindquist@94: if (r->isConst()) { lindquist@94: llvm::ConstantInt* cofs = llvm::cast(r->isConst()->c); lindquist@94: if (cofs->isZero()) { lindquist@94: Logger::println("is zero"); lindquist@94: return new DImValue(type, l->getRVal()); lindquist@94: } lindquist@94: } lindquist@213: LLValue* v = llvm::GetElementPtrInst::Create(l->getRVal(), r->getRVal(), "tmp", p->scopebb()); lindquist@86: return new DImValue(type, v); lindquist@1: } lindquist@104: else if (t->iscomplex()) { kamm@399: return DtoComplexAdd(loc, type, l, r); lindquist@104: } lindquist@86: assert(0); lindquist@1: } lindquist@104: else if (t->iscomplex()) { kamm@399: return DtoComplexAdd(loc, type, l, r); lindquist@104: } lindquist@1: else { lindquist@86: return DtoBinAdd(l,r); lindquist@1: } lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* AddAssignExp::toElem(IRState* p) lindquist@1: { kamm@770: Logger::print("AddAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: tomas@486: Type* t = type->toBasetype(); lindquist@104: lindquist@86: DValue* res; tomas@486: if (e1->type->toBasetype()->ty == Tpointer) { lindquist@213: LLValue* gep = llvm::GetElementPtrInst::Create(l->getRVal(),r->getRVal(),"tmp",p->scopebb()); lindquist@86: res = new DImValue(type, gep); lindquist@86: } lindquist@104: else if (t->iscomplex()) { kamm@399: res = DtoComplexAdd(loc, e1->type, l, r); lindquist@104: } lindquist@86: else { lindquist@86: res = DtoBinAdd(l,r); lindquist@86: } kamm@399: DtoAssign(loc, l, res); lindquist@86: kamm@770: if (res->getType() != type) kamm@770: res = DtoCast(loc, res, type); kamm@770: ChristianK@334: return res; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* MinExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("MinExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: tomas@486: Type* t = type->toBasetype(); tomas@486: Type* t1 = e1->type->toBasetype(); tomas@486: Type* t2 = e2->type->toBasetype(); lindquist@167: lindquist@167: if (t1->ty == Tpointer && t2->ty == Tpointer) { lindquist@213: LLValue* lv = l->getRVal(); lindquist@213: LLValue* rv = r->getRVal(); tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "lv: " << *lv << " rv: " << *rv << '\n'; lindquist@167: lv = p->ir->CreatePtrToInt(lv, DtoSize_t(), "tmp"); lindquist@167: rv = p->ir->CreatePtrToInt(rv, DtoSize_t(), "tmp"); lindquist@213: LLValue* diff = p->ir->CreateSub(lv,rv,"tmp"); lindquist@86: if (diff->getType() != DtoType(type)) lindquist@167: diff = p->ir->CreateIntToPtr(diff, DtoType(type), "tmp"); lindquist@86: return new DImValue(type, diff); lindquist@86: } lindquist@167: else if (t1->ty == Tpointer) { lindquist@213: LLValue* idx = p->ir->CreateNeg(r->getRVal(), "tmp"); lindquist@213: LLValue* v = llvm::GetElementPtrInst::Create(l->getRVal(), idx, "tmp", p->scopebb()); lindquist@167: return new DImValue(type, v); lindquist@167: } lindquist@104: else if (t->iscomplex()) { kamm@399: return DtoComplexSub(loc, type, l, r); lindquist@104: } lindquist@86: else { lindquist@86: return DtoBinSub(l,r); lindquist@86: } lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* MinAssignExp::toElem(IRState* p) lindquist@1: { lindquist@86: Logger::print("MinAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: tomas@486: Type* t = type->toBasetype(); lindquist@104: lindquist@86: DValue* res; tomas@486: if (e1->type->toBasetype()->ty == Tpointer) { lindquist@131: Logger::println("ptr"); lindquist@213: LLValue* tmp = r->getRVal(); lindquist@213: LLValue* zero = llvm::ConstantInt::get(tmp->getType(),0,false); tomas@704: tmp = llvm::BinaryOperator::CreateSub(zero,tmp,"tmp",p->scopebb()); lindquist@205: tmp = llvm::GetElementPtrInst::Create(l->getRVal(),tmp,"tmp",p->scopebb()); lindquist@86: res = new DImValue(type, tmp); lindquist@86: } lindquist@104: else if (t->iscomplex()) { lindquist@131: Logger::println("complex"); kamm@399: res = DtoComplexSub(loc, type, l, r); lindquist@104: } lindquist@86: else { lindquist@131: Logger::println("basic"); lindquist@86: res = DtoBinSub(l,r); lindquist@86: } kamm@399: DtoAssign(loc, l, res); lindquist@86: kamm@770: if (res->getType() != type) kamm@770: res = DtoCast(loc, res, type); kamm@770: ChristianK@364: return res; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* MulExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("MulExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: lindquist@104: if (type->iscomplex()) { kamm@399: return DtoComplexMul(loc, type, l, r); lindquist@86: } lindquist@104: kamm@524: return DtoBinMul(type, l, r); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* MulAssignExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("MulAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: lindquist@104: DValue* res; lindquist@104: if (type->iscomplex()) { kamm@399: res = DtoComplexMul(loc, type, l, r); lindquist@104: } lindquist@104: else { kamm@525: res = DtoBinMul(l->getType(), l, r); lindquist@104: } kamm@399: DtoAssign(loc, l, res); lindquist@86: kamm@770: if (res->getType() != type) kamm@770: res = DtoCast(loc, res, type); kamm@770: ChristianK@364: return res; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DivExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("DivExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: lindquist@104: if (type->iscomplex()) { kamm@399: return DtoComplexDiv(loc, type, l, r); lindquist@104: } lindquist@104: kamm@524: return DtoBinDiv(type, l, r); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DivAssignExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("DivAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: lindquist@104: DValue* res; lindquist@104: if (type->iscomplex()) { kamm@399: res = DtoComplexDiv(loc, type, l, r); lindquist@104: } lindquist@104: else { kamm@525: res = DtoBinDiv(l->getType(), l, r); lindquist@104: } kamm@399: DtoAssign(loc, l, res); lindquist@86: kamm@770: if (res->getType() != type) kamm@770: res = DtoCast(loc, res, type); kamm@770: ChristianK@364: return res; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* ModExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("ModExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: kamm@524: return DtoBinRem(type, l, r); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* ModAssignExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("ModAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: kamm@525: DValue* res = DtoBinRem(l->getType(), l, r); kamm@399: DtoAssign(loc, l, res); lindquist@86: kamm@770: if (res->getType() != type) kamm@770: res = DtoCast(loc, res, type); kamm@770: ChristianK@364: return res; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* CallExp::toElem(IRState* p) lindquist@1: { lindquist@104: Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@55: tomas@414: // get the callee value tomas@414: DValue* fnval = e1->toElem(p); tomas@414: tomas@414: // get func value if any tomas@414: DFuncValue* dfnval = fnval->isFunc(); tomas@414: tomas@414: // handle magic intrinsics (mapping to instructions) lindquist@55: bool va_intrinsic = false; tomas@414: if (dfnval && dfnval->func) tomas@414: { tomas@414: FuncDeclaration* fndecl = dfnval->func; lindquist@215: // va_start instruction tomas@414: if (fndecl->llvmInternal == LLVMva_start) { tomas@443: // llvm doesn't need the second param hence the override tomas@443: Expression* exp = (Expression*)arguments->data[0]; tomas@443: DValue* expv = exp->toElem(p); tomas@443: LLValue* arg = DtoBitCast(expv->getLVal(), getVoidPtrType()); tomas@443: return new DImValue(type, gIR->ir->CreateCall(GET_INTRINSIC_DECL(vastart), arg, "")); lindquist@55: } lindquist@215: // va_arg instruction lindquist@86: else if (fndecl->llvmInternal == LLVMva_arg) { tomas@414: return DtoVaArg(loc, type, (Expression*)arguments->data[0]); lindquist@55: } tomas@414: // C alloca lindquist@94: else if (fndecl->llvmInternal == LLVMalloca) { lindquist@94: Expression* exp = (Expression*)arguments->data[0]; lindquist@94: DValue* expv = exp->toElem(p); lindquist@132: if (expv->getType()->toBasetype()->ty != Tint32) kamm@399: expv = DtoCast(loc, expv, Type::tint32); tomas@486: return new DImValue(type, p->ir->CreateAlloca(LLType::Int8Ty, expv->getRVal(), ".alloca")); lindquist@55: } lindquist@55: } tomas@414: kamm@422: return DtoCallFunction(loc, type, fnval, arguments); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* CastExp::toElem(IRState* p) lindquist@1: { lindquist@53: Logger::print("CastExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: tomas@715: // get the value to cast lindquist@86: DValue* u = e1->toElem(p); tomas@715: tomas@715: // cast it to the 'to' type, if necessary tomas@715: DValue* v = u; tomas@715: if (!to->equals(e1->type)) tomas@715: v = DtoCast(loc, u, to); tomas@715: tomas@715: // paint the type, if necessary tomas@715: if (!type->equals(to)) tomas@715: v = DtoPaintType(loc, v, type); tomas@715: tomas@715: // slices are not valid lvalues tomas@715: if (v->isSlice()) lindquist@97: return v; tomas@715: // if we're casting a lvalue, keep it around, we might be in a lvalue cast. ChristianK@334: else if(u->isLVal()) ChristianK@359: return new DLRValue(u, v); tomas@715: // otherwise just return the new value tomas@715: return v; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: tomas@619: LLConstant* CastExp::toConstElem(IRState* p) tomas@619: { tomas@619: Logger::print("CastExp::toConstElem: %s | %s\n", toChars(), type->toChars()); tomas@619: LOG_SCOPE; tomas@619: tomas@619: LLConstant* c = e1->toConstElem(p); tomas@619: const LLType* lltype = DtoType(type); kamm@624: kamm@624: if(!isaPointer(c->getType()) || !isaPointer(lltype)) { tomas@715: error("can only cast pointers to pointers at code generation time, not %s to %s", type->toChars(), e1->type->toChars()); kamm@624: fatal(); kamm@624: } tomas@619: tomas@619: return llvm::ConstantExpr::getBitCast(c, lltype); tomas@619: } tomas@619: tomas@619: ////////////////////////////////////////////////////////////////////////////////////////// tomas@619: lindquist@86: DValue* SymOffExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@98: assert(0 && "SymOffExp::toElem should no longer be called :/"); lindquist@94: return 0; lindquist@94: } lindquist@94: lindquist@94: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@94: lindquist@94: DValue* AddrExp::toElem(IRState* p) lindquist@94: { lindquist@108: Logger::println("AddrExp::toElem: %s | %s", toChars(), type->toChars()); lindquist@94: LOG_SCOPE; lindquist@94: DValue* v = e1->toElem(p); lindquist@108: if (v->isField()) { lindquist@108: Logger::println("is field"); lindquist@94: return v; lindquist@108: } lindquist@100: else if (DFuncValue* fv = v->isFunc()) { lindquist@108: Logger::println("is func"); lindquist@100: //Logger::println("FuncDeclaration"); lindquist@94: FuncDeclaration* fd = fv->func; lindquist@94: assert(fd); lindquist@136: DtoForceDeclareDsymbol(fd); ChristianK@173: return new DFuncValue(fd, fd->ir.irFunc->func); lindquist@1: } lindquist@101: else if (DImValue* im = v->isIm()) { lindquist@108: Logger::println("is immediate"); lindquist@101: return v; lindquist@101: } lindquist@108: Logger::println("is nothing special"); tomas@820: tomas@820: // we special case here, since apparently taking the address of a slice is ok tomas@820: LLValue* lval; tomas@820: if (v->isLVal()) tomas@820: lval = v->getLVal(); tomas@820: else tomas@820: { tomas@820: assert(v->isSlice()); tomas@820: LLValue* rval = v->getRVal(); tomas@820: lval = DtoAlloca(rval->getType(), ".tmp_slice_storage"); tomas@820: DtoStore(rval, lval); tomas@820: } tomas@820: tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "lval: " << *lval << '\n'; tomas@820: tomas@820: return new DImValue(type, DtoBitCast(lval, DtoType(type))); lindquist@1: } lindquist@1: kamm@459: LLConstant* AddrExp::toConstElem(IRState* p) kamm@459: { tomas@819: // FIXME: this should probably be generalized more so we don't tomas@819: // need to have a case for each thing we can take the address of tomas@819: tomas@819: // address of global variable tomas@819: if (e1->op == TOKvar) tomas@486: { tomas@819: VarExp* vexp = (VarExp*)e1; tomas@819: tomas@819: // make sure 'this' isn't needed tomas@819: if (vexp->var->needThis()) tomas@819: { tomas@819: error("need 'this' to access %s", vexp->var->toChars()); tomas@819: fatal(); tomas@819: } tomas@819: tomas@819: // global variable tomas@819: if (VarDeclaration* vd = vexp->var->isVarDeclaration()) tomas@819: { tomas@819: LLConstant* llc = llvm::dyn_cast(vd->ir.getIrValue()); tomas@819: assert(llc); tomas@819: return llc; tomas@819: } tomas@819: // static function tomas@819: else if (FuncDeclaration* fd = vexp->var->isFuncDeclaration()) tomas@819: { tomas@819: IrFunction* irfunc = fd->ir.irFunc; tomas@819: assert(irfunc); tomas@819: return irfunc->func; tomas@819: } tomas@819: // something else tomas@819: else tomas@819: { tomas@819: // fail tomas@819: goto Lerr; tomas@819: } tomas@486: } tomas@819: // address of indexExp tomas@819: else if (e1->op == TOKindex) tomas@469: { tomas@819: IndexExp* iexp = (IndexExp*)e1; tomas@819: tomas@819: // indexee must be global static array var tomas@819: assert(iexp->e1->op == TOKvar); tomas@819: VarExp* vexp = (VarExp*)iexp->e1; tomas@819: VarDeclaration* vd = vexp->var->isVarDeclaration(); tomas@819: assert(vd); tomas@819: assert(vd->type->toBasetype()->ty == Tsarray); tomas@819: assert(vd->ir.irGlobal); tomas@819: tomas@819: // get index tomas@819: LLConstant* index = iexp->e2->toConstElem(p); tomas@819: assert(index->getType() == DtoSize_t()); tomas@819: tomas@819: // gep tomas@819: LLConstant* idxs[2] = { DtoConstSize_t(0), index }; tomas@819: LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(isaConstant(vd->ir.irGlobal->value), idxs, 2); tomas@819: tomas@819: // bitcast to requested type tomas@819: assert(type->toBasetype()->ty == Tpointer); tomas@819: return DtoBitCast(gep, DtoType(type)); tomas@469: } tomas@469: // not yet supported tomas@469: else tomas@469: { tomas@819: Lerr: tomas@469: error("constant expression '%s' not yet implemented", toChars()); tomas@469: fatal(); tomas@469: } kamm@459: } kamm@459: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* PtrExp::toElem(IRState* p) lindquist@1: { lindquist@108: Logger::println("PtrExp::toElem: %s | %s", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* a = e1->toElem(p); lindquist@86: tomas@585: // this is *so* ugly.. I'd really like to figure out some way to avoid this badness... lindquist@213: LLValue* lv = a->getRVal(); lindquist@213: LLValue* v = lv; tomas@585: tomas@585: Type* bt = type->toBasetype(); tomas@585: tomas@585: // we can't load function pointers, but they aren't passed by reference either tomas@585: // FIXME: maybe a MayLoad function isn't a bad idea after all ... tomas@585: if (!DtoIsPassedByRef(bt) && bt->ty != Tfunction) lindquist@86: v = DtoLoad(v); tomas@585: tomas@585: return new DLRValue(new DVarValue(type, lv), new DImValue(type, v)); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DotVarExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("DotVarExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@1: tomas@486: Type* t = type->toBasetype(); tomas@486: Type* e1type = e1->type->toBasetype(); lindquist@40: lindquist@172: //Logger::println("e1type=%s", e1type->toChars()); lindquist@172: //Logger::cout() << *DtoType(e1type) << '\n'; lindquist@1: lindquist@1: if (VarDeclaration* vd = var->isVarDeclaration()) { lindquist@213: LLValue* arrptr; tomas@705: // indexing struct pointer lindquist@40: if (e1type->ty == Tpointer) { tomas@758: assert(e1type->nextOf()->ty == Tstruct); tomas@758: TypeStruct* ts = (TypeStruct*)e1type->nextOf(); tomas@705: arrptr = DtoIndexStruct(l->getRVal(), ts->sym, vd); lindquist@1: } tomas@705: // indexing normal struct tomas@486: else if (e1type->ty == Tstruct) { tomas@486: TypeStruct* ts = (TypeStruct*)e1type; tomas@705: arrptr = DtoIndexStruct(l->getRVal(), ts->sym, vd); tomas@486: } tomas@705: // indexing class lindquist@113: else if (e1type->ty == Tclass) { lindquist@40: TypeClass* tc = (TypeClass*)e1type; tomas@705: arrptr = DtoIndexClass(l->getRVal(), tc->sym, vd); lindquist@1: } lindquist@77: else lindquist@77: assert(0); lindquist@86: lindquist@123: //Logger::cout() << "mem: " << *arrptr << '\n'; tomas@585: return new DVarValue(type, vd, arrptr); lindquist@1: } lindquist@1: else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) lindquist@1: { lindquist@113: DtoResolveDsymbol(fdecl); lindquist@113: lindquist@213: LLValue* funcval; lindquist@213: LLValue* vthis2 = 0; lindquist@113: if (e1type->ty == Tclass) { lindquist@113: TypeClass* tc = (TypeClass*)e1type; lindquist@113: if (tc->sym->isInterfaceDeclaration()) { lindquist@114: vthis2 = DtoCastInterfaceToObject(l, NULL)->getRVal(); lindquist@113: } lindquist@1: } lindquist@213: LLValue* vthis = l->getRVal(); lindquist@113: if (!vthis2) vthis2 = vthis; lindquist@1: lindquist@133: // super call lindquist@133: if (e1->op == TOKsuper) { lindquist@133: DtoForceDeclareDsymbol(fdecl); ChristianK@173: funcval = fdecl->ir.irFunc->func; lindquist@133: assert(funcval); lindquist@133: } lindquist@133: // normal virtual call lindquist@133: else if (fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual())) { lindquist@1: assert(fdecl->vtblIndex > 0); lindquist@40: assert(e1type->ty == Tclass); lindquist@1: tomas@797: LLValue* zero = DtoConstUint(0); tomas@797: size_t vtblidx = fdecl->vtblIndex; tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "vthis: " << *vthis << '\n'; tomas@797: funcval = vthis; tomas@797: if (!fdecl->isMember2()->isInterfaceDeclaration()) tomas@797: funcval = DtoGEP(funcval, zero, zero); lindquist@244: funcval = DtoLoad(funcval); tomas@797: Logger::println("vtblidx = %lu", vtblidx); tomas@797: funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars()); lindquist@244: funcval = DtoLoad(funcval); tomas@797: lindquist@193: funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "funcval casted: " << *funcval << '\n'; lindquist@1: } lindquist@113: // static call lindquist@113: else { lindquist@113: DtoForceDeclareDsymbol(fdecl); ChristianK@173: funcval = fdecl->ir.irFunc->func; lindquist@113: assert(funcval); lindquist@113: } lindquist@113: return new DFuncValue(fdecl, funcval, vthis2); lindquist@1: } lindquist@1: else { lindquist@123: printf("unsupported dotvarexp: %s\n", var->toChars()); lindquist@1: } lindquist@1: lindquist@86: assert(0); lindquist@86: return 0; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* ThisExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("ThisExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@328: // this seems to happen for dmd generated assert statements like: lindquist@328: // assert(this, "null this"); tomas@452: // FIXME: check for TOKthis in AssertExp instead lindquist@328: if (!var) lindquist@328: { tomas@486: LLValue* v = p->func()->thisArg; lindquist@328: assert(v); tomas@585: return new DVarValue(type, v); lindquist@328: } lindquist@328: // regular this expr lindquist@328: else if (VarDeclaration* vd = var->isVarDeclaration()) { lindquist@213: LLValue* v; tomas@452: if (vd->toParent2() != p->func()->decl) { tomas@452: Logger::println("nested this exp"); tomas@486: return DtoNestedVariable(loc, type, vd); tomas@452: } tomas@452: else { tomas@452: Logger::println("normal this exp"); tomas@486: v = p->func()->thisArg; tomas@452: } tomas@585: return new DVarValue(type, vd, v); lindquist@1: } lindquist@1: lindquist@328: // anything we're not yet handling ? lindquist@86: assert(0); lindquist@86: return 0; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* IndexExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("IndexExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@1: tomas@486: Type* e1type = e1->type->toBasetype(); lindquist@40: lindquist@86: p->arrays.push_back(l); // if $ is used it must be an array so this is fine. lindquist@86: DValue* r = e2->toElem(p); lindquist@1: p->arrays.pop_back(); lindquist@1: lindquist@244: LLValue* zero = DtoConstUint(0); lindquist@244: LLValue* one = DtoConstUint(1); lindquist@213: lindquist@213: LLValue* arrptr = 0; lindquist@40: if (e1type->ty == Tpointer) { lindquist@244: arrptr = DtoGEP1(l->getRVal(),r->getRVal()); lindquist@1: } lindquist@40: else if (e1type->ty == Tsarray) { kamm@439: if(global.params.useArrayBounds) kamm@440: DtoArrayBoundsCheck(loc, l, r, false); lindquist@244: arrptr = DtoGEP(l->getRVal(), zero, r->getRVal()); lindquist@1: } lindquist@40: else if (e1type->ty == Tarray) { kamm@439: if(global.params.useArrayBounds) kamm@440: DtoArrayBoundsCheck(loc, l, r, false); lindquist@275: arrptr = DtoArrayPtr(l); lindquist@244: arrptr = DtoGEP1(arrptr,r->getRVal()); lindquist@1: } lindquist@109: else if (e1type->ty == Taarray) { tomas@458: return DtoAAIndex(loc, type, l, r, modifiable); lindquist@109: } lindquist@109: else { lindquist@109: Logger::println("invalid index exp! e1type: %s", e1type->toChars()); lindquist@109: assert(0); lindquist@109: } tomas@585: return new DVarValue(type, arrptr); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* SliceExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("SliceExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@308: // this is the new slicing code, it's different in that a full slice will no longer retain the original pointer. lindquist@308: // but this was broken if there *was* no original pointer, ie. a slice of a slice... lindquist@308: // now all slices have *both* the 'len' and 'ptr' fields set to != null. lindquist@308: lindquist@308: // value being sliced lindquist@308: LLValue* elen; lindquist@308: LLValue* eptr; lindquist@308: DValue* e = e1->toElem(p); lindquist@308: lindquist@308: // handle pointer slicing lindquist@308: Type* etype = e1->type->toBasetype(); lindquist@308: if (etype->ty == Tpointer) lindquist@308: { lindquist@308: assert(lwr); lindquist@308: eptr = e->getRVal(); lindquist@308: } lindquist@308: // array slice lindquist@308: else lindquist@308: { lindquist@308: eptr = DtoArrayPtr(e); lindquist@308: } lindquist@308: lindquist@308: // has lower bound, pointer needs adjustment lindquist@1: if (lwr) lindquist@1: { lindquist@308: // must have upper bound too then lindquist@1: assert(upr); lindquist@308: lindquist@308: // get bounds (make sure $ works) lindquist@308: p->arrays.push_back(e); lindquist@86: DValue* lo = lwr->toElem(p); lindquist@86: DValue* up = upr->toElem(p); lindquist@1: p->arrays.pop_back(); lindquist@308: LLValue* vlo = lo->getRVal(); lindquist@308: LLValue* vup = up->getRVal(); lindquist@308: kamm@440: if(global.params.useArrayBounds && (etype->ty == Tsarray || etype->ty == Tarray)) kamm@440: DtoArrayBoundsCheck(loc, e, up, true); kamm@440: lindquist@308: // offset by lower lindquist@308: eptr = DtoGEP1(eptr, vlo); lindquist@308: lindquist@308: // adjust length lindquist@308: elen = p->ir->CreateSub(vup, vlo, "tmp"); lindquist@1: } lindquist@308: // no bounds or full slice -> just convert to slice lindquist@1: else lindquist@1: { lindquist@308: assert(e1->type->toBasetype()->ty != Tpointer); lindquist@339: // if the sliceee is a static array, we use the length of that as DMD seems lindquist@339: // to give contrary inconsistent sizesin some multidimensional static array cases. lindquist@339: // (namely default initialization, int[16][16] arr; -> int[256] arr = 0;) lindquist@339: if (etype->ty == Tsarray) lindquist@339: { lindquist@339: TypeSArray* tsa = (TypeSArray*)etype; lindquist@339: elen = DtoConstSize_t(tsa->dim->toUInteger()); tomas@825: tomas@825: // in this case, we also need to make sure the pointer is cast to the innermost element type tomas@825: eptr = DtoBitCast(eptr, DtoType(tsa->nextOf()->pointerTo())); lindquist@339: } lindquist@339: // for normal code the actual array length is what we want! lindquist@339: else lindquist@339: { lindquist@339: elen = DtoArrayLen(e); lindquist@339: } lindquist@1: } lindquist@1: lindquist@308: return new DSliceValue(type, elen, eptr); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* CmpExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("CmpExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@1: tomas@486: Type* t = e1->type->toBasetype(); tomas@486: Type* e2t = e2->type->toBasetype(); lindquist@1: lindquist@213: LLValue* eval = 0; lindquist@86: lindquist@58: if (t->isintegral() || t->ty == Tpointer) lindquist@1: { lindquist@1: llvm::ICmpInst::Predicate cmpop; lindquist@40: bool skip = false; tomas@575: // pointers don't report as being unsigned tomas@575: bool uns = (t->isunsigned() || t->ty == Tpointer); lindquist@1: switch(op) lindquist@1: { lindquist@1: case TOKlt: lindquist@40: case TOKul: tomas@575: cmpop = uns ? llvm::ICmpInst::ICMP_ULT : llvm::ICmpInst::ICMP_SLT; lindquist@1: break; lindquist@1: case TOKle: lindquist@40: case TOKule: tomas@575: cmpop = uns ? llvm::ICmpInst::ICMP_ULE : llvm::ICmpInst::ICMP_SLE; lindquist@1: break; lindquist@1: case TOKgt: lindquist@40: case TOKug: tomas@575: cmpop = uns ? llvm::ICmpInst::ICMP_UGT : llvm::ICmpInst::ICMP_SGT; lindquist@1: break; lindquist@1: case TOKge: lindquist@40: case TOKuge: tomas@575: cmpop = uns ? llvm::ICmpInst::ICMP_UGE : llvm::ICmpInst::ICMP_SGE; lindquist@1: break; lindquist@40: case TOKue: lindquist@40: cmpop = llvm::ICmpInst::ICMP_EQ; lindquist@40: break; lindquist@40: case TOKlg: lindquist@40: cmpop = llvm::ICmpInst::ICMP_NE; lindquist@40: break; lindquist@40: case TOKleg: lindquist@40: skip = true; lindquist@86: eval = llvm::ConstantInt::getTrue(); lindquist@40: break; lindquist@40: case TOKunord: lindquist@40: skip = true; lindquist@86: eval = llvm::ConstantInt::getFalse(); lindquist@40: break; lindquist@40: lindquist@1: default: lindquist@1: assert(0); lindquist@1: } lindquist@40: if (!skip) lindquist@40: { lindquist@213: LLValue* a = l->getRVal(); lindquist@213: LLValue* b = r->getRVal(); tomas@622: if (Logger::enabled()) tomas@622: { tomas@622: Logger::cout() << "type 1: " << *a << '\n'; tomas@622: Logger::cout() << "type 2: " << *b << '\n'; tomas@622: } tomas@574: if (a->getType() != b->getType()) tomas@574: b = DtoBitCast(b, a->getType()); lindquist@365: eval = p->ir->CreateICmp(cmpop, a, b, "tmp"); lindquist@40: } lindquist@1: } lindquist@1: else if (t->isfloating()) lindquist@1: { lindquist@1: llvm::FCmpInst::Predicate cmpop; lindquist@1: switch(op) lindquist@1: { lindquist@1: case TOKlt: lindquist@1: cmpop = llvm::FCmpInst::FCMP_OLT;break; lindquist@1: case TOKle: lindquist@1: cmpop = llvm::FCmpInst::FCMP_OLE;break; lindquist@1: case TOKgt: lindquist@1: cmpop = llvm::FCmpInst::FCMP_OGT;break; lindquist@1: case TOKge: lindquist@1: cmpop = llvm::FCmpInst::FCMP_OGE;break; lindquist@1: case TOKunord: lindquist@1: cmpop = llvm::FCmpInst::FCMP_UNO;break; lindquist@1: case TOKule: lindquist@1: cmpop = llvm::FCmpInst::FCMP_ULE;break; lindquist@1: case TOKul: lindquist@1: cmpop = llvm::FCmpInst::FCMP_ULT;break; lindquist@1: case TOKuge: lindquist@1: cmpop = llvm::FCmpInst::FCMP_UGE;break; lindquist@1: case TOKug: lindquist@1: cmpop = llvm::FCmpInst::FCMP_UGT;break; lindquist@1: case TOKue: lindquist@1: cmpop = llvm::FCmpInst::FCMP_UEQ;break; lindquist@1: case TOKlg: lindquist@1: cmpop = llvm::FCmpInst::FCMP_ONE;break; lindquist@1: case TOKleg: lindquist@1: cmpop = llvm::FCmpInst::FCMP_ORD;break; lindquist@1: lindquist@1: default: lindquist@1: assert(0); lindquist@1: } lindquist@365: eval = p->ir->CreateFCmp(cmpop, l->getRVal(), r->getRVal(), "tmp"); lindquist@1: } lindquist@99: else if (t->ty == Tsarray || t->ty == Tarray) lindquist@99: { lindquist@99: Logger::println("static or dynamic array"); kamm@424: eval = DtoArrayCompare(loc,op,l,r); lindquist@99: } lindquist@1: else lindquist@1: { lindquist@1: assert(0 && "Unsupported CmpExp type"); lindquist@1: } lindquist@1: lindquist@86: return new DImValue(type, eval); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* EqualExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("EqualExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@1: tomas@486: Type* t = e1->type->toBasetype(); tomas@486: Type* e2t = e2->type->toBasetype(); lindquist@108: //assert(t == e2t); lindquist@1: lindquist@213: LLValue* eval = 0; lindquist@86: kamm@512: // the Tclass catches interface comparisons, regular kamm@512: // class equality should be rewritten as a.opEquals(b) by this time kamm@512: if (t->isintegral() || t->ty == Tpointer || t->ty == Tclass) lindquist@1: { kamm@512: Logger::println("integral or pointer or interface"); lindquist@1: llvm::ICmpInst::Predicate cmpop; lindquist@1: switch(op) lindquist@1: { lindquist@1: case TOKequal: lindquist@1: cmpop = llvm::ICmpInst::ICMP_EQ; lindquist@1: break; lindquist@1: case TOKnotequal: lindquist@1: cmpop = llvm::ICmpInst::ICMP_NE; lindquist@1: break; lindquist@1: default: lindquist@1: assert(0); lindquist@1: } lindquist@213: LLValue* lv = l->getRVal(); lindquist@213: LLValue* rv = r->getRVal(); lindquist@108: if (rv->getType() != lv->getType()) { lindquist@108: rv = DtoBitCast(rv, lv->getType()); lindquist@108: } tomas@705: if (Logger::enabled()) tomas@705: { tomas@705: Logger::cout() << "lv: " << *lv << '\n'; tomas@705: Logger::cout() << "rv: " << *rv << '\n'; tomas@705: } lindquist@365: eval = p->ir->CreateICmp(cmpop, lv, rv, "tmp"); lindquist@1: } lindquist@104: else if (t->iscomplex()) lindquist@104: { lindquist@104: Logger::println("complex"); kamm@399: eval = DtoComplexEquals(loc, op, l, r); lindquist@104: } lindquist@1: else if (t->isfloating()) lindquist@1: { lindquist@64: Logger::println("floating"); lindquist@1: llvm::FCmpInst::Predicate cmpop; lindquist@1: switch(op) lindquist@1: { lindquist@1: case TOKequal: lindquist@1: cmpop = llvm::FCmpInst::FCMP_OEQ; lindquist@1: break; lindquist@1: case TOKnotequal: lindquist@1: cmpop = llvm::FCmpInst::FCMP_UNE; lindquist@1: break; lindquist@1: default: lindquist@1: assert(0); lindquist@1: } lindquist@365: eval = p->ir->CreateFCmp(cmpop, l->getRVal(), r->getRVal(), "tmp"); lindquist@1: } lindquist@98: else if (t->ty == Tsarray || t->ty == Tarray) lindquist@40: { lindquist@98: Logger::println("static or dynamic array"); kamm@424: eval = DtoArrayEquals(loc,op,l,r); lindquist@1: } lindquist@53: else if (t->ty == Tdelegate) lindquist@53: { lindquist@64: Logger::println("delegate"); lindquist@344: eval = DtoDelegateEquals(op,l->getRVal(),r->getRVal()); lindquist@344: } lindquist@344: else if (t->ty == Tstruct) lindquist@344: { lindquist@344: Logger::println("struct"); lindquist@344: // when this is reached it means there is no opEquals overload. lindquist@344: eval = DtoStructEquals(op,l,r); lindquist@53: } lindquist@1: else lindquist@1: { lindquist@1: assert(0 && "Unsupported EqualExp type"); lindquist@1: } lindquist@1: lindquist@86: return new DImValue(type, eval); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* PostExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("PostExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* l = e1->toElem(p); lindquist@86: DValue* r = e2->toElem(p); lindquist@86: lindquist@213: LLValue* val = l->getRVal(); lindquist@213: LLValue* post = 0; lindquist@1: tomas@486: Type* e1type = e1->type->toBasetype(); tomas@486: Type* e2type = e2->type->toBasetype(); lindquist@40: lindquist@40: if (e1type->isintegral()) lindquist@1: { lindquist@40: assert(e2type->isintegral()); lindquist@213: LLValue* one = llvm::ConstantInt::get(val->getType(), 1, !e2type->isunsigned()); lindquist@1: if (op == TOKplusplus) { tomas@704: post = llvm::BinaryOperator::CreateAdd(val,one,"tmp",p->scopebb()); lindquist@1: } lindquist@1: else if (op == TOKminusminus) { tomas@704: post = llvm::BinaryOperator::CreateSub(val,one,"tmp",p->scopebb()); lindquist@1: } lindquist@1: } lindquist@40: else if (e1type->ty == Tpointer) lindquist@1: { lindquist@40: assert(e2type->isintegral()); lindquist@213: LLConstant* minusone = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)-1,true); lindquist@213: LLConstant* plusone = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)1,false); lindquist@213: LLConstant* whichone = (op == TOKplusplus) ? plusone : minusone; lindquist@205: post = llvm::GetElementPtrInst::Create(val, whichone, "tmp", p->scopebb()); lindquist@1: } lindquist@40: else if (e1type->isfloating()) lindquist@1: { lindquist@40: assert(e2type->isfloating()); lindquist@213: LLValue* one = DtoConstFP(e1type, 1.0); lindquist@1: if (op == TOKplusplus) { tomas@704: post = llvm::BinaryOperator::CreateAdd(val,one,"tmp",p->scopebb()); lindquist@1: } lindquist@1: else if (op == TOKminusminus) { tomas@704: post = llvm::BinaryOperator::CreateSub(val,one,"tmp",p->scopebb()); lindquist@1: } lindquist@1: } lindquist@1: else lindquist@1: assert(post); lindquist@1: lindquist@86: DtoStore(post,l->getLVal()); lindquist@86: tomas@486: return new DImValue(type,val); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* NewExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("NewExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@1: assert(newtype); tomas@486: Type* ntype = newtype->toBasetype(); lindquist@81: lindquist@203: // new class lindquist@133: if (ntype->ty == Tclass) { lindquist@169: Logger::println("new class"); tomas@486: return DtoNewClass(loc, (TypeClass*)ntype, this); lindquist@133: } lindquist@203: // new dynamic array lindquist@203: else if (ntype->ty == Tarray) lindquist@203: { lindquist@203: Logger::println("new dynamic array: %s", newtype->toChars()); lindquist@203: // get dim lindquist@203: assert(arguments); lindquist@286: assert(arguments->dim >= 1); lindquist@286: if (arguments->dim == 1) lindquist@286: { lindquist@286: DValue* sz = ((Expression*)arguments->data[0])->toElem(p); lindquist@286: // allocate & init kamm@591: return DtoNewDynArray(loc, newtype, sz, true); lindquist@286: } lindquist@286: else lindquist@286: { lindquist@286: size_t ndims = arguments->dim; lindquist@286: std::vector dims(ndims); lindquist@286: for (size_t i=0; idata[i])->toElem(p); kamm@591: return DtoNewMulDimDynArray(loc, newtype, &dims[0], ndims, true); lindquist@286: } lindquist@203: } lindquist@203: // new static array lindquist@203: else if (ntype->ty == Tsarray) lindquist@203: { lindquist@203: assert(0); lindquist@203: } lindquist@203: // new struct lindquist@203: else if (ntype->ty == Tstruct) lindquist@203: { lindquist@213: Logger::println("new struct on heap: %s\n", newtype->toChars()); lindquist@203: // allocate lindquist@213: LLValue* mem = DtoNew(newtype); lindquist@203: // init lindquist@203: TypeStruct* ts = (TypeStruct*)ntype; lindquist@203: if (ts->isZeroInit()) { lindquist@244: DtoAggrZeroInit(mem); lindquist@203: } lindquist@203: else { lindquist@203: assert(ts->sym); kamm@671: DtoForceConstInitDsymbol(ts->sym); lindquist@244: DtoAggrCopy(mem,ts->sym->ir.irStruct->init); lindquist@203: } tomas@486: return new DImValue(type, mem); lindquist@203: } lindquist@203: // new basic type lindquist@203: else lindquist@203: { lindquist@203: // allocate lindquist@213: LLValue* mem = DtoNew(newtype); tomas@585: DVarValue tmpvar(newtype, mem); lindquist@212: lindquist@212: // default initialize lindquist@212: Expression* exp = newtype->defaultInit(loc); lindquist@212: DValue* iv = exp->toElem(gIR); kamm@399: DtoAssign(loc, &tmpvar, iv); lindquist@212: lindquist@212: // return as pointer-to tomas@486: return new DImValue(type, mem); lindquist@203: } lindquist@203: lindquist@203: assert(0); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DeleteExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@209: DValue* dval = e1->toElem(p); tomas@486: Type* et = e1->type->toBasetype(); lindquist@209: lindquist@209: // simple pointer lindquist@209: if (et->ty == Tpointer) lindquist@209: { lindquist@213: LLValue* rval = dval->getRVal(); lindquist@209: DtoDeleteMemory(rval); tomas@585: if (dval->isVar()) lindquist@209: DtoStore(llvm::Constant::getNullValue(rval->getType()), dval->getLVal()); lindquist@1: } lindquist@209: // class lindquist@209: else if (et->ty == Tclass) lindquist@209: { lindquist@209: bool onstack = false; lindquist@210: TypeClass* tc = (TypeClass*)et; lindquist@210: if (tc->sym->isInterfaceDeclaration()) lindquist@210: { lindquist@210: DtoDeleteInterface(dval->getRVal()); lindquist@210: onstack = true; lindquist@210: } lindquist@210: else if (DVarValue* vv = dval->isVar()) { lindquist@209: if (vv->var && vv->var->onstack) { kamm@554: DtoFinalizeClass(dval->getRVal()); lindquist@275: onstack = true; lindquist@113: } lindquist@1: } lindquist@209: if (!onstack) { lindquist@213: LLValue* rval = dval->getRVal(); lindquist@209: DtoDeleteClass(rval); lindquist@209: } tomas@585: if (dval->isVar()) { lindquist@213: LLValue* lval = dval->getLVal(); lindquist@209: DtoStore(llvm::Constant::getNullValue(lval->getType()->getContainedType(0)), lval); lindquist@209: } lindquist@1: } lindquist@209: // dyn array lindquist@209: else if (et->ty == Tarray) lindquist@209: { lindquist@209: DtoDeleteArray(dval); tomas@715: if (dval->isLVal()) tomas@715: DtoSetArrayToNull(dval->getLVal()); lindquist@1: } lindquist@209: // unknown/invalid lindquist@209: else lindquist@209: { lindquist@209: assert(0 && "invalid delete"); lindquist@1: } lindquist@1: lindquist@209: // no value to return lindquist@209: return NULL; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* ArrayLengthExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("ArrayLengthExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* u = e1->toElem(p); lindquist@335: return new DImValue(type, DtoArrayLen(u)); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* AssertExp::toElem(IRState* p) lindquist@1: { lindquist@328: Logger::print("AssertExp::toElem: %s\n", toChars()); lindquist@1: LOG_SCOPE; lindquist@1: kamm@530: if(!global.params.useAssert) kamm@530: return NULL; kamm@530: lindquist@133: // condition lindquist@133: DValue* cond = e1->toElem(p); kamm@530: Type* condty = e1->type->toBasetype(); kamm@530: kamm@530: InvariantDeclaration* invdecl; kamm@530: kamm@530: // class invariants kamm@530: if( kamm@530: global.params.useInvariants && kamm@530: condty->ty == Tclass && kamm@530: !((TypeClass*)condty)->sym->isInterfaceDeclaration()) kamm@530: { kamm@530: Logger::print("calling class invariant"); kamm@530: llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_invariant"); kamm@530: LLValue* arg = DtoBitCast(cond->getRVal(), fn->getFunctionType()->getParamType(0)); kamm@530: gIR->CreateCallOrInvoke(fn, arg); kamm@530: } kamm@530: // struct invariants kamm@530: else if( kamm@530: global.params.useInvariants && tomas@758: condty->ty == Tpointer && condty->nextOf()->ty == Tstruct && tomas@758: (invdecl = ((TypeStruct*)condty->nextOf())->sym->inv) != NULL) kamm@530: { kamm@530: Logger::print("calling struct invariant"); kamm@530: DFuncValue invfunc(invdecl, invdecl->ir.irFunc->func, cond->getRVal()); kamm@530: DtoCallFunction(loc, NULL, &invfunc, NULL); kamm@530: } kamm@530: else kamm@530: { kamm@530: // create basic blocks kamm@530: llvm::BasicBlock* oldend = p->scopeend(); kamm@530: llvm::BasicBlock* assertbb = llvm::BasicBlock::Create("assert", p->topfunc(), oldend); kamm@530: llvm::BasicBlock* endbb = llvm::BasicBlock::Create("noassert", p->topfunc(), oldend); kamm@530: kamm@530: // test condition kamm@778: LLValue* condval = DtoCast(loc, cond, Type::tbool)->getRVal(); kamm@530: kamm@530: // branch kamm@530: llvm::BranchInst::Create(endbb, assertbb, condval, p->scopebb()); kamm@530: kamm@530: // call assert runtime functions kamm@530: p->scope() = IRScope(assertbb,endbb); kamm@530: DtoAssert(&loc, msg ? msg->toElem(p) : NULL); kamm@530: kamm@530: // rewrite the scope kamm@530: p->scope() = IRScope(endbb,oldend); kamm@530: } lindquist@133: lindquist@133: // no meaningful return value lindquist@133: return NULL; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* NotExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("NotExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* u = e1->toElem(p); lindquist@86: kamm@778: LLValue* b = DtoCast(loc, u, Type::tbool)->getRVal(); lindquist@213: kamm@611: LLConstant* zero = DtoConstBool(false); lindquist@86: b = p->ir->CreateICmpEQ(b,zero); lindquist@86: lindquist@86: return new DImValue(type, b); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* AndAndExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("AndAndExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@1: // allocate a temporary for the final result. failed to come up with a better way :/ lindquist@213: LLValue* resval = 0; lindquist@1: llvm::BasicBlock* entryblock = &p->topfunc()->front(); kamm@479: resval = DtoAlloca(LLType::Int1Ty,"andandtmp"); lindquist@86: lindquist@86: DValue* u = e1->toElem(p); lindquist@1: lindquist@1: llvm::BasicBlock* oldend = p->scopeend(); lindquist@205: llvm::BasicBlock* andand = llvm::BasicBlock::Create("andand", gIR->topfunc(), oldend); lindquist@205: llvm::BasicBlock* andandend = llvm::BasicBlock::Create("andandend", gIR->topfunc(), oldend); lindquist@86: kamm@778: LLValue* ubool = DtoCast(loc, u, Type::tbool)->getRVal(); lindquist@244: DtoStore(ubool,resval); lindquist@205: llvm::BranchInst::Create(andand,andandend,ubool,p->scopebb()); lindquist@86: lindquist@1: p->scope() = IRScope(andand, andandend); lindquist@86: DValue* v = e2->toElem(p); lindquist@86: kamm@778: LLValue* vbool = DtoCast(loc, v, Type::tbool)->getRVal(); tomas@704: LLValue* uandvbool = llvm::BinaryOperator::Create(llvm::BinaryOperator::And, ubool, vbool,"tmp",p->scopebb()); lindquist@244: DtoStore(uandvbool,resval); lindquist@205: llvm::BranchInst::Create(andandend,p->scopebb()); lindquist@1: lindquist@1: p->scope() = IRScope(andandend, oldend); lindquist@86: lindquist@244: resval = DtoLoad(resval); lindquist@86: return new DImValue(type, resval); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* OrOrExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("OrOrExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@1: // allocate a temporary for the final result. failed to come up with a better way :/ lindquist@213: LLValue* resval = 0; lindquist@1: llvm::BasicBlock* entryblock = &p->topfunc()->front(); kamm@479: resval = DtoAlloca(LLType::Int1Ty,"orortmp"); lindquist@86: lindquist@86: DValue* u = e1->toElem(p); lindquist@1: lindquist@1: llvm::BasicBlock* oldend = p->scopeend(); lindquist@205: llvm::BasicBlock* oror = llvm::BasicBlock::Create("oror", gIR->topfunc(), oldend); lindquist@205: llvm::BasicBlock* ororend = llvm::BasicBlock::Create("ororend", gIR->topfunc(), oldend); lindquist@86: kamm@778: LLValue* ubool = DtoCast(loc, u, Type::tbool)->getRVal(); lindquist@244: DtoStore(ubool,resval); lindquist@205: llvm::BranchInst::Create(ororend,oror,ubool,p->scopebb()); lindquist@86: lindquist@1: p->scope() = IRScope(oror, ororend); lindquist@86: DValue* v = e2->toElem(p); lindquist@86: kamm@778: LLValue* vbool = DtoCast(loc, v, Type::tbool)->getRVal(); lindquist@244: DtoStore(vbool,resval); lindquist@205: llvm::BranchInst::Create(ororend,p->scopebb()); lindquist@1: lindquist@1: p->scope() = IRScope(ororend, oldend); lindquist@86: lindquist@86: resval = new llvm::LoadInst(resval,"tmp",p->scopebb()); lindquist@86: return new DImValue(type, resval); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@1: #define BinBitExp(X,Y) \ lindquist@86: DValue* X##Exp::toElem(IRState* p) \ lindquist@1: { \ lindquist@1: Logger::print("%sExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ lindquist@1: LOG_SCOPE; \ lindquist@86: DValue* u = e1->toElem(p); \ lindquist@86: DValue* v = e2->toElem(p); \ tomas@704: LLValue* x = llvm::BinaryOperator::Create(llvm::Instruction::Y, u->getRVal(), v->getRVal(), "tmp", p->scopebb()); \ lindquist@86: return new DImValue(type, x); \ lindquist@1: } \ lindquist@1: \ lindquist@86: DValue* X##AssignExp::toElem(IRState* p) \ lindquist@1: { \ lindquist@1: Logger::print("%sAssignExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ lindquist@1: LOG_SCOPE; \ lindquist@86: DValue* u = e1->toElem(p); \ lindquist@86: DValue* v = e2->toElem(p); \ lindquist@213: LLValue* uval = u->getRVal(); \ lindquist@213: LLValue* vval = v->getRVal(); \ tomas@704: LLValue* tmp = llvm::BinaryOperator::Create(llvm::Instruction::Y, uval, vval, "tmp", p->scopebb()); \ lindquist@244: DtoStore(DtoPointedType(u->getLVal(), tmp), u->getLVal()); \ lindquist@86: return u; \ lindquist@1: } lindquist@1: lindquist@1: BinBitExp(And,And); lindquist@1: BinBitExp(Or,Or); lindquist@1: BinBitExp(Xor,Xor); lindquist@1: BinBitExp(Shl,Shl); lindquist@1: BinBitExp(Ushr,LShr); lindquist@1: lindquist@268: DValue* ShrExp::toElem(IRState* p) lindquist@268: { lindquist@268: Logger::print("ShrExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@268: LOG_SCOPE; lindquist@268: DValue* u = e1->toElem(p); lindquist@268: DValue* v = e2->toElem(p); lindquist@268: LLValue* x; lindquist@268: if (e1->type->isunsigned()) lindquist@268: x = p->ir->CreateLShr(u->getRVal(), v->getRVal(), "tmp"); lindquist@268: else lindquist@268: x = p->ir->CreateAShr(u->getRVal(), v->getRVal(), "tmp"); lindquist@268: return new DImValue(type, x); lindquist@268: } lindquist@268: lindquist@268: DValue* ShrAssignExp::toElem(IRState* p) lindquist@268: { lindquist@268: Logger::print("ShrAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@268: LOG_SCOPE; lindquist@268: DValue* u = e1->toElem(p); lindquist@268: DValue* v = e2->toElem(p); lindquist@268: LLValue* uval = u->getRVal(); lindquist@268: LLValue* vval = v->getRVal(); lindquist@268: LLValue* tmp; lindquist@268: if (e1->type->isunsigned()) lindquist@268: tmp = p->ir->CreateLShr(uval, vval, "tmp"); lindquist@268: else lindquist@268: tmp = p->ir->CreateAShr(uval, vval, "tmp"); lindquist@268: DtoStore(DtoPointedType(u->getLVal(), tmp), u->getLVal()); lindquist@268: return u; lindquist@268: } lindquist@268: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* HaltExp::toElem(IRState* p) lindquist@1: { lindquist@262: Logger::print("HaltExp::toElem: %s\n", toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@363: // FIXME: DMD inserts a trap here... we probably should as well !?! lindquist@363: ChristianK@281: #if 1 lindquist@258: DtoAssert(&loc, NULL); lindquist@258: #else lindquist@217: // call the new (?) trap intrinsic lindquist@217: p->ir->CreateCall(GET_INTRINSIC_DECL(trap),""); lindquist@291: new llvm::UnreachableInst(p->scopebb()); lindquist@258: #endif lindquist@36: ChristianK@282: // this terminated the basicblock, start a new one ChristianK@282: // this is sensible, since someone might goto behind the assert ChristianK@282: // and prevents compiler errors if a terminator follows the assert ChristianK@282: llvm::BasicBlock* oldend = gIR->scopeend(); ChristianK@282: llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterhalt", p->topfunc(), oldend); ChristianK@282: p->scope() = IRScope(bb,oldend); ChristianK@282: lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* DelegateExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("DelegateExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: kamm@426: if(func->isStatic()) kamm@426: error("can't take delegate of static function %s, it does not require a context ptr", func->toChars()); kamm@426: lindquist@244: const LLPointerType* int8ptrty = getPtrToType(LLType::Int8Ty); lindquist@1: tomas@719: assert(type->toBasetype()->ty == Tdelegate); tomas@719: const LLType* dgty = DtoType(type); lindquist@1: lindquist@143: DValue* u = e1->toElem(p); lindquist@213: LLValue* uval; lindquist@119: if (DFuncValue* f = u->isFunc()) { tomas@634: assert(f->func); tomas@634: LLValue* contextptr = DtoNestedContext(loc, f->func); tomas@486: uval = DtoBitCast(contextptr, getVoidPtrType()); lindquist@119: } lindquist@119: else { lindquist@143: DValue* src = u; lindquist@143: if (ClassDeclaration* cd = u->getType()->isClassHandle()) lindquist@143: { lindquist@143: Logger::println("context type is class handle"); lindquist@143: if (cd->isInterfaceDeclaration()) lindquist@143: { lindquist@143: Logger::println("context type is interface"); lindquist@143: src = DtoCastInterfaceToObject(u, ClassDeclaration::object->type); lindquist@143: } lindquist@143: } lindquist@143: uval = src->getRVal(); lindquist@119: } lindquist@119: tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "context = " << *uval << '\n'; lindquist@143: lindquist@213: LLValue* castcontext = DtoBitCast(uval, int8ptrty); lindquist@133: lindquist@133: Logger::println("func: '%s'", func->toPrettyChars()); lindquist@133: lindquist@213: LLValue* castfptr; lindquist@133: if (func->isVirtual()) lindquist@133: castfptr = DtoVirtualFunctionPointer(u, func); lindquist@133: else if (func->isAbstract()) lindquist@133: assert(0 && "TODO delegate to abstract method"); lindquist@133: else if (func->toParent()->isInterfaceDeclaration()) lindquist@133: assert(0 && "TODO delegate to interface method"); lindquist@133: else lindquist@150: { lindquist@150: DtoForceDeclareDsymbol(func); ChristianK@173: castfptr = func->ir.irFunc->func; lindquist@150: } lindquist@133: tomas@719: castfptr = DtoBitCast(castfptr, dgty->getContainedType(1)); tomas@719: tomas@719: return new DImValue(type, DtoAggrPair(castcontext, castfptr, ".dg")); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* IdentityExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("IdentityExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* u = e1->toElem(p); lindquist@86: DValue* v = e2->toElem(p); lindquist@86: lindquist@308: Type* t1 = e1->type->toBasetype(); lindquist@308: lindquist@308: // handle dynarray specially lindquist@308: if (t1->ty == Tarray) lindquist@308: return new DImValue(type, DtoDynArrayIs(op,u,v)); lindquist@345: // also structs lindquist@345: else if (t1->ty == Tstruct) lindquist@345: return new DImValue(type, DtoStructEquals(op,u,v)); lindquist@345: lindquist@345: // FIXME this stuff isn't pretty lindquist@213: LLValue* l = u->getRVal(); lindquist@213: LLValue* r = v->getRVal(); lindquist@213: LLValue* eval = 0; lindquist@86: lindquist@308: if (t1->ty == Tdelegate) { lindquist@162: if (v->isNull()) { lindquist@162: r = NULL; lindquist@162: } lindquist@162: else { lindquist@162: assert(l->getType() == r->getType()); lindquist@162: } lindquist@344: eval = DtoDelegateEquals(op,l,r); lindquist@162: } lindquist@144: else if (t1->isfloating()) lindquist@144: { lindquist@365: eval = (op == TOKidentity) lindquist@365: ? p->ir->CreateFCmpOEQ(l,r,"tmp") lindquist@365: : p->ir->CreateFCmpONE(l,r,"tmp"); lindquist@144: } tomas@629: else if (t1->ty == Tpointer || t1->ty == Tclass) lindquist@167: { lindquist@167: if (l->getType() != r->getType()) { lindquist@167: if (v->isNull()) lindquist@167: r = llvm::ConstantPointerNull::get(isaPointer(l->getType())); lindquist@167: else lindquist@244: r = DtoBitCast(r, l->getType()); lindquist@167: } lindquist@365: eval = (op == TOKidentity) lindquist@365: ? p->ir->CreateICmpEQ(l,r,"tmp") lindquist@365: : p->ir->CreateICmpNE(l,r,"tmp"); lindquist@167: } lindquist@54: else { tomas@629: assert(l->getType() == r->getType()); lindquist@365: eval = (op == TOKidentity) lindquist@365: ? p->ir->CreateICmpEQ(l,r,"tmp") lindquist@365: : p->ir->CreateICmpNE(l,r,"tmp"); lindquist@54: } lindquist@86: return new DImValue(type, eval); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* CommaExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("CommaExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* u = e1->toElem(p); lindquist@86: DValue* v = e2->toElem(p); lindquist@144: assert(e2->type == type); lindquist@1: return v; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* CondExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: tomas@486: Type* dtype = type->toBasetype(); lindquist@213: const LLType* resty = DtoType(dtype); lindquist@1: lindquist@1: // allocate a temporary for the final result. failed to come up with a better way :/ lindquist@1: llvm::BasicBlock* entryblock = &p->topfunc()->front(); kamm@479: LLValue* resval = DtoAlloca(resty,"condtmp"); tomas@585: DVarValue* dvv = new DVarValue(type, resval); lindquist@1: lindquist@1: llvm::BasicBlock* oldend = p->scopeend(); lindquist@205: llvm::BasicBlock* condtrue = llvm::BasicBlock::Create("condtrue", gIR->topfunc(), oldend); lindquist@205: llvm::BasicBlock* condfalse = llvm::BasicBlock::Create("condfalse", gIR->topfunc(), oldend); lindquist@205: llvm::BasicBlock* condend = llvm::BasicBlock::Create("condend", gIR->topfunc(), oldend); lindquist@1: lindquist@86: DValue* c = econd->toElem(p); kamm@778: LLValue* cond_val = DtoCast(loc, c, Type::tbool)->getRVal(); lindquist@205: llvm::BranchInst::Create(condtrue,condfalse,cond_val,p->scopebb()); lindquist@1: lindquist@1: p->scope() = IRScope(condtrue, condfalse); lindquist@86: DValue* u = e1->toElem(p); kamm@399: DtoAssign(loc, dvv, u); lindquist@205: llvm::BranchInst::Create(condend,p->scopebb()); lindquist@1: lindquist@1: p->scope() = IRScope(condfalse, condend); lindquist@86: DValue* v = e2->toElem(p); kamm@399: DtoAssign(loc, dvv, v); lindquist@205: llvm::BranchInst::Create(condend,p->scopebb()); lindquist@1: lindquist@1: p->scope() = IRScope(condend, oldend); lindquist@86: return dvv; lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* ComExp::toElem(IRState* p) lindquist@1: { lindquist@1: Logger::print("ComExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@1: LOG_SCOPE; lindquist@1: lindquist@86: DValue* u = e1->toElem(p); lindquist@86: lindquist@213: LLValue* value = u->getRVal(); tomas@809: LLValue* minusone = llvm::ConstantInt::get(value->getType(), (uint64_t)-1, true); tomas@704: value = llvm::BinaryOperator::Create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb()); lindquist@86: lindquist@86: return new DImValue(type, value); lindquist@1: } lindquist@1: lindquist@1: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@86: DValue* NegExp::toElem(IRState* p) lindquist@23: { lindquist@23: Logger::print("NegExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@23: LOG_SCOPE; lindquist@86: lindquist@86: DValue* l = e1->toElem(p); lindquist@164: lindquist@164: if (type->iscomplex()) { kamm@399: return DtoComplexNeg(loc, type, l); lindquist@164: } lindquist@164: lindquist@213: LLValue* val = l->getRVal(); kamm@616: kamm@616: val = gIR->ir->CreateNeg(val,"negval"); lindquist@86: return new DImValue(type, val); lindquist@23: } lindquist@23: lindquist@23: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@23: lindquist@86: DValue* CatExp::toElem(IRState* p) lindquist@36: { lindquist@36: Logger::print("CatExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@36: LOG_SCOPE; lindquist@36: tomas@486: Type* t = type->toBasetype(); tomas@486: tomas@486: bool arrNarr = e1->type->toBasetype() == e2->type->toBasetype(); lindquist@132: lindquist@203: // array ~ array lindquist@203: if (arrNarr) lindquist@203: { lindquist@203: return DtoCatArrays(type, e1, e2); lindquist@203: } lindquist@203: // array ~ element lindquist@203: // element ~ array lindquist@203: else lindquist@203: { lindquist@203: return DtoCatArrayElement(type, e1, e2); lindquist@203: } lindquist@36: } lindquist@36: lindquist@36: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@36: lindquist@86: DValue* CatAssignExp::toElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("CatAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@40: lindquist@86: DValue* l = e1->toElem(p); lindquist@40: tomas@486: Type* e1type = e1->type->toBasetype(); tomas@758: Type* elemtype = e1type->nextOf()->toBasetype(); tomas@486: Type* e2type = e2->type->toBasetype(); lindquist@40: lindquist@40: if (e2type == elemtype) { lindquist@203: DSliceValue* slice = DtoCatAssignElement(l,e2); kamm@399: DtoAssign(loc, l, slice); lindquist@86: } lindquist@86: else if (e1type == e2type) { lindquist@203: DSliceValue* slice = DtoCatAssignArray(l,e2); kamm@399: DtoAssign(loc, l, slice); lindquist@40: } lindquist@40: else lindquist@40: assert(0 && "only one element at a time right now"); lindquist@40: lindquist@203: return l; lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@86: DValue* FuncExp::toElem(IRState* p) lindquist@86: { lindquist@86: Logger::print("FuncExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@86: LOG_SCOPE; lindquist@86: lindquist@86: assert(fd); lindquist@86: lindquist@86: if (fd->isNested()) Logger::println("nested"); lindquist@86: Logger::println("kind = %s\n", fd->kind()); lindquist@86: lindquist@108: DtoForceDefineDsymbol(fd); kamm@521: assert(fd->ir.irFunc->func); lindquist@86: kamm@520: if(fd->tok == TOKdelegate) { kamm@520: const LLType* dgty = DtoType(type); tomas@719: kamm@520: LLValue* cval; kamm@520: IrFunction* irfn = p->func(); kamm@520: if (irfn->nestedVar) kamm@520: cval = irfn->nestedVar; kamm@520: else if (irfn->nestArg) kamm@520: cval = irfn->nestArg; kamm@520: else kamm@520: cval = getNullPtr(getVoidPtrType()); tomas@719: cval = DtoBitCast(cval, dgty->getContainedType(0)); tomas@719: tomas@719: LLValue* castfptr = DtoBitCast(fd->ir.irFunc->func, dgty->getContainedType(1)); tomas@719: tomas@719: return new DImValue(type, DtoAggrPair(cval, castfptr, ".func")); kamm@521: kamm@520: } else if(fd->tok == TOKfunction) { tomas@585: return new DImValue(type, fd->ir.irFunc->func); kamm@520: } kamm@521: kamm@521: assert(0 && "fd->tok must be TOKfunction or TOKdelegate"); lindquist@86: } lindquist@86: lindquist@86: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@86: tomas@797: LLConstant* FuncExp::toConstElem(IRState* p) tomas@797: { tomas@797: Logger::print("FuncExp::toConstElem: %s | %s\n", toChars(), type->toChars()); tomas@797: LOG_SCOPE; tomas@797: tomas@797: assert(fd); tomas@797: assert(fd->tok == TOKfunction); tomas@797: tomas@797: DtoForceDefineDsymbol(fd); tomas@797: assert(fd->ir.irFunc->func); tomas@797: tomas@797: return fd->ir.irFunc->func; tomas@797: } tomas@797: tomas@797: ////////////////////////////////////////////////////////////////////////////////////////// tomas@797: lindquist@86: DValue* ArrayLiteralExp::toElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@40: lindquist@175: // D types lindquist@175: Type* arrayType = type->toBasetype(); lindquist@175: Type* elemType = arrayType->nextOf()->toBasetype(); lindquist@175: lindquist@175: // is dynamic ? lindquist@175: bool dyn = (arrayType->ty == Tarray); lindquist@175: // length lindquist@175: size_t len = elements->dim; lindquist@175: lindquist@175: // llvm target type lindquist@213: const LLType* llType = DtoType(arrayType); tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << (dyn?"dynamic":"static") << " array literal with length " << len << " of D type: '" << arrayType->toChars() << "' has llvm type: '" << *llType << "'\n"; lindquist@175: lindquist@175: // llvm storage type tomas@587: const LLType* llElemType = DtoTypeNotVoid(elemType); tomas@587: const LLType* llStoType = LLArrayType::get(llElemType, len); tomas@622: if (Logger::enabled()) tomas@622: Logger::cout() << "llvm storage type: '" << *llStoType << "'\n"; lindquist@175: tomas@587: // don't allocate storage for zero length dynamic array literals tomas@587: if (dyn && len == 0) tomas@587: { tomas@587: // dmd seems to just make them null... tomas@587: return new DSliceValue(type, DtoConstSize_t(0), getNullPtr(getPtrToType(llElemType))); tomas@587: } tomas@587: lindquist@175: // dst pointer kamm@592: LLValue* dstMem; kamm@592: DSliceValue* dynSlice = NULL; kamm@592: if(dyn) kamm@592: { kamm@592: dynSlice = DtoNewDynArray(loc, arrayType, new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false); kamm@592: dstMem = dynSlice->ptr; kamm@592: } kamm@592: else kamm@592: dstMem = DtoAlloca(llStoType, "arrayliteral"); lindquist@175: lindquist@175: // store elements lindquist@175: for (size_t i=0; idata[i]; kamm@592: LLValue* elemAddr; kamm@592: if(dyn) kamm@592: elemAddr = DtoGEPi1(dstMem, i, "tmp", p->scopebb()); kamm@592: else kamm@592: elemAddr = DtoGEPi(dstMem,0,i,"tmp",p->scopebb()); lindquist@175: lindquist@175: // emulate assignment tomas@585: DVarValue* vv = new DVarValue(expr->type, elemAddr); lindquist@86: DValue* e = expr->toElem(p); tomas@486: DtoAssign(loc, vv, e); lindquist@40: } lindquist@40: lindquist@175: // return storage directly ? tomas@486: if (!dyn) tomas@486: return new DImValue(type, dstMem); tomas@486: kamm@592: // return slice kamm@592: return dynSlice; lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@213: LLConstant* ArrayLiteralExp::toConstElem(IRState* p) lindquist@40: { lindquist@40: Logger::print("ArrayLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); lindquist@40: LOG_SCOPE; lindquist@40: tomas@602: // extract D types tomas@602: Type* bt = type->toBasetype(); tomas@758: Type* elemt = bt->nextOf(); tomas@602: tomas@602: // build llvm array type tomas@602: const LLArrayType* arrtype = LLArrayType::get(DtoType(elemt), elements->dim); tomas@602: tomas@602: // dynamic arrays can occur here as well ... kamm@603: bool dyn = (bt->ty == Tarray); tomas@602: tomas@602: // build the initializer lindquist@213: std::vector vals(elements->dim, NULL); lindquist@40: for (unsigned i=0; idim; ++i) lindquist@40: { lindquist@40: Expression* expr = (Expression*)elements->data[i]; lindquist@40: vals[i] = expr->toConstElem(p); lindquist@40: } lindquist@40: tomas@602: // build the constant array initializer tomas@602: LLConstant* initval = llvm::ConstantArray::get(arrtype, vals); tomas@602: tomas@602: // if static array, we're done tomas@602: if (!dyn) tomas@602: return initval; tomas@602: tomas@602: // for dynamic arrays we need to put the initializer in a global, and build a constant dynamic array reference with the .ptr field pointing into this global tomas@602: LLConstant* globalstore = new LLGlobalVariable(arrtype, true, LLGlobalValue::InternalLinkage, initval, ".dynarrayStorage", p->module); tomas@602: LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; tomas@602: LLConstant* globalstorePtr = llvm::ConstantExpr::getGetElementPtr(globalstore, idxs, 2); tomas@602: tomas@602: return DtoConstSlice(DtoConstSize_t(elements->dim), globalstorePtr); lindquist@40: } lindquist@40: lindquist@40: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@40: lindquist@86: DValue* StructLiteralExp::toElem(IRState* p) lindquist@49: { lindquist@86: Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@49: LOG_SCOPE; lindquist@49: tomas@797: // get arrays tomas@823: size_t nexprs = elements->dim;; tomas@797: Expression** exprs = (Expression**)elements->data; tomas@797: tomas@823: size_t nvars = sd->fields.dim; tomas@797: VarDeclaration** vars = (VarDeclaration**)sd->fields.data; tomas@797: tomas@823: assert(nexprs <= nvars); tomas@823: tomas@823: // first locate all explicit initializers tomas@823: std::vector explicitInits; tomas@823: for (size_t i=0; i < nexprs; i++) tomas@823: { tomas@823: if (exprs[i]) tomas@823: { tomas@823: explicitInits.push_back(vars[i]); tomas@823: } tomas@823: } tomas@823: tomas@797: // vector of values to build aggregate from tomas@797: std::vector values; tomas@797: tomas@823: // offset trackers tomas@797: size_t lastoffset = 0; tomas@797: size_t lastsize = 0; tomas@797: tomas@823: // index of next explicit init tomas@823: size_t exidx = 0; tomas@823: // number of explicit inits tomas@823: size_t nex = explicitInits.size(); tomas@823: tomas@797: // for through each field and build up the struct, padding with zeros tomas@823: size_t i; tomas@823: for (i=0; i i) ? exprs[i] : NULL; tomas@797: VarDeclaration* var = vars[i]; tomas@797: tomas@823: // get var info tomas@823: size_t os = var->offset; tomas@823: size_t sz = var->type->size(); tomas@823: tomas@823: // get next explicit tomas@823: VarDeclaration* nextVar = NULL; tomas@823: size_t nextOs = 0; tomas@823: if (exidx < nex) tomas@823: { tomas@823: nextVar = explicitInits[exidx]; tomas@823: nextOs = nextVar->offset; tomas@823: } tomas@823: // none, rest is defaults tomas@823: else tomas@823: { tomas@823: break; tomas@823: } tomas@823: tomas@823: // not explicit initializer, default initialize if there is room, otherwise skip tomas@797: if (!e) tomas@823: { tomas@823: // default init if there is room tomas@823: // (past current offset) and (small enough to fit before next explicit) tomas@823: if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) tomas@823: { tomas@823: // add any 0 padding needed before this field tomas@823: if (os > lastoffset + lastsize) tomas@823: { tomas@823: //printf("1added %lu zeros\n", os - lastoffset - lastsize); tomas@823: addZeros(values, lastoffset + lastsize, os); tomas@823: } tomas@823: tomas@823: // get field default init tomas@823: IrField* f = var->ir.irField; tomas@823: assert(f); tomas@823: if (!f->constInit) tomas@823: f->constInit = DtoConstInitializer(var->loc, var->type, var->init); tomas@823: tomas@823: values.push_back(f->constInit); tomas@823: tomas@823: lastoffset = os; tomas@823: lastsize = sz; tomas@823: //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); tomas@823: } tomas@823: // skip tomas@797: continue; tomas@823: } tomas@823: tomas@823: assert(nextVar == var); tomas@797: tomas@797: // add any 0 padding needed before this field tomas@823: if (os > lastoffset + lastsize) tomas@797: { tomas@823: //printf("added %lu zeros\n", os - lastoffset - lastsize); tomas@823: addZeros(values, lastoffset + lastsize, os); lindquist@86: } tomas@797: tomas@797: // add the expression value tomas@797: DValue* v = e->toElem(p); tomas@797: values.push_back(v->getRVal()); tomas@797: tomas@797: // update offsets tomas@823: lastoffset = os; tomas@823: lastsize = sz; tomas@823: tomas@823: // go to next explicit init tomas@823: exidx++; tomas@823: tomas@823: //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); tomas@823: } tomas@823: tomas@823: // fill out rest with default initializers tomas@823: const LLType* structtype = DtoType(sd->type); tomas@823: size_t structsize = getABITypeSize(structtype); tomas@823: tomas@823: // FIXME: this could probably share some code with the above tomas@823: if (structsize > lastoffset+lastsize) tomas@823: { tomas@823: for (/*continue from first loop*/; i < nvars; i++) tomas@823: { tomas@823: VarDeclaration* var = vars[i]; tomas@823: tomas@823: // get var info tomas@823: size_t os = var->offset; tomas@823: size_t sz = var->type->size(); tomas@823: tomas@823: // skip? tomas@823: if (os < lastoffset + lastsize) tomas@823: continue; tomas@823: tomas@823: // add any 0 padding needed before this field tomas@823: if (os > lastoffset + lastsize) tomas@823: { tomas@823: //printf("2added %lu zeros\n", os - lastoffset - lastsize); tomas@823: addZeros(values, lastoffset + lastsize, os); tomas@823: } tomas@823: tomas@823: // get field default init tomas@823: IrField* f = var->ir.irField; tomas@823: assert(f); tomas@823: if (!f->constInit) tomas@823: f->constInit = DtoConstInitializer(var->loc, var->type, var->init); tomas@823: tomas@823: values.push_back(f->constInit); tomas@823: tomas@823: lastoffset = os; tomas@823: lastsize = sz; tomas@823: //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); tomas@823: } tomas@797: } tomas@797: tomas@797: // add any 0 padding needed at the end of the literal tomas@797: if (structsize > lastoffset+lastsize) tomas@797: { tomas@823: //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); tomas@797: addZeros(values, lastoffset + lastsize, structsize); lindquist@50: } lindquist@49: tomas@797: // get the struct type from the values tomas@823: size_t n = values.size(); tomas@797: std::vector types(n, NULL); tomas@797: tomas@797: for (size_t i=0; igetType(); lindquist@86: } lindquist@86: tomas@797: const LLStructType* sty = LLStructType::get(types, sd->ir.irStruct->packed); tomas@797: tomas@797: // allocate storage for the struct literal on the stack tomas@797: LLValue* mem = DtoAlloca(sty, "tmpstructliteral"); tomas@797: tomas@797: // put all the values into the storage tomas@797: for (size_t i=0; itoChars()); lindquist@86: LOG_SCOPE; lindquist@86: tomas@797: // get arrays tomas@797: size_t n = elements->dim; tomas@797: Expression** exprs = (Expression**)elements->data; tomas@797: tomas@797: assert(sd->fields.dim == n); tomas@797: VarDeclaration** vars = (VarDeclaration**)sd->fields.data; tomas@797: tomas@797: // vector of values to build aggregate from tomas@797: std::vector values; tomas@797: tomas@797: // trackers tomas@797: size_t lastoffset = 0; tomas@797: size_t lastsize = 0; tomas@797: tomas@797: // for through each field and build up the struct, padding with zeros tomas@797: for (size_t i=0; ioffset > lastoffset + lastsize) tomas@797: { tomas@797: addZeros(values, lastoffset + lastsize, var->offset); tomas@797: } tomas@797: tomas@797: // add the expression value tomas@797: values.push_back(e->toConstElem(p)); tomas@797: tomas@797: // update offsets tomas@797: lastoffset = var->offset; tomas@797: lastsize = var->type->size(); lindquist@86: } lindquist@86: tomas@797: // add any 0 padding needed at the end of the literal tomas@797: const LLType* structtype = DtoType(sd->type); tomas@797: size_t structsize = getABITypeSize(structtype); tomas@797: tomas@797: if (structsize > lastoffset+lastsize) tomas@797: { tomas@797: addZeros(values, lastoffset + lastsize, structsize); tomas@797: } tomas@797: tomas@797: // return constant struct tomas@797: return LLConstantStruct::get(values, sd->ir.irStruct->packed); lindquist@86: } lindquist@86: lindquist@86: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@86: lindquist@109: DValue* InExp::toElem(IRState* p) lindquist@109: { lindquist@109: Logger::print("InExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@109: LOG_SCOPE; lindquist@109: lindquist@109: DValue* key = e1->toElem(p); lindquist@109: DValue* aa = e2->toElem(p); lindquist@109: kamm@399: return DtoAAIn(loc, type, aa, key); lindquist@109: } lindquist@109: lindquist@127: DValue* RemoveExp::toElem(IRState* p) lindquist@127: { lindquist@127: Logger::print("RemoveExp::toElem: %s\n", toChars()); lindquist@127: LOG_SCOPE; lindquist@127: lindquist@127: DValue* aa = e1->toElem(p); lindquist@127: DValue* key = e2->toElem(p); lindquist@127: kamm@399: DtoAARemove(loc, aa, key); lindquist@127: lindquist@127: return NULL; // does not produce anything useful lindquist@127: } lindquist@127: lindquist@109: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@109: lindquist@125: DValue* AssocArrayLiteralExp::toElem(IRState* p) lindquist@125: { lindquist@125: Logger::print("AssocArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); lindquist@125: LOG_SCOPE; lindquist@125: lindquist@125: assert(keys); lindquist@125: assert(values); lindquist@125: assert(keys->dim == values->dim); lindquist@125: tomas@486: Type* aatype = type->toBasetype(); tomas@758: Type* vtype = aatype->nextOf(); ChristianK@283: const LLType* aalltype = DtoType(type); ChristianK@283: ChristianK@283: // it should be possible to avoid the temporary in some cases kamm@479: LLValue* tmp = DtoAlloca(aalltype,"aaliteral"); tomas@585: DValue* aa = new DVarValue(type, tmp); ChristianK@283: DtoStore(LLConstant::getNullValue(aalltype), tmp); lindquist@127: lindquist@125: const size_t n = keys->dim; lindquist@125: for (size_t i=0; idata[i]; lindquist@125: Expression* eval = (Expression*)values->data[i]; lindquist@125: lindquist@125: Logger::println("(%u) aa[%s] = %s", i, ekey->toChars(), eval->toChars()); lindquist@127: lindquist@127: // index lindquist@127: DValue* key = ekey->toElem(p); tomas@458: DValue* mem = DtoAAIndex(loc, vtype, aa, key, true); lindquist@127: lindquist@127: // store lindquist@127: DValue* val = eval->toElem(p); kamm@399: DtoAssign(loc, mem, val); lindquist@125: } lindquist@125: lindquist@127: return aa; lindquist@125: } lindquist@125: lindquist@125: ////////////////////////////////////////////////////////////////////////////////////////// lindquist@125: tomas@599: DValue* GEPExp::toElem(IRState* p) tomas@599: { tomas@599: // this should be good enough for now! tomas@599: DValue* val = e1->toElem(p); tomas@599: assert(val->isLVal()); tomas@599: LLValue* v = DtoGEPi(val->getLVal(), 0, index); tomas@599: return new DVarValue(type, DtoBitCast(v, getPtrToType(DtoType(type)))); tomas@599: } tomas@599: tomas@599: ////////////////////////////////////////////////////////////////////////////////////////// tomas@599: kamm@666: DValue* BoolExp::toElem(IRState* p) kamm@666: { kamm@778: return new DImValue(type, DtoCast(loc, e1->toElem(p), Type::tbool)->getRVal()); kamm@666: } kamm@666: kamm@666: ////////////////////////////////////////////////////////////////////////////////////////// kamm@666: kamm@667: DValue* DotTypeExp::toElem(IRState* p) kamm@667: { kamm@667: Type* t = sym->getType(); kamm@667: assert(t); kamm@667: return e1->toElem(p); kamm@667: } kamm@667: kamm@667: ////////////////////////////////////////////////////////////////////////////////////////// kamm@667: lindquist@86: #define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } lindquist@1: STUB(Expression); lindquist@1: STUB(TypeDotIdExp); lindquist@1: STUB(ScopeExp); lindquist@1: STUB(TypeExp); lindquist@92: STUB(TupleExp); lindquist@1: tomas@758: #if DMDV2 tomas@758: STUB(SymbolExp); tomas@758: #endif tomas@758: lindquist@213: #define CONSTSTUB(x) LLConstant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); fatal(); return NULL; } lindquist@40: CONSTSTUB(Expression); lindquist@40: CONSTSTUB(AssocArrayLiteralExp); lindquist@40: lindquist@1: unsigned Type::totym() { return 0; } lindquist@1: lindquist@37: type * Type::toCtype() lindquist@37: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: type * Type::toCParamtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: Symbol * Type::toSymbol() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: type * lindquist@1: TypeTypedef::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: type * lindquist@1: TypeTypedef::toCParamtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: void lindquist@1: TypedefDeclaration::toDebug() lindquist@1: { lindquist@37: assert(0); lindquist@1: } lindquist@1: lindquist@1: lindquist@1: type * lindquist@1: TypeEnum::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: type * lindquist@1: TypeStruct::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: void lindquist@1: StructDeclaration::toDebug() lindquist@1: { lindquist@37: assert(0); lindquist@1: } lindquist@1: lindquist@1: Symbol * TypeClass::toSymbol() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@1: unsigned TypeFunction::totym() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypeFunction::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypeSArray::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type *TypeSArray::toCParamtype() lindquist@37: { lindquist@37: assert(0); lindquist@37: return 0; lindquist@37: } lindquist@1: lindquist@37: type * TypeDArray::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypeAArray::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypePointer::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypeDelegate::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: type * TypeClass::toCtype() lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: lindquist@37: void ClassDeclaration::toDebug() lindquist@1: { lindquist@37: assert(0); lindquist@1: } lindquist@1: lindquist@14: ////////////////////////////////////////////////////////////////////////////// lindquist@1: lindquist@1: void lindquist@1: EnumDeclaration::toDebug() lindquist@1: { lindquist@37: assert(0); lindquist@1: } lindquist@1: lindquist@37: int Dsymbol::cvMember(unsigned char*) lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@37: int EnumDeclaration::cvMember(unsigned char*) lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@37: int FuncDeclaration::cvMember(unsigned char*) lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@37: int VarDeclaration::cvMember(unsigned char*) lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@37: int TypedefDeclaration::cvMember(unsigned char*) lindquist@1: { lindquist@37: assert(0); lindquist@1: return 0; lindquist@1: } lindquist@1: tomas@659: void obj_includelib(const char* lib) lindquist@340: { kamm@594: char *arg = (char *)mem.malloc(64); kamm@594: strcpy(arg, "-l"); kamm@594: strncat(arg, lib, 64); kamm@594: global.params.linkswitches->push(arg); lindquist@340: } lindquist@340: lindquist@340: void backend_init() lindquist@1: { lindquist@37: // now lazily loaded lindquist@1: //LLVM_D_InitRuntime(); lindquist@1: } lindquist@1: lindquist@340: void backend_term() lindquist@1: { lindquist@1: LLVM_D_FreeRuntime(); lindquist@1: }