DValue *binAdd(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { Type *lhsType = lhs->type->toBasetype(); Type *rhsType = rhs->type->toBasetype(); if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { Logger::println("Adding integer to pointer"); return emitPointerOffset(loc, lhs, rhs, false, type, loadLhsAfterRhs); } auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (type->ty == Tnull) return DtoNullValue(type, loc); if (type->iscomplex()) return DtoComplexAdd(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); if (auto aa = isAssociativeArrayAndNull(type, l, r)) return aa; LLValue *res = (type->isfloating() ? gIR->ir->CreateFAdd(l, r) : gIR->ir->CreateAdd(l, r)); return new DImValue(type, res); }
void DtoGetComplexParts(Loc &loc, Type *to, DValue *val, LLValue *&re, LLValue *&im) { DValue *dre, *dim; DtoGetComplexParts(loc, to, val, dre, dim); re = dre ? DtoRVal(dre) : nullptr; im = dim ? DtoRVal(dim) : nullptr; }
void DtoGetComplexParts(Loc &loc, Type *to, DValue *val, DValue *&re, DValue *&im) { Type *baserety; Type *baseimty; switch (to->toBasetype()->ty) { default: llvm_unreachable("Unexpected complex floating point type"); case Tcomplex32: baserety = Type::tfloat32; baseimty = Type::timaginary32; break; case Tcomplex64: baserety = Type::tfloat64; baseimty = Type::timaginary64; break; case Tcomplex80: baserety = Type::tfloat80; baseimty = Type::timaginary80; break; } Type *t = val->type->toBasetype(); if (t->iscomplex()) { DValue *v = DtoCastComplex(loc, val, to); if (to->iscomplex()) { if (v->isLVal()) { LLValue *reVal = DtoGEPi(DtoLVal(v), 0, 0, ".re_part"); LLValue *imVal = DtoGEPi(DtoLVal(v), 0, 1, ".im_part"); re = new DLValue(baserety, reVal); im = new DLValue(baseimty, imVal); } else { LLValue *reVal = gIR->ir->CreateExtractValue(DtoRVal(v), 0, ".re_part"); LLValue *imVal = gIR->ir->CreateExtractValue(DtoRVal(v), 1, ".im_part"); re = new DImValue(baserety, reVal); im = new DImValue(baseimty, imVal); } } else { DtoGetComplexParts(loc, to, v, re, im); } } else if (t->isimaginary()) { re = nullptr; im = DtoCastFloat(loc, val, baseimty); } else if (t->isfloating()) { re = DtoCastFloat(loc, val, baserety); im = nullptr; } else if (t->isintegral()) { re = DtoCastInt(loc, val, baserety); im = nullptr; } else { llvm_unreachable("Unexpected numeric type."); } }
DValue *binMul(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (type->iscomplex()) return DtoComplexMul(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); LLValue *res = (type->isfloating() ? gIR->ir->CreateFMul(l, r) : gIR->ir->CreateMul(l, r)); return new DImValue(type, res); }
LLValue *DtoCallableValue(DValue *fn) { Type *type = fn->type->toBasetype(); if (type->ty == Tfunction) { return DtoRVal(fn); } if (type->ty == Tdelegate) { if (fn->isLVal()) { LLValue *dg = DtoLVal(fn); LLValue *funcptr = DtoGEPi(dg, 0, 1); return DtoLoad(funcptr, ".funcptr"); } LLValue *dg = DtoRVal(fn); assert(isaStruct(dg)); return gIR->ir->CreateExtractValue(dg, 1, ".funcptr"); } llvm_unreachable("Not a callable type."); }
void vaCopy(DLValue *dest, DValue *src) override { // Analog to va_start, we first need to allocate a new __va_list struct on // the stack and set `dest` to its address. LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem"); DtoStore(valistmem, DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType()))); // Then fill the new struct with a bitcopy of the source struct. // `src` is a char* pointer to the source struct. DtoMemCpy(valistmem, DtoRVal(src)); }
LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) { Type *t = l->type->toBasetype(); assert(t == r->type->toBasetype() && "aa equality is only defined for aas of same type"); llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaEqual"); LLFunctionType *funcTy = func->getFunctionType(); LLValue *aaval = DtoBitCast(DtoRVal(l), funcTy->getParamType(1)); LLValue *abval = DtoBitCast(DtoRVal(r), funcTy->getParamType(2)); LLValue *aaTypeInfo = DtoTypeInfoOf(t); LLValue *res = gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes") .getInstruction(); const auto predicate = eqTokToICmpPred(op, /* invert = */ true); res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0)); return res; }
DValue *binMod(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (type->iscomplex()) return DtoComplexMod(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); LLValue *res; if (type->isfloating()) { res = gIR->ir->CreateFRem(l, r); } else if (!isLLVMUnsigned(type)) { res = gIR->ir->CreateSRem(l, r); } else { res = gIR->ir->CreateURem(l, r); } return new DImValue(type, res); }
DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { Type *lhsType = lhs->type->toBasetype(); Type *rhsType = rhs->type->toBasetype(); if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { Logger::println("Subtracting integer from pointer"); return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs); } auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) { LLValue *l = DtoRVal(rvals.lhs); LLValue *r = DtoRVal(rvals.rhs); LLType *llSizeT = DtoSize_t(); l = gIR->ir->CreatePtrToInt(l, llSizeT); r = gIR->ir->CreatePtrToInt(r, llSizeT); LLValue *diff = gIR->ir->CreateSub(l, r); LLType *llType = DtoType(type); if (diff->getType() != llType) diff = gIR->ir->CreateIntToPtr(diff, llType); return new DImValue(type, diff); } if (type->ty == Tnull) return DtoNullValue(type, loc); if (type->iscomplex()) return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs); LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); if (auto aa = isAssociativeArrayAndNull(type, l, r)) return aa; LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r) : gIR->ir->CreateSub(l, r)); return new DImValue(type, res); }
LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) { LLValue *res = nullptr; if (op == TOKequal || op == TOKnotequal) { LLValue *l = DtoRVal(lhs); LLValue *r = DtoRVal(rhs); res = (op == TOKequal ? gIR->ir->CreateFCmpOEQ(l, r) : gIR->ir->CreateFCmpUNE(l, r)); if (lhs->type->toBasetype()->ty == Tvector) { res = mergeVectorEquals(res, op); } } else { const auto cmpop = op == TOKidentity ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; LLValue *sz = DtoConstSize_t(getTypeStoreSize(DtoType(lhs->type))); LLValue *val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz); res = gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false)); } assert(res); return res; }
DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key) { // D1: // call: // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaInX"); LLFunctionType *funcTy = func->getFunctionType(); IF_LOG Logger::cout() << "_aaIn = " << *func << '\n'; // aa param LLValue *aaval = DtoRVal(aa); IF_LOG { Logger::cout() << "aaval: " << *aaval << '\n'; Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n'; } aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param LLValue *keyti = to_keyti(aa); keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue *pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, getVoidPtrType()); // call runtime LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in") .getInstruction(); // cast return value LLType *targettype = DtoType(type); if (ret->getType() != targettype) { ret = DtoBitCast(ret, targettype); } return new DImValue(type, ret); }
DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key) { // D1: // call: // extern(C) void _aaDel(AA aa, TypeInfo keyti, void* pkey) // D2: // call: // extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaDelX"); LLFunctionType *funcTy = func->getFunctionType(); IF_LOG Logger::cout() << "_aaDel = " << *func << '\n'; // aa param LLValue *aaval = DtoRVal(aa); IF_LOG { Logger::cout() << "aaval: " << *aaval << '\n'; Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n'; } aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // keyti param LLValue *keyti = to_keyti(aa); keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // pkey param LLValue *pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(2)); // call runtime LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey); return new DImValue(Type::tbool, call.getInstruction()); }
void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) { IF_LOG Logger::println("InlineAsmStatement::toIR(): %s", stmt->loc.toChars()); LOG_SCOPE; // sanity check assert(irs->func()->decl->hasReturnExp & 8); // get asm block IRAsmBlock *asmblock = irs->asmBlock; assert(asmblock); // debug info gIR->DBuilder.EmitStopPoint(stmt->loc); if (!stmt->asmcode) { return; } static std::string i_cns = "i"; static std::string p_cns = "i"; static std::string m_cns = "*m"; static std::string mw_cns = "=*m"; static std::string mrw_cns = "+*m"; static std::string memory_name = "memory"; AsmCode *code = static_cast<AsmCode *>(stmt->asmcode); std::vector<LLValue *> input_values; std::vector<std::string> input_constraints; std::vector<LLValue *> output_values; std::vector<std::string> output_constraints; std::vector<std::string> clobbers; // FIXME //#define HOST_WIDE_INT long // HOST_WIDE_INT var_frame_offset; // "frame_offset" is a macro bool clobbers_mem = code->clobbersMemory; int input_idx = 0; int n_outputs = 0; int arg_map[10]; assert(code->args.size() <= 10); auto arg = code->args.begin(); for (unsigned i = 0; i < code->args.size(); i++, ++arg) { bool is_input = true; LLValue *arg_val = nullptr; std::string cns; switch (arg->type) { case Arg_Integer: arg_val = DtoRVal(arg->expr); do_integer: cns = i_cns; break; case Arg_Pointer: assert(arg->expr->op == TOKvar); arg_val = DtoRVal(arg->expr); cns = p_cns; break; case Arg_Memory: arg_val = DtoRVal(arg->expr); switch (arg->mode) { case Mode_Input: cns = m_cns; break; case Mode_Output: cns = mw_cns; is_input = false; break; case Mode_Update: cns = mrw_cns; is_input = false; break; } break; case Arg_FrameRelative: // FIXME llvm_unreachable("Arg_FrameRelative not supported."); /* if (arg->expr->op == TOKvar) arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree; else assert(0); if ( getFrameRelativeValue(arg_val, & var_frame_offset) ) { // arg_val = irs->integerConstant(var_frame_offset); cns = i_cns; } else { this->error("%s", "argument not frame relative"); return; } if (arg->mode != Mode_Input) clobbers_mem = true; break;*/ case Arg_LocalSize: // FIXME llvm_unreachable("Arg_LocalSize not supported."); /* var_frame_offset = cfun->x_frame_offset; if (var_frame_offset < 0) var_frame_offset = - var_frame_offset; arg_val = irs->integerConstant( var_frame_offset );*/ goto do_integer; default: llvm_unreachable("Unknown inline asm reference type."); } if (is_input) { arg_map[i] = --input_idx; input_values.push_back(arg_val); input_constraints.push_back(cns); } else { arg_map[i] = n_outputs++; output_values.push_back(arg_val); output_constraints.push_back(cns); } } // Telling GCC that callee-saved registers are clobbered makes it preserve // those registers. This changes the stack from what a naked function // expects. // FIXME // if (! irs->func->naked) { assert(asmparser); for (size_t i = 0; i < code->regs.size(); i++) { if (code->regs[i]) { clobbers.push_back(asmparser->getRegName(i)); } } if (clobbers_mem) { clobbers.push_back(memory_name); } // } // Remap argument numbers for (unsigned i = 0; i < code->args.size(); i++) { if (arg_map[i] < 0) { arg_map[i] = -arg_map[i] - 1 + n_outputs; } } bool pct = false; auto p = code->insnTemplate.begin(); auto q = code->insnTemplate.end(); // printf("start: %.*s\n", code->insnTemplateLen, code->insnTemplate); while (p < q) { if (pct) { if (*p >= '0' && *p <= '9') { // %% doesn't check against nargs *p = '0' + arg_map[*p - '0']; pct = false; } else if (*p == '$') { pct = false; } // assert(*p == '%');// could be 'a', etc. so forget it.. } else if (*p == '$') { pct = true; } ++p; } IF_LOG { Logger::cout() << "final asm: " << code->insnTemplate << '\n'; std::ostringstream ss; ss << "GCC-style output constraints: {"; for (const auto &oc : output_constraints) { ss << " " << oc; } ss << " }"; Logger::println("%s", ss.str().c_str()); ss.str(""); ss << "GCC-style input constraints: {"; for (const auto &ic : input_constraints) { ss << " " << ic; } ss << " }"; Logger::println("%s", ss.str().c_str()); ss.str(""); ss << "GCC-style clobbers: {"; for (const auto &c : clobbers) { ss << " " << c; } ss << " }"; Logger::println("%s", ss.str().c_str()); } // rewrite GCC-style constraints to LLVM-style constraints std::string llvmOutConstraints; std::string llvmInConstraints; int n = 0; for (auto &oc : output_constraints) { // rewrite update constraint to in and out constraints if (oc[0] == '+') { assert(oc == mrw_cns && "What else are we updating except memory?"); /* LLVM doesn't support updating operands, so split into an input * and an output operand. */ // Change update operand to pure output operand. oc = mw_cns; // Add input operand with same value, with original as "matching output". std::ostringstream ss; ss << '*' << (n + asmblock->outputcount); // Must be at the back; unused operands before used ones screw up // numbering. input_constraints.push_back(ss.str()); input_values.push_back(output_values[n]); } llvmOutConstraints += oc; llvmOutConstraints += ","; n++; } asmblock->outputcount += n; for (const auto &ic : input_constraints) { llvmInConstraints += ic; llvmInConstraints += ","; } std::string clobstr; for (const auto &c : clobbers) { clobstr = "~{" + c + "},"; asmblock->clobs.insert(clobstr); } IF_LOG { { Logger::println("Output values:"); LOG_SCOPE size_t i = 0; for (auto ov : output_values) { Logger::cout() << "Out " << i++ << " = " << *ov << '\n'; } } { Logger::println("Input values:"); LOG_SCOPE size_t i = 0; for (auto iv : input_values) { Logger::cout() << "In " << i++ << " = " << *iv << '\n'; } } } // excessive commas are removed later... replace_func_name(irs, code->insnTemplate); // push asm statement auto asmStmt = new IRAsmStmt; asmStmt->code = code->insnTemplate; asmStmt->out_c = llvmOutConstraints; asmStmt->in_c = llvmInConstraints; asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end()); asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end()); asmStmt->isBranchToLabel = stmt->isBranchToLabel; asmblock->s.push_back(asmStmt); }
DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) { // D2: // call: // extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void* // pkey) // or // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey) // first get the runtime function llvm::Function *func = getRuntimeFunction(loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX"); LLFunctionType *funcTy = func->getFunctionType(); // aa param LLValue *aaval = lvalue ? DtoLVal(aa) : DtoRVal(aa); aaval = DtoBitCast(aaval, funcTy->getParamType(0)); // pkey param LLValue *pkey = makeLValue(loc, key); pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2)); // call runtime LLValue *ret; if (lvalue) { LLValue *rawAATI = DtoTypeInfoOf(aa->type->unSharedOf()->mutableOf(), false); LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1)); LLValue *valsize = DtoConstSize_t(getTypeAllocSize(DtoType(type))); ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey, "aa.index") .getInstruction(); } else { LLValue *keyti = DtoBitCast(to_keyti(aa), funcTy->getParamType(1)); ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index") .getInstruction(); } // cast return value LLType *targettype = DtoPtrToType(type); if (ret->getType() != targettype) { ret = DtoBitCast(ret, targettype); } // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. if (!lvalue && gIR->emitArrayBoundsChecks()) { llvm::BasicBlock *okbb = gIR->insertBB("aaboundsok"); llvm::BasicBlock *failbb = gIR->insertBBAfter(okbb, "aaboundscheckfail"); LLValue *nullaa = LLConstant::getNullValue(ret->getType()); LLValue *cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck"); gIR->ir->CreateCondBr(cond, okbb, failbb); // set up failbb to call the array bounds error runtime function gIR->scope() = IRScope(failbb); llvm::Function *errorfn = getRuntimeFunction(loc, gIR->module, "_d_arraybounds"); gIR->CreateCallOrInvoke( errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc), DtoConstUint(loc.linnum)); // the function does not return gIR->ir->CreateUnreachable(); // if ok, proceed in okbb gIR->scope() = IRScope(okbb); } return new DLValue(type, ret); }
DValue *DtoCastComplex(Loc &loc, DValue *val, Type *_to) { Type *to = _to->toBasetype(); Type *vty = val->type->toBasetype(); if (to->iscomplex()) { if (vty->size() == to->size()) { return val; } llvm::Value *re, *im; DtoGetComplexParts(loc, val->type, val, re, im); LLType *toty = DtoComplexBaseType(to); if (to->size() < vty->size()) { re = gIR->ir->CreateFPTrunc(re, toty); im = gIR->ir->CreateFPTrunc(im, toty); } else { re = gIR->ir->CreateFPExt(re, toty); im = gIR->ir->CreateFPExt(im, toty); } LLValue *pair = DtoAggrPair(DtoType(_to), re, im); return new DImValue(_to, pair); } if (to->isimaginary()) { // FIXME: this loads both values, even when we only need one LLValue *v = DtoRVal(val); LLValue *impart = gIR->ir->CreateExtractValue(v, 1, ".im_part"); Type *extractty; switch (vty->ty) { default: llvm_unreachable("Unexpected complex floating point type"); case Tcomplex32: extractty = Type::timaginary32; break; case Tcomplex64: extractty = Type::timaginary64; break; case Tcomplex80: extractty = Type::timaginary80; break; } auto im = new DImValue(extractty, impart); return DtoCastFloat(loc, im, to); } if (to->ty == Tbool) { return new DImValue( _to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty))); } if (to->isfloating() || to->isintegral()) { // FIXME: this loads both values, even when we only need one LLValue *v = DtoRVal(val); LLValue *repart = gIR->ir->CreateExtractValue(v, 0, ".re_part"); Type *extractty; switch (vty->ty) { default: llvm_unreachable("Unexpected complex floating point type"); case Tcomplex32: extractty = Type::tfloat32; break; case Tcomplex64: extractty = Type::tfloat64; break; case Tcomplex80: extractty = Type::tfloat80; break; } auto re = new DImValue(extractty, repart); return DtoCastFloat(loc, re, to); } error(loc, "Don't know how to cast %s to %s", vty->toChars(), to->toChars()); fatal(); }
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue *mem; bool doInit = true; if (newexp->onstack) { unsigned alignment = tc->sym->alignsize; if (alignment == STRUCTALIGN_DEFAULT) alignment = 0; mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), alignment, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator)); DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs); mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom"); } // default allocator else { const bool useEHAlloc = global.params.ehnogc && newexp->thrownew; llvm::Function *fn = getRuntimeFunction( loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass"); LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(getClassInfoType())); mem = gIR->CreateCallOrInvoke(fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc") .getInstruction(); mem = DtoBitCast(mem, DtoType(tc), useEHAlloc ? ".newthrowable" : ".newclass_gc"); doInit = !useEHAlloc; } // init if (doInit) DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue *src = DtoRVal(newexp->thisexp); LLValue *dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { // evaluate argprefix if (newexp->argprefix) { toElemDtor(newexp->argprefix); } Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem); // ignore ctor return value (C++ ctors on Posix may not return `this`) DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); return new DImValue(tc, mem); } assert(newexp->argprefix == NULL); // return default constructed class return new DImValue(tc, mem); }
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(), _to->toChars()); LOG_SCOPE; Type *to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType *tolltype = DtoType(_to); LLValue *rval = DtoBitCast(DtoRVal(val), tolltype); return new DImValue(_to, rval); } // class -> bool if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue *llval = DtoRVal(val); LLValue *zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue *v = DtoRVal(val); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // class -> typeof(null) if (to->ty == Tnull) { IF_LOG Logger::println("to %s", to->toChars()); return new DImValue(_to, LLConstant::getNullValue(DtoType(_to))); } // must be class/interface assert(to->ty == Tclass); TypeClass *tc = static_cast<TypeClass *>(to); // from type Type *from = val->type->toBasetype(); TypeClass *fc = static_cast<TypeClass *>(from); // copy DMD logic: // if to isBaseOf from with offset: (to ? to + offset : null) // else if from is C++ and to is C++: to // else if from is C++ and to is D: null // else if from is interface: _d_interface_cast(to) // else if from is class: _d_dynamic_cast(to) LLType *toType = DtoType(_to); int offset = 0; if (tc->sym->isBaseOf(fc->sym, &offset)) { Logger::println("static down cast"); // interface types don't cover the full object in case of multiple inheritence // so GEP on the original type is inappropriate // offset pointer LLValue *orig = DtoRVal(val); LLValue *v = orig; if (offset != 0) { v = DtoBitCast(v, getVoidPtrType()); LLValue *off = LLConstantInt::get(LLType::getInt32Ty(gIR->context()), offset); v = gIR->ir->CreateGEP(v, off); } IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *toType << std::endl; } v = DtoBitCast(v, toType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was // null. LLValue *isNull = gIR->ir->CreateICmpEQ( orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(toType), v, ".interface"); // return r-value return new DImValue(_to, v); }
LLValue *prepareVaArg(DLValue *ap) override { // Pass a i8* pointer to the actual __va_list struct to LLVM's va_arg // intrinsic. return DtoRVal(ap); }
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue *mem; if (newexp->onstack) { mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), DtoAlignment(tc), ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator)); DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs); mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocclass"); LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue *src = DtoRVal(newexp->thisexp); LLValue *dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { // evaluate argprefix if (newexp->argprefix) { toElemDtor(newexp->argprefix); } Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } assert(newexp->argprefix == NULL); // return default constructed class return new DImValue(tc, mem); }