diff --git a/dmd/attrib.c b/dmd/attrib.c index f036e8c6e3..d3148bfcca 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -416,6 +416,10 @@ void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) case LINKcpp: p = "C++"; break; case LINKwindows: p = "Windows"; break; case LINKpascal: p = "Pascal"; break; + + // LDC + case LINKintrinsic: p = "Intrinsic"; break; + default: assert(0); break; @@ -1003,6 +1007,8 @@ void PragmaDeclaration::semantic(Scope *sc) { fd->llvmInternal = llvm_internal; fd->intrinsicName = arg1str; + fd->linkage = LINKintrinsic; + ((TypeFunction*)fd->type)->linkage = LINKintrinsic; } else if (TemplateDeclaration* td = s->isTemplateDeclaration()) { diff --git a/dmd/expression.c b/dmd/expression.c index 20f95049a0..70fb82fa12 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -684,12 +684,16 @@ void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argume //arg->error("cannot modify slice %s", arg->toChars()); } +// LDC we don't want this! +#if !IN_LLVM // Convert static arrays to pointers tb = arg->type->toBasetype(); if (tb->ty == Tsarray) { arg = arg->checkToPointer(); } +#endif + // Convert lazy argument to a delegate if (p->storageClass & STClazy) @@ -701,7 +705,8 @@ void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argume { // If not D linkage, do promotions - if (tf->linkage != LINKd) + // LDC: don't do promotions on intrinsics + if (tf->linkage != LINKd && tf->linkage != LINKintrinsic) { // Promote bytes, words, etc., to ints arg = arg->integralPromotions(sc); diff --git a/dmd/mangle.c b/dmd/mangle.c index 0aa2ff2618..a4faf51b99 100644 --- a/dmd/mangle.c +++ b/dmd/mangle.c @@ -104,6 +104,9 @@ char *Declaration::mangle() case LINKd: break; + // LDC + case LINKintrinsic: + case LINKc: case LINKwindows: case LINKpascal: diff --git a/dmd/mars.h b/dmd/mars.h index 13edb9c038..102cd06708 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -309,6 +309,9 @@ enum LINK LINKcpp, LINKwindows, LINKpascal, + + // LDC + LINKintrinsic, }; enum DYNCAST diff --git a/dmd/mtype.c b/dmd/mtype.c index 551bb82ea2..8a80a815c0 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -2673,6 +2673,8 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en this->usesNest = false; this->retAttrs = 0; this->thisAttrs = 0; + this->reverseParams = false; + this->reverseIndex = 0; } Type *TypeFunction::syntaxCopy() @@ -2685,6 +2687,8 @@ Type *TypeFunction::syntaxCopy() t->usesNest = usesNest; t->retAttrs = retAttrs; t->thisAttrs = thisAttrs; + t->reverseParams = reverseParams; + t->reverseIndex = reverseIndex; return t; } @@ -2794,6 +2798,10 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf) case LINKwindows: mc = 'W'; break; case LINKpascal: mc = 'V'; break; case LINKcpp: mc = 'R'; break; + + // LDC + case LINKintrinsic: mc = 'Q'; break; + default: assert(0); } @@ -2826,6 +2834,10 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs case LINKwindows: p = "Windows "; break; case LINKpascal: p = "Pascal "; break; case LINKcpp: p = "C++ "; break; + + // LDC + case LINKintrinsic: p = "Intrinsic"; break; + default: assert(0); } @@ -2861,6 +2873,10 @@ void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) case LINKwindows: p = "Windows "; break; case LINKpascal: p = "Pascal "; break; case LINKcpp: p = "C++ "; break; + + // LDC + case LINKintrinsic: p = "Intrinsic"; break; + default: assert(0); } diff --git a/dmd/mtype.h b/dmd/mtype.h index 2b5212fa4e..6f70239e90 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -440,6 +440,9 @@ struct TypeFunction : Type bool usesNest; unsigned retAttrs; unsigned thisAttrs; // also used for nest + + bool reverseParams; + size_t reverseIndex; }; struct TypeDelegate : Type diff --git a/gen/functions.cpp b/gen/functions.cpp index 3e06e95ee4..054844e204 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -21,6 +21,8 @@ #include "gen/classes.h" #include "gen/dvalue.h" +#include + const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, const LLType* nesttype, bool ismain) { assert(type->ty == Tfunction); @@ -111,8 +113,23 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co // do nothing? } + // number of formal params size_t n = Argument::dim(f->parameters); + // on x86 we need to reverse the formal params in some cases to match the ABI + if (global.params.cpu == ARCHx86) + { + // more than one formal arg, + // extern(D) linkage + // not a D-style vararg + if (n > 1 && f->linkage == LINKd && !typesafeVararg) + { + f->reverseParams = true; + f->reverseIndex = paramvec.size(); + } + } + + for (int i=0; i < n; ++i) { Argument* arg = Argument::getNth(f->parameters, i); // ensure scalar @@ -167,6 +184,12 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co } } + // reverse params? + if (f->reverseParams) + { + std::reverse(paramvec.begin() + f->reverseIndex, paramvec.end()); + } + // construct function type bool isvararg = !(typesafeVararg || arrayVararg) && f->varargs; llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); @@ -189,6 +212,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co // otherwise check the first formal parameter else { + int inreg = f->reverseParams ? n - 1 : 0; Argument* arg = Argument::getNth(f->parameters, 0); Type* t = arg->type->toBasetype(); @@ -340,6 +364,8 @@ void DtoResolveFunction(FuncDeclaration* fdecl) Logger::println("overloaded intrinsic found"); fdecl->llvmInternal = LLVMintrinsic; DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName); + fdecl->linkage = LINKintrinsic; + ((TypeFunction*)fdecl->type)->linkage = LINKintrinsic; } } @@ -354,7 +380,7 @@ void DtoResolveFunction(FuncDeclaration* fdecl) static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl) { - int llidx = 1; + int llidx = 0; if (f->retInPtr) ++llidx; if (f->usesThis) ++llidx; else if (f->usesNest) ++llidx; @@ -362,9 +388,8 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati llidx += 2; int funcNumArgs = func->getArgumentList().size(); - std::vector attrs; - int k = 0; + LLSmallVector attrs; llvm::AttributeWithIndex PAWI; // set return value attrs if any @@ -392,20 +417,38 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati } // set attrs on the rest of the arguments - for (; llidx <= funcNumArgs && Argument::dim(f->parameters) > k; ++llidx,++k) + size_t n = Argument::dim(f->parameters); + assert(funcNumArgs >= n); // main might mismatch, for the implicit char[][] arg + + LLSmallVector attrptr(n, 0); + + for (size_t k = 0; k < n; ++k) { Argument* fnarg = Argument::getNth(f->parameters, k); assert(fnarg); - PAWI.Index = llidx; - PAWI.Attrs = fnarg->llvmAttrs; - - if (PAWI.Attrs) - attrs.push_back(PAWI); + attrptr[k] = fnarg->llvmAttrs; } - llvm::AttrListPtr palist = llvm::AttrListPtr::get(attrs.begin(), attrs.end()); - func->setAttributes(palist); + // reverse params? + if (f->reverseParams) + { + std::reverse(attrptr.begin(), attrptr.end()); + } + + // build rest of attrs list + for (int i = 0; i < n; i++) + { + if (attrptr[i]) + { + PAWI.Index = llidx+i+1; + PAWI.Attrs = attrptr[i]; + attrs.push_back(PAWI); + } + } + + llvm::AttrListPtr attrlist = llvm::AttrListPtr::get(attrs.begin(), attrs.end()); + func->setAttributes(attrlist); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -503,13 +546,13 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) { // name parameters llvm::Function::arg_iterator iarg = func->arg_begin(); - int k = 0; + if (f->retInPtr) { iarg->setName(".sretarg"); fdecl->ir.irFunc->retArg = iarg; ++iarg; } - + if (f->usesThis) { iarg->setName("this"); fdecl->ir.irFunc->thisArg = iarg; @@ -532,17 +575,26 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) ++iarg; } + int k = 0; + for (; iarg != func->arg_end(); ++iarg) { if (fdecl->parameters && fdecl->parameters->dim > k) { - Dsymbol* argsym = (Dsymbol*)fdecl->parameters->data[k++]; + Dsymbol* argsym; + if (f->reverseParams) + argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1]; + else + argsym = (Dsymbol*)fdecl->parameters->data[k]; + VarDeclaration* argvd = argsym->isVarDeclaration(); assert(argvd); assert(!argvd->ir.irLocal); argvd->ir.irLocal = new IrLocal(argvd); argvd->ir.irLocal->value = iarg; iarg->setName(argvd->ident->toChars()); + + k++; } else { @@ -902,7 +954,7 @@ DValue* DtoArgument(Argument* fnarg, Expression* argexp) DValue* arg = argexp->toElem(gIR); // ref/out arg - if (fnarg && ((fnarg->storageClass & STCref) || (fnarg->storageClass & STCout))) + if (fnarg && (fnarg->storageClass & (STCref | STCout))) { if (arg->isVar() || arg->isLRValue()) arg = new DImValue(argexp->type, arg->getLVal()); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 88b92472c3..8f4567af59 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -34,7 +34,7 @@ TypeFunction* DtoTypeFunction(DValue* fnval) unsigned DtoCallingConv(LINK l) { - if (l == LINKc || l == LINKcpp) + if (l == LINKc || l == LINKcpp || l == LINKintrinsic) return llvm::CallingConv::C; else if (l == LINKd || l == LINKdefault) { @@ -111,7 +111,7 @@ const LLFunctionType* DtoExtractFunctionType(const LLType* type) ////////////////////////////////////////////////////////////////////////////////////////// -void DtoBuildDVarArgList(std::vector& args, llvm::AttrListPtr& palist, TypeFunction* tf, Expressions* arguments, size_t argidx) +void DtoBuildDVarArgList(std::vector& args, std::vector& attrs, TypeFunction* tf, Expressions* arguments, size_t argidx) { Logger::println("doing d-style variadic arguments"); @@ -195,7 +195,12 @@ void DtoBuildDVarArgList(std::vector& args, llvm::AttrListPtr& palist, args.push_back(argval->getRVal()); if (fnarg->llvmAttrs) - palist = palist.addAttr(argidx, fnarg->llvmAttrs); + { + llvm::AttributeWithIndex Attr; + Attr.Index = argidx; + Attr.Attrs = fnarg->llvmAttrs; + attrs.push_back(Attr); + } ++argidx; } @@ -234,6 +239,11 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* const LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType()); assert(callableTy); + if (Logger::enabled()) + { + Logger::cout() << "callable: " << *callable << '\n'; + } + // get n arguments size_t n_arguments = arguments ? arguments->dim : 0; @@ -242,11 +252,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* LLFunctionType::param_iterator argiter = argbegin; // parameter attributes - llvm::AttrListPtr palist; + std::vector attrs; + llvm::AttributeWithIndex Attr; // return attrs if (tf->retAttrs) - palist = palist.addAttr(0, tf->retAttrs); + { + Attr.Index = 0; + Attr.Attrs = tf->retAttrs; + attrs.push_back(Attr); + } // handle implicit arguments std::vector args; @@ -259,7 +274,9 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* args.push_back(retvar); // add attrs for hidden ptr - palist = palist.addAttr(1, llvm::Attribute::StructRet); + Attr.Index = 1; + Attr.Attrs = llvm::Attribute::StructRet; + attrs.push_back(Attr); } // then comes a context argument... @@ -304,7 +321,11 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // add attributes for context argument if (tf->thisAttrs) - palist = palist.addAttr(retinptr?2:1, tf->thisAttrs); + { + Attr.Index = retinptr ? 2 : 1; + Attr.Attrs = tf->thisAttrs; + attrs.push_back(Attr); + } } // handle the rest of the arguments based on param passing style @@ -326,33 +347,83 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // d style varargs needs a few more hidden arguments as well as special passing else if (dvarargs) { - DtoBuildDVarArgList(args, palist, tf, arguments, argiter-argbegin+1); + DtoBuildDVarArgList(args, attrs, tf, arguments, argiter-argbegin+1); } // otherwise we're looking at a normal function call + // or a C style vararg call else { Logger::println("doing normal arguments"); - for (int i=0; iparameters); + + LLSmallVector attrptr(n, 0); + + // do formal params + int beg = argiter-argbegin; + for (int i=0; iparameters, i); + assert(fnarg); DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); LLValue* arg = argval->getRVal(); - if (fnarg) // can fnarg ever be null in this block? + + 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)) { + #if 0 if (Logger::enabled()) { Logger::cout() << "arg: " << *arg << '\n'; Logger::cout() << "expects: " << *callableTy->getParamType(j) << '\n'; } - if (arg->getType() != callableTy->getParamType(j)) - arg = DtoBitCast(arg, callableTy->getParamType(j)); - if (fnarg->llvmAttrs) - palist = palist.addAttr(j+1, fnarg->llvmAttrs); + #endif + arg = DtoBitCast(arg, callableTy->getParamType(j)); } + + // param attrs + attrptr[i] = fnarg->llvmAttrs; + ++argiter; args.push_back(arg); } + + // reverse the relevant params as well as the param attrs + if (tf->reverseParams) + { + std::reverse(args.begin() + tf->reverseIndex, args.end()); + std::reverse(attrptr.begin(), attrptr.end()); + } + + // add attributes + for (int i = 0; i < n; i++) + { + if (attrptr[i]) + { + Attr.Index = beg + i + 1; + Attr.Attrs = attrptr[i]; + attrs.push_back(Attr); + } + } + + // do C varargs + if (n_arguments > n) + { + for (int i=n; iparameters, i); + DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); + LLValue* arg = argval->getRVal(); + + // FIXME: do we need any param attrs here ? + + ++argiter; + args.push_back(arg); + } + } } #if 0 @@ -405,17 +476,18 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* } // set calling convention and parameter attributes + llvm::AttrListPtr attrlist = llvm::AttrListPtr::get(attrs.begin(), attrs.end()); if (dfnval && dfnval->func) { LLFunction* llfunc = llvm::dyn_cast(dfnval->val); - if (llfunc && llfunc->isIntrinsic()) - palist = llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)llfunc->getIntrinsicID()); + if (llfunc && llfunc->isIntrinsic()) // override intrinsic attrs + attrlist = llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)llfunc->getIntrinsicID()); else call->setCallingConv(callconv); } else call->setCallingConv(callconv); - call->setAttributes(palist); + call->setAttributes(attrlist); return new DImValue(resulttype, retllval); } diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 7b6a5bd06f..446b79cfcf 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -163,11 +163,15 @@ const LLType* DtoType(Type* t) // associative arrays case Taarray: + #if 1 + return getVoidPtrType(); + #else { TypeAArray* taa = (TypeAArray*)t; // aa key/val can't be void return getPtrToType(LLStructType::get(DtoType(taa->key), DtoType(taa->next), 0)); } + #endif /* Not needed atm as VarDecls for tuples are rewritten as a string of diff --git a/tests/mini/intrinsics.d b/tests/mini/intrinsics.d index 85f44a3b94..5d05013f94 100644 --- a/tests/mini/intrinsics.d +++ b/tests/mini/intrinsics.d @@ -21,7 +21,7 @@ void main() real r; printf("Enter real: "); - //scanf("%lf", &d); + //scanf("%llf", &r); r = 3.2311167891231231234754764576; version(X86) {