diff --git a/gen/functions.cpp b/gen/functions.cpp index c9895b8fea..1768f3e156 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -603,6 +603,11 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) { // add func to IRFunc irFunc->setLLVMFunc(func); + // First apply the TargetMachine attributes, such that they can be overridden + // by UDAs. + applyTargetMachineAttributes(*func, *gTargetMachine); + applyFuncDeclUDAs(fdecl, irFunc); + // parameter attributes if (!DtoIsIntrinsic(fdecl)) { applyParamAttrsToLLFunc(f, getIrFunc(fdecl)->irFty, func); @@ -611,11 +616,6 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) { } } - // First apply the TargetMachine attributes, such that they can be overridden - // by UDAs. - applyTargetMachineAttributes(*func, *gTargetMachine); - applyFuncDeclUDAs(fdecl, irFunc); - if(irFunc->isDynamicCompiled()) { declareDynamicCompiledFunction(gIR, irFunc); } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 71ad634bf9..954625ac01 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -121,7 +121,7 @@ static void addExplicitArguments(std::vector &args, AttrSet &attrs, const size_t formalLLArgCount = irFty.args.size(); // Number of formal arguments in the D call expression (excluding varargs). - const int formalDArgCount = Parameter::dim(formalParams); + const size_t formalDArgCount = Parameter::dim(formalParams); // The number of explicit arguments in the D call expression (including // varargs), not all of which necessarily generate a LLVM argument. @@ -167,8 +167,10 @@ static void addExplicitArguments(std::vector &args, AttrSet &attrs, // Make sure to evaluate argument expressions for which there's no LL // parameter (e.g., empty structs for some ABIs). - for (; dArgIndex < irArg->parametersIdx; ++dArgIndex) { - toElem(argexps[dArgIndex]); + if (irArg->parametersIdx < formalDArgCount) { + for (; dArgIndex < irArg->parametersIdx; ++dArgIndex) { + toElem(argexps[dArgIndex]); + } } Expression *const argexp = argexps[dArgIndex]; diff --git a/gen/uda.cpp b/gen/uda.cpp index 3a8ab7c0b6..8b122649f8 100644 --- a/gen/uda.cpp +++ b/gen/uda.cpp @@ -207,19 +207,19 @@ void applyAttrAllocSize(StructLiteralExp *sle, IrFunction *irFunc) { // @llvmAttr("key", "value") // @llvmAttr("key") -void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::Function *func) { +void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::AttrBuilder &attrs) { checkStructElems(sle, {Type::tstring, Type::tstring}); llvm::StringRef key = getStringElem(sle, 0); llvm::StringRef value = getStringElem(sle, 1); if (value.empty()) { const auto kind = llvm::getAttrKindFromName(key); if (kind != llvm::Attribute::None) { - func->addFnAttr(kind); + attrs.addAttribute(kind); } else { - func->addFnAttr(key); + attrs.addAttribute(key); } } else { - func->addFnAttr(key, value); + attrs.addAttribute(key, value); } } @@ -407,48 +407,85 @@ void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar) { } void applyFuncDeclUDAs(FuncDeclaration *decl, IrFunction *irFunc) { - if (!decl->userAttribDecl) - return; + // function UDAs + if (decl->userAttribDecl) { + llvm::Function *func = irFunc->getLLVMFunc(); + assert(func); - llvm::Function *func = irFunc->getLLVMFunc(); - assert(func); + Expressions *attrs = decl->userAttribDecl->getAttributes(); + expandTuples(attrs); + for (auto &attr : *attrs) { + auto sle = getLdcAttributesStruct(attr); + if (!sle) + continue; - Expressions *attrs = decl->userAttribDecl->getAttributes(); - expandTuples(attrs); - for (auto &attr : *attrs) { - auto sle = getLdcAttributesStruct(attr); - if (!sle) + auto ident = sle->sd->ident; + if (ident == Id::udaAllocSize) { + applyAttrAllocSize(sle, irFunc); + } else if (ident == Id::udaLLVMAttr) { + llvm::AttrBuilder attrs; + applyAttrLLVMAttr(sle, attrs); +#if LDC_LLVM_VER >= 500 + func->addAttributes(LLAttributeSet::FunctionIndex, attrs); +#else + AttrSet attrSet; + attrSet.addToFunction(attrs); + func->addAttributes(LLAttributeSet::FunctionIndex, attrSet); +#endif + } else if (ident == Id::udaLLVMFastMathFlag) { + applyAttrLLVMFastMathFlag(sle, irFunc); + } else if (ident == Id::udaOptStrategy) { + applyAttrOptStrategy(sle, irFunc); + } else if (ident == Id::udaSection) { + applyAttrSection(sle, func); + } else if (ident == Id::udaTarget) { + applyAttrTarget(sle, func, irFunc); + } else if (ident == Id::udaAssumeUsed) { + applyAttrAssumeUsed(*gIR, sle, func); + } else if (ident == Id::udaWeak || ident == Id::udaKernel) { + // @weak and @kernel are applied elsewhere + } else if (ident == Id::udaDynamicCompile) { + irFunc->dynamicCompile = true; + } else if (ident == Id::udaDynamicCompileEmit) { + irFunc->dynamicCompileEmit = true; + } else if (ident == Id::udaDynamicCompileConst) { + sle->error( + "Special attribute `ldc.attributes.%s` is only valid for variables", + ident->toChars()); + } else { + sle->warning( + "Ignoring unrecognized special attribute `ldc.attributes.%s`", + ident->toChars()); + } + } + } + + // parameter UDAs + auto parameterList = irFunc->type->parameterList; + for (auto arg : irFunc->irFty.args) { + if (arg->parametersIdx >= parameterList.length()) continue; - auto ident = sle->sd->ident; - if (ident == Id::udaAllocSize) { - applyAttrAllocSize(sle, irFunc); - } else if (ident == Id::udaLLVMAttr) { - applyAttrLLVMAttr(sle, func); - } else if (ident == Id::udaLLVMFastMathFlag) { - applyAttrLLVMFastMathFlag(sle, irFunc); - } else if (ident == Id::udaOptStrategy) { - applyAttrOptStrategy(sle, irFunc); - } else if (ident == Id::udaSection) { - applyAttrSection(sle, func); - } else if (ident == Id::udaTarget) { - applyAttrTarget(sle, func, irFunc); - } else if (ident == Id::udaAssumeUsed) { - applyAttrAssumeUsed(*gIR, sle, func); - } else if (ident == Id::udaWeak || ident == Id::udaKernel) { - // @weak and @kernel are applied elsewhere - } else if (ident == Id::udaDynamicCompile) { - irFunc->dynamicCompile = true; - } else if (ident == Id::udaDynamicCompileEmit) { - irFunc->dynamicCompileEmit = true; - } else if (ident == Id::udaDynamicCompileConst) { - sle->error( - "Special attribute `ldc.attributes.%s` is only valid for variables", - ident->toChars()); - } else { - sle->warning( - "Ignoring unrecognized special attribute `ldc.attributes.%s`", - ident->toChars()); + auto param = + Parameter::getNth(parameterList.parameters, arg->parametersIdx); + if (!param->userAttribDecl) + continue; + + Expressions *attrs = param->userAttribDecl->getAttributes(); + expandTuples(attrs); + for (auto &attr : *attrs) { + auto sle = getLdcAttributesStruct(attr); + if (!sle) + continue; + + auto ident = sle->sd->ident; + if (ident == Id::udaLLVMAttr) { + applyAttrLLVMAttr(sle, arg->attrs); + } else { + sle->warning("Ignoring unrecognized special parameter attribute " + "`ldc.attributes.%s`", + ident->toChars()); + } } } } diff --git a/ir/irfuncty.h b/ir/irfuncty.h index 9abd215bb3..4877da52b8 100644 --- a/ir/irfuncty.h +++ b/ir/irfuncty.h @@ -46,7 +46,7 @@ struct IrFuncTyArg { /// The index of the declaration in the FuncDeclaration::parameters array /// corresponding to this argument. - size_t parametersIdx = 0; + size_t parametersIdx = -1; /// This is the final LLVM Type used for the parameter/return value type llvm::Type *ltype = nullptr; diff --git a/tests/codegen/attr_param.d b/tests/codegen/attr_param.d new file mode 100644 index 0000000000..05b3bd04bf --- /dev/null +++ b/tests/codegen/attr_param.d @@ -0,0 +1,6 @@ +// RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +import ldc.attributes; + +// CHECK: define{{.*}} @{{.*}}3foo{{.*}}(i8* noalias %p_arg) +void foo(@llvmAttr("noalias") void* p) {}