diff --git a/dmd/mtype.c b/dmd/mtype.c index 7eba380e51..551bb82ea2 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -2672,6 +2672,7 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en this->usesThis = false; this->usesNest = false; this->retAttrs = 0; + this->thisAttrs = 0; } Type *TypeFunction::syntaxCopy() @@ -2683,6 +2684,7 @@ Type *TypeFunction::syntaxCopy() t->usesThis = usesThis; t->usesNest = usesNest; t->retAttrs = retAttrs; + t->thisAttrs = thisAttrs; return t; } diff --git a/dmd/mtype.h b/dmd/mtype.h index c1463dee3c..2b5212fa4e 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -439,6 +439,7 @@ struct TypeFunction : Type bool usesThis; bool usesNest; unsigned retAttrs; + unsigned thisAttrs; // also used for nest }; struct TypeDelegate : Type diff --git a/gen/functions.cpp b/gen/functions.cpp index 4c201e8cfe..3e06e95ee4 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -171,6 +171,39 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co bool isvararg = !(typesafeVararg || arrayVararg) && f->varargs; llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); + // tell first param to be passed in a register if we can + // ONLY extern(D) functions ! + if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) + { + // FIXME: Only x86 right now ... + if (global.params.cpu == ARCHx86) + { + // pass first param in EAX if it fits, is not floating point and is not a 3 byte struct. + // FIXME: struct are not passed in EAX yet + + // if there is a implicit context parameter, pass it in EAX + if (usesthis || usesnest) + { + f->thisAttrs |= llvm::Attribute::InReg; + } + // otherwise check the first formal parameter + else + { + Argument* arg = Argument::getNth(f->parameters, 0); + Type* t = arg->type->toBasetype(); + + // 32bit ints, pointers, classes and static arrays are candidate for being passed in EAX + if ((arg->storageClass & STCin) && + ((t->isscalar() && !t->isfloating()) || t->ty == Tclass || t->ty == Tsarray) && + (t->size() <= PTRSIZE)) + { + arg->llvmAttrs |= llvm::Attribute::InReg; + } + } + } + } + + // done f->retInPtr = retinptr; f->usesThis = usesthis; f->usesNest = usesnest; @@ -350,6 +383,14 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati attrs.push_back(PAWI); } + // set this/nest param attrs + if (f->thisAttrs) + { + PAWI.Index = f->retInPtr ? 2 : 1; + PAWI.Attrs = f->thisAttrs; + attrs.push_back(PAWI); + } + // set attrs on the rest of the arguments for (; llidx <= funcNumArgs && Argument::dim(f->parameters) > k; ++llidx,++k) { diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 3dfef1bc2b..88b92472c3 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -257,6 +257,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* LLValue* retvar = DtoAlloca(argiter->get()->getContainedType(0), ".rettmp"); ++argiter; args.push_back(retvar); + + // add attrs for hidden ptr palist = palist.addAttr(1, llvm::Attribute::StructRet); } @@ -299,6 +301,10 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* error(loc, "Context argument required but none given"); fatal(); } + + // add attributes for context argument + if (tf->thisAttrs) + palist = palist.addAttr(retinptr?2:1, tf->thisAttrs); } // handle the rest of the arguments based on param passing style diff --git a/gen/toir.cpp b/gen/toir.cpp index 1b3b2e3b7d..cad2a36f94 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -373,9 +373,7 @@ DValue* StringExp::toElem(IRState* p) if (dtype->ty == Tarray) { LLConstant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false); - LLValue* tmpmem = DtoAlloca(DtoType(dtype),"tempstring"); - DtoSetArray(tmpmem, clen, arrptr); - return new DVarValue(type, tmpmem); + return new DImValue(type, DtoConstSlice(clen, arrptr)); } else if (dtype->ty == Tsarray) { const LLType* dstType = getPtrToType(LLArrayType::get(ct, len));