void rewriteFunctionType(IrFuncTy &fty) override { Type *retTy = fty.ret->type->toBasetype(); if (!fty.ret->byref && retTy->ty == Tstruct) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) { hfaToArray.applyTo(*fty.ret, fty.ret->ltype); } else { integerRewrite.applyTo(*fty.ret); } } for (auto arg : fty.args) { if (!arg->byref) rewriteArgument(fty, *arg); } }
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; } }