diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2334,10 +2334,18 @@ } // Verifies LLVM- and implementation-specific properties of the LLVM func Op: +// - arguments passthrough attributes defined as an array attribute // - functions don't have 'common' linkage // - external functions have 'external' or 'extern_weak' linkage; // - vararg is (currently) only supported for external functions; LogicalResult LLVMFuncOp::verify() { + for (unsigned i = 0; i < getNumArguments(); ++i) { + auto attrs = getArgAttrDict(i); + auto passthrough = attrs ? attrs.get("llvm.passthrough") : Attribute(); + if (passthrough && !passthrough.isa()) + return emitOpError() << "`llvm.passthrough` attribute must be an array"; + } + if (getLinkage() == LLVM::Linkage::Common) return emitOpError() << "functions cannot have '" << stringifyLinkage(LLVM::Linkage::Common) diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -760,6 +760,20 @@ return success(); } +/// Attempts to add an attribute identified by `key` to LLVM function argument +/// `llvmArg`. Reports errors at `loc` if any. If the attribute has a kind known +/// to LLVM IR, create the attribute of this kind, otherwise returns an error. +static LogicalResult checkedAddLLVMArgAttribute(Location loc, + llvm::Argument *llvmArg, + StringRef key) { + auto kind = llvm::Attribute::getAttrKindFromName(key); + if (kind == llvm::Attribute::None) + return emitError(loc) << "unknown LLVM attribute '" << key << "'"; + + llvmArg->addAttr(kind); + return success(); +} + /// Attaches the attributes listed in the given array attribute to `llvmFunc`. /// Reports error to `loc` if any and returns immediately. Expects `attributes` /// to be an array attribute containing either string attributes, treated as @@ -799,6 +813,31 @@ return success(); } +/// Attaches the attributes listed in the given array attribute to `llvmArg`. +/// Reports error to `loc` if any and returns immediately. Expects `attributes` +/// to be an array attribute containing string attributes, treated as value-less +/// LLVM attributes +static LogicalResult +forwardPassthroughAttributes(Location loc, Optional attributes, + llvm::Argument *llvmArg) { + if (!attributes) + return success(); + + for (Attribute attr : *attributes) { + if (auto stringAttr = attr.dyn_cast()) { + if (failed( + checkedAddLLVMArgAttribute(loc, llvmArg, stringAttr.getValue()))) + return failure(); + continue; + } + + return emitError(loc) + << "expected 'llvm.passthrough' to contain string attributes"; + } + + return success(); +} + LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) { // Clear the block, branch value mappings, they are only relevant within one // function. @@ -927,10 +966,20 @@ mapFunction(function.getName(), llvmFunc); addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc); - // Forward the pass-through attributes to LLVM. + // Forward the pass-through function attributes to LLVM. if (failed(forwardPassthroughAttributes( function.getLoc(), function.getPassthrough(), llvmFunc))) return failure(); + + // Forward the pass-through function arguments attributes to LLVM. + for (unsigned i = 0; i < function.getNumArguments(); ++i) { + auto attrs = function.getArgAttrDict(i); + auto passthrough = attrs ? attrs.get("llvm.passthrough") : Attribute(); + if (passthrough && failed(forwardPassthroughAttributes( + function.getLoc(), passthrough.cast(), + llvmFunc->getArg(i)))) + return failure(); + } } return success(); diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1456,8 +1456,9 @@ } // CHECK-LABEL: @passthrough -// CHECK: #[[ATTR_GROUP:[0-9]*]] -llvm.func @passthrough() attributes {passthrough = ["noinline", ["alignstack", "4"], "null_pointer_is_valid", ["foo", "bar"]]} { +// CHECK-SAME: (ptr nocapture %[[ARG:.*]]) +// CHECK-SAME: #[[ATTR_GROUP:[0-9]*]] +llvm.func @passthrough(%arg0: !llvm.ptr {llvm.passthrough = ["nocapture"]}) attributes {passthrough = ["noinline", ["alignstack", "4"], "null_pointer_is_valid", ["foo", "bar"]]} { llvm.return }