DValue* DtoArgument(Parameter* fnarg, Expression* argexp) { IF_LOG Logger::println("DtoArgument"); LOG_SCOPE; DValue* arg = toElem(argexp); // ref/out arg if (fnarg && (fnarg->storageClass & (STCref | STCout))) { Loc loc; arg = new DImValue(argexp->type, makeLValue(loc, arg)); } // lazy arg else if (fnarg && (fnarg->storageClass & STClazy)) { assert(argexp->type->toBasetype()->ty == Tdelegate); assert(!arg->isLVal()); return arg; } // byval arg, but expr has no storage yet else if (DtoIsPassedByRef(argexp->type) && (arg->isSlice() || arg->isNull())) { LLValue* alloc = DtoAlloca(argexp->type, ".tmp_arg"); DVarValue* vv = new DVarValue(argexp->type, alloc); DtoAssign(argexp->loc, vv, arg); arg = vv; } return arg; }
DValue* DtoNewClass(Loc& loc, TypeClass* tc, NewExp* newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue* mem; if (newexp->onstack) { // FIXME align scope class to its largest member mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, getIrFunc(newexp->allocator)->func); DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass"); LLConstant* ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; DValue* thisval = toElem(newexp->thisexp); unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue* src = thisval->getRVal(); LLValue* dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, getIrFunc(newexp->member)->func, mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } // return default constructed class return new DImValue(tc, mem); }
void AsmStatement_toIR(AsmStatement *stmt, IRState * irs) { IF_LOG Logger::println("AsmStatement::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.linnum); 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); std::vector<AsmArg>::iterator arg = code->args.begin(); for (unsigned i = 0; i < code->args.size(); i++, ++arg) { bool is_input = true; LLValue* arg_val = 0; std::string cns; switch (arg->type) { case Arg_Integer: arg_val = toElem(arg->expr)->getRVal(); do_integer: cns = i_cns; break; case Arg_Pointer: assert(arg->expr->op == TOKvar); arg_val = toElem(arg->expr)->getRVal(); cns = p_cns; break; case Arg_Memory: arg_val = toElem(arg->expr)->getRVal(); 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; default: llvm_unreachable("Unknown inline asm reference mode."); 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; std::string::iterator p = code->insnTemplate.begin(), 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; } typedef std::vector<std::string>::iterator It; IF_LOG { Logger::cout() << "final asm: " << code->insnTemplate << '\n'; std::ostringstream ss; ss << "GCC-style output constraints: {"; for (It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i) { ss << " " << *i; } ss << " }"; Logger::println("%s", ss.str().c_str()); ss.str(""); ss << "GCC-style input constraints: {"; for (It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) { ss << " " << *i; } ss << " }"; Logger::println("%s", ss.str().c_str()); ss.str(""); ss << "GCC-style clobbers: {"; for (It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) { ss << " " << *i; } 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(It i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) { // rewrite update constraint to in and out constraints if((*i)[0] == '+') { assert(*i == 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. *i = 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 += *i; llvmOutConstraints += ","; } asmblock->outputcount += n; for(It i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) { llvmInConstraints += *i; llvmInConstraints += ","; } std::string clobstr; for(It i = clobbers.begin(), e = clobbers.end(); i != e; ++i) { clobstr = "~{" + *i + "},"; asmblock->clobs.insert(clobstr); } IF_LOG { typedef std::vector<LLValue*>::iterator It; { Logger::println("Output values:"); LOG_SCOPE size_t i = 0; for (It I = output_values.begin(), E = output_values.end(); I != E; ++I) { Logger::cout() << "Out " << i++ << " = " << **I << '\n'; } } { Logger::println("Input values:"); LOG_SCOPE size_t i = 0; for (It I = input_values.begin(), E = input_values.end(); I != E; ++I) { Logger::cout() << "In " << i++ << " = " << **I << '\n'; } } } // excessive commas are removed later... replace_func_name(irs, code->insnTemplate); // push asm statement IRAsmStmt* 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); }