diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -1423,9 +1423,63 @@ funcOp.setMemoryAttr(memAttr); } +static void processPassthroughAttrs(llvm::Function *func, LLVMFuncOp funcOp) { + MLIRContext *context = funcOp.getContext(); + SmallVector passthroughs; + llvm::AttributeSet funcAttrs = func->getAttributes().getAttributes( + llvm::AttributeList::AttrIndex::FunctionIndex); + for (llvm::Attribute attr : funcAttrs) { + // Skip the memory attribute since the LLVMFuncOp has an explicit memory + // attribute. + if (attr.hasAttribute(llvm::Attribute::Memory)) + continue; + + // Skip invalid type attributes. + if (attr.isTypeAttribute()) { + emitWarning(funcOp.getLoc(), + "type attributes on a function are invalid, skipping it"); + continue; + } + + StringRef attrName; + if (attr.isStringAttribute()) + attrName = attr.getKindAsString(); + else + attrName = llvm::Attribute::getNameFromAttrKind(attr.getKindAsEnum()); + auto keyAttr = StringAttr::get(context, attrName); + + if (attr.isStringAttribute()) { + StringRef val = attr.getValueAsString(); + if (val.empty()) { + passthroughs.push_back(keyAttr); + continue; + } + passthroughs.push_back( + ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)})); + continue; + } + if (attr.isIntAttribute()) { + auto val = std::to_string(attr.getValueAsInt()); + passthroughs.push_back( + ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)})); + continue; + } + if (attr.isEnumAttribute()) { + passthroughs.push_back(keyAttr); + continue; + } + + llvm_unreachable("unexpected attribute kind"); + } + + if (!passthroughs.empty()) + funcOp.setPassthroughAttr(ArrayAttr::get(context, passthroughs)); +} + void ModuleImport::processFunctionAttributes(llvm::Function *func, LLVMFuncOp funcOp) { processMemoryEffects(func, funcOp); + processPassthroughAttrs(func, funcOp); } LogicalResult ModuleImport::processFunction(llvm::Function *func) { diff --git a/mlir/test/Target/LLVMIR/Import/basic.ll b/mlir/test/Target/LLVMIR/Import/basic.ll --- a/mlir/test/Target/LLVMIR/Import/basic.ll +++ b/mlir/test/Target/LLVMIR/Import/basic.ll @@ -8,9 +8,8 @@ ; CHECK: llvm.func @fe(i32) -> f32 declare float @fe(i32) -; FIXME: function attributes. -; CHECK-LABEL: llvm.func internal @f1(%arg0: i64) -> i32 attributes {dso_local} { -; CHECK-DBG: llvm.func internal @f1(%arg0: i64 loc({{.*}}basic.ll{{.*}}:0:0)) -> i32 attributes {dso_local} { +; CHECK-LABEL: llvm.func internal @f1(%arg0: i64) -> i32 attributes {dso_local, passthrough = ["norecurse"]} { +; CHECK-DBG: llvm.func internal @f1(%arg0: i64 loc({{.*}}basic.ll{{.*}}:0:0)) -> i32 attributes {dso_local, passthrough = ["norecurse"]} { ; CHECK: %[[c2:[0-9]+]] = llvm.mlir.constant(2 : i32) : i32 ; CHECK: %[[c1:[0-9]+]] = llvm.mlir.constant(true) : i1 ; CHECK: %[[c43:[0-9]+]] = llvm.mlir.constant(43 : i32) : i32 diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll --- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll +++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll @@ -1,4 +1,4 @@ -; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s +; RUN: mlir-translate -import-llvm -split-input-file %s --verify-diagnostics | FileCheck %s ; CHECK: llvm.func internal @func_internal define internal void @func_internal() { @@ -57,3 +57,25 @@ define void @func_memory() memory(readwrite, argmem: none) { ret void } + +; // ----- + +; CHECK-LABEL: @passthrough_combined +; CHECK-SAME: attributes {passthrough = [ +; CHECK-DAG: ["alignstack", "16"] +; CHECK-DAG: "noinline" +; CHECK-DAG: "probe-stack" +; CHECK-DAG: ["alloc-family", "malloc"] +; CHECK: llvm.return +define void @passthrough_combined() alignstack(16) noinline "probe-stack" "alloc-family"="malloc" { + ret void +} + +// ----- + +; CHECK-LABEL: @passthrough_string_only +; CHECK-SAME: attributes {passthrough = ["no-enum-attr"]} +; CHECK: llvm.return +define void @passthrough_string_only() "no-enum-attr" { + ret void +}