void rewriteFunctionType(IrFuncTy &fty) override { const bool externD = (fty.type->linkage == LINKd && fty.type->parameterList.varargs != VARARGvariadic); // return value: if (!fty.ret->byref) { Type *rt = fty.type->next->toBasetype(); // for sret, rt == void if (isAggregate(rt) && !isMagicCppStruct(rt) && canRewriteAsInt(rt) && // don't rewrite cfloat for extern(D) !(externD && rt->ty == Tcomplex32)) { integerRewrite.applyToIfNotObsolete(*fty.ret); } } // extern(D): try passing an argument in EAX if (externD) { // try an implicit argument... if (fty.arg_this) { Logger::println("Putting 'this' in register"); fty.arg_this->attrs.addAttribute(LLAttribute::InReg); } else if (fty.arg_nest) { Logger::println("Putting context ptr in register"); fty.arg_nest->attrs.addAttribute(LLAttribute::InReg); } else if (IrFuncTyArg *sret = fty.arg_sret) { Logger::println("Putting sret ptr in register"); // sret and inreg are incompatible, but the ABI requires the // sret parameter to be in EAX in this situation... sret->attrs.removeAttribute(LLAttribute::StructRet); sret->attrs.addAttribute(LLAttribute::InReg); } // ... otherwise try the last argument else if (!fty.args.empty()) { // The last parameter is passed in EAX rather than being pushed on the // stack if the following conditions are met: // * It fits in EAX. // * It is not a 3 byte struct. // * It is not a floating point type. IrFuncTyArg *last = fty.args.back(); Type *lastTy = last->type->toBasetype(); unsigned sz = lastTy->size(); if (last->byref && !last->isByVal()) { Logger::println("Putting last (byref) parameter in register"); last->attrs.addAttribute(LLAttribute::InReg); } else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) { // rewrite aggregates as integers to make inreg work if (lastTy->ty == Tstruct || lastTy->ty == Tsarray) { integerRewrite.applyTo(*last); // undo byval semantics applied via passByVal() returning true last->byref = false; last->attrs.clear(); } last->attrs.addAttribute(LLAttribute::InReg); } } // all other arguments are passed on the stack, don't rewrite } // extern(C++) on Posix: non-POD args are passed indirectly by-value else if (!isMSVC && fty.type->linkage == LINKcpp) { for (auto arg : fty.args) { if (!arg->byref && !isPOD(arg->type)) indirectByvalRewrite.applyTo(*arg); } } workaroundIssue1356(fty.args); // Clang does not pass empty structs, while it seems that GCC does, // at least on Linux x86. We don't know whether the C compiler will // be Clang or GCC, so just assume Clang on OS X and G++ on Linux. if (externD || !isOSX) return; size_t i = 0; while (i < fty.args.size()) { Type *type = fty.args[i]->type->toBasetype(); if (type->ty == Tstruct) { // Do not pass empty structs at all for C++ ABI compatibility. // Tests with clang reveal that more complex "empty" types, for // example a struct containing an empty struct, are not // optimized in the same way. auto sd = static_cast<TypeStruct *>(type)->sym; if (sd->fields.empty()) { fty.args.erase(fty.args.begin() + i); continue; } } ++i; } }
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; } }
void rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty) { // extern(D) if (tf->linkage == LINKd) { // IMPLICIT PARAMETERS // mark this/nested params inreg if (fty.arg_this) { Logger::println("Putting 'this' in register"); fty.arg_this->attrs.clear() .add(LDC_ATTRIBUTE(InReg)); } else if (fty.arg_nest) { Logger::println("Putting context ptr in register"); fty.arg_nest->attrs.clear() .add(LDC_ATTRIBUTE(InReg)); } else if (IrFuncTyArg* sret = fty.arg_sret) { Logger::println("Putting sret ptr in register"); // sret and inreg are incompatible, but the ABI requires the // sret parameter to be in EAX in this situation... sret->attrs.add(LDC_ATTRIBUTE(InReg)).remove(LDC_ATTRIBUTE(StructRet)); } // otherwise try to mark the last param inreg else if (!fty.args.empty()) { // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met: // * It fits in EAX. // * It is not a 3 byte struct. // * It is not a floating point type. IrFuncTyArg* last = fty.args.back(); Type* lastTy = last->type->toBasetype(); unsigned sz = lastTy->size(); if (last->byref && !last->isByVal()) { Logger::println("Putting last (byref) parameter in register"); last->attrs.add(LDC_ATTRIBUTE(InReg)); } else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right? { // rewrite the struct into an integer to make inreg work if (lastTy->ty == Tstruct || lastTy->ty == Tsarray) { last->rewrite = &integerRewrite; last->ltype = integerRewrite.type(last->type, last->ltype); last->byref = false; // erase previous attributes last->attrs.clear(); } last->attrs.add(LDC_ATTRIBUTE(InReg)); } } // FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec: // "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee." // EXPLICIT PARAMETERS // reverse parameter order // for non variadics if (!fty.args.empty() && tf->varargs != 1) { fty.reverseParams = true; } } // extern(C) and all others else { // RETURN VALUE // cfloat -> i64 if (tf->next->toBasetype() == Type::tcomplex32) { fty.ret->rewrite = &integerRewrite; fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype); } // IMPLICIT PARAMETERS // EXPLICIT PARAMETERS } }
void rewriteFunctionType(TypeFunction* tf) { IrFuncTy& fty = tf->fty; Type* rt = fty.ret->type->toBasetype(); // extern(D) if (tf->linkage == LINKd) { // RETURN VALUE // complex {re,im} -> {im,re} if (rt->iscomplex()) { Logger::println("Rewriting complex return value"); fty.ret->rewrite = &swapComplex; } // IMPLICIT PARAMETERS // mark this/nested params inreg if (fty.arg_this) { Logger::println("Putting 'this' in register"); #if LDC_LLVM_VER >= 302 fty.arg_this->attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::InReg)); #else fty.arg_this->attrs = llvm::Attribute::InReg; #endif } else if (fty.arg_nest) { Logger::println("Putting context ptr in register"); #if LDC_LLVM_VER >= 302 fty.arg_nest->attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::InReg)); #else fty.arg_nest->attrs = llvm::Attribute::InReg; #endif } else if (IrFuncTyArg* sret = fty.arg_sret) { Logger::println("Putting sret ptr in register"); // sret and inreg are incompatible, but the ABI requires the // sret parameter to be in EAX in this situation... #if LDC_LLVM_VER >= 302 sret->attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder(sret->attrs).addAttribute(llvm::Attributes::InReg) .removeAttribute(llvm::Attributes::StructRet)); #else sret->attrs = (sret->attrs | llvm::Attribute::InReg) & ~llvm::Attribute::StructRet; #endif } // otherwise try to mark the last param inreg else if (!fty.args.empty()) { // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met: // * It fits in EAX. // * It is not a 3 byte struct. // * It is not a floating point type. IrFuncTyArg* last = fty.args.back(); Type* lastTy = last->type->toBasetype(); unsigned sz = lastTy->size(); if (last->byref && !last->isByVal()) { Logger::println("Putting last (byref) parameter in register"); #if LDC_LLVM_VER >= 302 last->attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder(last->attrs).addAttribute(llvm::Attributes::InReg)); #else last->attrs |= llvm::Attribute::InReg; #endif } else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right? { // rewrite the struct into an integer to make inreg work if (lastTy->ty == Tstruct || lastTy->ty == Tsarray) { last->rewrite = &compositeToInt; last->ltype = compositeToInt.type(last->type, last->ltype); last->byref = false; // erase previous attributes #if LDC_LLVM_VER >= 302 last->attrs = llvm::Attributes(); #else last->attrs = llvm::Attribute::None; #endif } #if LDC_LLVM_VER >= 302 last->attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder(last->attrs).addAttribute(llvm::Attributes::InReg)); #else last->attrs |= llvm::Attribute::InReg; #endif } } // FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec: // "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee." // EXPLICIT PARAMETERS // reverse parameter order // for non variadics if (!fty.args.empty() && tf->varargs != 1) { fty.reverseParams = true; } } // extern(C) and all others else { // RETURN VALUE // cfloat -> i64 if (tf->next->toBasetype() == Type::tcomplex32) { fty.ret->rewrite = &cfloatToInt; fty.ret->ltype = LLType::getInt64Ty(gIR->context()); } // IMPLICIT PARAMETERS // EXPLICIT PARAMETERS } }