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; }
LLValue* DVarValue::getRVal() { assert(val); Type* bt = type->toBasetype(); if (DtoIsPassedByRef(bt)) return val; return DtoLoad(val); }
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs, IrFuncTy &irFty, LLFunctionType *callableTy, const std::vector<DValue *> &argvals, int numFormalParams) { // Number of arguments added to the LLVM type that are implicit on the // frontend side of things (this, context pointers, etc.) const size_t implicitLLArgCount = args.size(); // Number of formal arguments in the LLVM type (i.e. excluding varargs). const size_t formalLLArgCount = irFty.args.size(); // The number of explicit arguments in the D call expression (including // varargs), not all of which necessarily generate a LLVM argument. const size_t explicitDArgCount = argvals.size(); // construct and initialize an IrFuncTyArg object for each vararg std::vector<IrFuncTyArg *> optionalIrArgs; for (size_t i = numFormalParams; i < explicitDArgCount; i++) { Type *argType = argvals[i]->getType(); bool passByVal = gABI->passByVal(argType); AttrBuilder initialAttrs; if (passByVal) { initialAttrs.add(LLAttribute::ByVal); } else { initialAttrs.add(DtoShouldExtend(argType)); } optionalIrArgs.push_back(new IrFuncTyArg(argType, passByVal, initialAttrs)); optionalIrArgs.back()->parametersIdx = i; } // let the ABI rewrite the IrFuncTyArg objects gABI->rewriteVarargs(irFty, optionalIrArgs); const size_t explicitLLArgCount = formalLLArgCount + optionalIrArgs.size(); args.resize(implicitLLArgCount + explicitLLArgCount, static_cast<llvm::Value *>(nullptr)); // Iterate the explicit arguments from left to right in the D source, // which is the reverse of the LLVM order if irFty.reverseParams is true. for (size_t i = 0; i < explicitLLArgCount; ++i) { const bool isVararg = (i >= irFty.args.size()); IrFuncTyArg *irArg = nullptr; if (isVararg) { irArg = optionalIrArgs[i - numFormalParams]; } else { irArg = irFty.args[i]; } DValue *const argval = argvals[irArg->parametersIdx]; Type *const argType = argval->getType(); llvm::Value *llVal = nullptr; if (isVararg) { llVal = irFty.putParam(*irArg, argval); } else { llVal = irFty.putParam(i, argval); } const size_t llArgIdx = implicitLLArgCount + (irFty.reverseParams ? explicitLLArgCount - i - 1 : i); llvm::Type *const callableArgType = (isVararg ? nullptr : callableTy->getParamType(llArgIdx)); // Hack around LDC assuming structs and static arrays are in memory: // If the function wants a struct, and the argument value is a // pointer to a struct, load from it before passing it in. if (isaPointer(llVal) && DtoIsPassedByRef(argType) && ((!isVararg && !isaPointer(callableArgType)) || (isVararg && !irArg->byref && !irArg->isByVal()))) { Logger::println("Loading struct type for function argument"); llVal = DtoLoad(llVal); } // parameter type mismatch, this is hard to get rid of if (!isVararg && llVal->getType() != callableArgType) { IF_LOG { Logger::cout() << "arg: " << *llVal << '\n'; Logger::cout() << "expects: " << *callableArgType << '\n'; } if (isaStruct(llVal)) { llVal = DtoAggrPaint(llVal, callableArgType); } else { llVal = DtoBitCast(llVal, callableArgType); } } args[llArgIdx] = llVal; // +1 as index 0 contains the function attributes. attrs.add(llArgIdx + 1, irArg->attrs); if (isVararg) { delete irArg; } }