diff --git a/dmd/mtype.c b/dmd/mtype.c index a7c8a210..98c37eeb 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -2691,7 +2691,7 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en this->retInPtr = false; this->usesThis = false; this->usesNest = false; - this->structInregArg = false; + this->structInregArg = NULL; this->retAttrs = 0; this->thisAttrs = 0; this->reverseParams = false; diff --git a/dmd/mtype.h b/dmd/mtype.h index c9ed4a4e..9b6fd9c4 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -23,6 +23,7 @@ // llvm #include "../ir/irtype.h" +namespace llvm { class Type; } struct Scope; struct Identifier; @@ -438,7 +439,8 @@ struct TypeFunction : Type bool retInPtr; bool usesThis; bool usesNest; - bool structInregArg; + // when the last arg is a struct and passed in EAX, this holds its real type + const llvm::Type* structInregArg; unsigned retAttrs; unsigned thisAttrs; // also used for nest // parameter index in the llvm function that contains the first not-implicit arg diff --git a/gen/functions.cpp b/gen/functions.cpp index 4a09ea3f..e4f8ce73 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -220,15 +220,15 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co arg->llvmAttrs |= llvm::Attribute::InReg; assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!"); - // structs need to go from {...}* byval to {...} inreg + // structs need to go from {...}* byval to i8/i16/i32 inreg if ((arg->storageClass & STCin) && t->ty == Tstruct) { int n_param = f->reverseParams ? f->firstRealArg + n - 1 - n_inreg : f->firstRealArg + n_inreg; assert(isaPointer(paramvec[n_param]) && (arg->llvmAttrs & llvm::Attribute::ByVal) && "struct parameter expected to be {...}* byval before inreg is applied"); - paramvec[n_param] = paramvec[n_param]->getContainedType(0); + f->structInregArg = paramvec[n_param]->getContainedType(0); + paramvec[n_param] = LLIntegerType::get(8*t->size()); arg->llvmAttrs &= ~llvm::Attribute::ByVal; - f->structInregArg = true; } } } @@ -759,11 +759,14 @@ void DtoDefineFunction(FuncDeclaration* fd) if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0)) { int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i; - assert(!f->usesNest && !f->usesThis && isaStruct(functype->getParamType(n_param)) + const LLType* paramty = functype->getParamType(n_param); + assert(!f->usesNest && !f->usesThis && + llvm::isa(paramty) && isaStruct(f->structInregArg) && "Preconditions for inreg struct arg not met!"); - LLValue* mem = DtoAlloca(functype->getParamType(n_param), "inregstructarg"); - DtoStore(irloc->value, mem); + LLValue* mem = DtoAlloca(f->structInregArg, "inregstructarg"); + + DtoStore(irloc->value, DtoBitCast(mem, getPtrToType(paramty))); irloc->value = mem; } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index a3af9fa3..11f34f52 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -370,15 +370,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); LLValue* arg = argval->getRVal(); + int j = tf->reverseParams ? beg + n - i - 1 : beg + i; + // if it's a struct inreg arg, load first to pass as first-class value if (tf->structInregArg && i == (tf->reverseParams ? n - 1 : 0)) { - assert(fnarg->llvmAttrs & llvm::Attribute::InReg); + assert((fnarg->llvmAttrs & llvm::Attribute::InReg) && isaStruct(tf->structInregArg)); + arg = DtoBitCast(arg, getPtrToType(callableTy->getParamType(j))); arg = DtoLoad(arg); } - int j = tf->reverseParams ? beg + n - i - 1 : beg + i; - // parameter type mismatch, this is hard to get rid of if (arg->getType() != callableTy->getParamType(j)) {