Skip to content

Commit 13cb085

Browse files
committed
[mlir] Support llvm.readnone attribute for all FunctionOpInterface ops.
The attribute is translated into LLVM's function attribute 'readnone'. There is no explicit verification regarding conflicting 'readnone' and function attributes from 'passthrough', though, LLVM would assert if they are incompatible during LLVM IR creation. Differential Revision: https://reviews.llvm.org/D131457
1 parent f79214d commit 13cb085

File tree

7 files changed

+79
-0
lines changed

7 files changed

+79
-0
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ def LLVM_Dialect : Dialect {
6666
/// Returns `true` if the given type is compatible with the LLVM dialect.
6767
static bool isCompatibleType(Type);
6868

69+
/// Name of the attribute mapped to LLVM's 'readnone' function attribute.
70+
/// It is allowed on any FunctionOpInterface operations.
71+
static StringRef getReadnoneAttrName() {
72+
return "llvm.readnone";
73+
}
74+
6975
private:
7076
/// A cache storing compatible LLVM types that have been verified. This
7177
/// can save us lots of verification time if there are many occurrences

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,17 @@ LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
26832683
<< "' to be a `loopopts` attribute";
26842684
}
26852685

2686+
if (attr.getName() == LLVMDialect::getReadnoneAttrName()) {
2687+
const auto attrName = LLVMDialect::getReadnoneAttrName();
2688+
if (!isa<FunctionOpInterface>(op))
2689+
return op->emitOpError()
2690+
<< "'" << attrName
2691+
<< "' is permitted only on FunctionOpInterface operations";
2692+
if (!attr.getValue().isa<UnitAttr>())
2693+
return op->emitOpError()
2694+
<< "expected '" << attrName << "' to be a unit attribute";
2695+
}
2696+
26862697
if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) {
26872698
return op->emitOpError()
26882699
<< "'" << LLVM::LLVMDialect::getStructAttrsAttrName()

mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ class Importer {
168168
/// Imports `f` into the current module.
169169
LogicalResult processFunction(llvm::Function *f);
170170

171+
/// Converts function attributes of LLVM Function \p f
172+
/// into LLVM dialect attributes of LLVMFuncOp \p funcOp.
173+
void processFunctionAttributes(llvm::Function *f, LLVMFuncOp funcOp);
174+
171175
/// Imports GV as a GlobalOp, creating it if it doesn't exist.
172176
GlobalOp processGlobal(llvm::GlobalVariable *gv);
173177

@@ -1157,6 +1161,15 @@ FlatSymbolRefAttr Importer::getPersonalityAsAttr(llvm::Function *f) {
11571161
return FlatSymbolRefAttr();
11581162
}
11591163

1164+
void Importer::processFunctionAttributes(llvm::Function *func,
1165+
LLVMFuncOp funcOp) {
1166+
auto addNamedUnitAttr = [&](StringRef name) {
1167+
return funcOp->setAttr(name, UnitAttr::get(context));
1168+
};
1169+
if (func->hasFnAttribute(llvm::Attribute::ReadNone))
1170+
addNamedUnitAttr(LLVMDialect::getReadnoneAttrName());
1171+
}
1172+
11601173
LogicalResult Importer::processFunction(llvm::Function *f) {
11611174
blocks.clear();
11621175
instMap.clear();
@@ -1191,6 +1204,9 @@ LogicalResult Importer::processFunction(llvm::Function *f) {
11911204
if (f->hasGC())
11921205
fop.setGarbageCollectorAttr(b.getStringAttr(f->getGC()));
11931206

1207+
// Handle Function attributes.
1208+
processFunctionAttributes(f, fop);
1209+
11941210
if (f->isDeclaration())
11951211
return success();
11961212

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,9 @@ LogicalResult ModuleTranslation::convertFunctionSignatures() {
927927
mapFunction(function.getName(), llvmFunc);
928928
addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
929929

930+
if (function->getAttrOfType<UnitAttr>(LLVMDialect::getReadnoneAttrName()))
931+
llvmFunc->addFnAttr(llvm::Attribute::ReadNone);
932+
930933
// Forward the pass-through attributes to LLVM.
931934
if (failed(forwardPassthroughAttributes(
932935
function.getLoc(), function.getPassthrough(), llvmFunc)))

mlir/test/Dialect/LLVMIR/func.mlir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,21 @@ module {
277277
"llvm.func"() ({
278278
}) {sym_name = "generic_unknown_calling_convention", CConv = #llvm.cconv<cc_12>, function_type = !llvm.func<i64 (i64, i64)>} : () -> ()
279279
}
280+
281+
// -----
282+
283+
module {
284+
// expected-error@+3 {{'llvm.readnone' is permitted only on FunctionOpInterface operations}}
285+
"llvm.func"() ({
286+
^bb0:
287+
llvm.return {llvm.readnone}
288+
}) {sym_name = "readnone_return", function_type = !llvm.func<void ()>} : () -> ()
289+
}
290+
291+
// -----
292+
293+
module {
294+
// expected-error@+1 {{op expected 'llvm.readnone' to be a unit attribute}}
295+
"llvm.func"() ({
296+
}) {sym_name = "readnone_func", llvm.readnone = true, function_type = !llvm.func<void ()>} : () -> ()
297+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
2+
3+
// -----
4+
5+
; CHECK: llvm.func @readnone_attr() attributes {llvm.readnone}
6+
declare void @readnone_attr() #0
7+
attributes #0 = { readnone }
8+
9+
// -----
10+
11+
; CHECK: llvm.func @readnone_attr() attributes {llvm.readnone} {
12+
; CHECK: llvm.return
13+
; CHECK: }
14+
define void @readnone_attr() readnone {
15+
entry:
16+
ret void
17+
}

mlir/test/Target/LLVMIR/llvmir.mlir

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,3 +1937,11 @@ llvm.func @vararg_function(%arg0: i32, ...) {
19371937
// CHECK: ret void
19381938
llvm.return
19391939
}
1940+
1941+
// -----
1942+
1943+
// Function attributes: readnone
1944+
1945+
// CHECK: declare void @readnone_function() #[[ATTR:[0-9]+]]
1946+
// CHECK: attributes #[[ATTR]] = { readnone }
1947+
llvm.func @readnone_function() attributes {llvm.readnone}

0 commit comments

Comments
 (0)