Skip to content

Commit

Permalink
[mlir] Support llvm.readnone attribute for all FunctionOpInterface ops.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vzakhari committed Aug 24, 2022
1 parent f79214d commit 13cb085
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 0 deletions.
6 changes: 6 additions & 0 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
Expand Up @@ -66,6 +66,12 @@ def LLVM_Dialect : Dialect {
/// Returns `true` if the given type is compatible with the LLVM dialect.
static bool isCompatibleType(Type);

/// Name of the attribute mapped to LLVM's 'readnone' function attribute.
/// It is allowed on any FunctionOpInterface operations.
static StringRef getReadnoneAttrName() {
return "llvm.readnone";
}

private:
/// A cache storing compatible LLVM types that have been verified. This
/// can save us lots of verification time if there are many occurrences
Expand Down
11 changes: 11 additions & 0 deletions mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
Expand Up @@ -2683,6 +2683,17 @@ LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
<< "' to be a `loopopts` attribute";
}

if (attr.getName() == LLVMDialect::getReadnoneAttrName()) {
const auto attrName = LLVMDialect::getReadnoneAttrName();
if (!isa<FunctionOpInterface>(op))
return op->emitOpError()
<< "'" << attrName
<< "' is permitted only on FunctionOpInterface operations";
if (!attr.getValue().isa<UnitAttr>())
return op->emitOpError()
<< "expected '" << attrName << "' to be a unit attribute";
}

if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) {
return op->emitOpError()
<< "'" << LLVM::LLVMDialect::getStructAttrsAttrName()
Expand Down
16 changes: 16 additions & 0 deletions mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
Expand Up @@ -168,6 +168,10 @@ class Importer {
/// Imports `f` into the current module.
LogicalResult processFunction(llvm::Function *f);

/// Converts function attributes of LLVM Function \p f
/// into LLVM dialect attributes of LLVMFuncOp \p funcOp.
void processFunctionAttributes(llvm::Function *f, LLVMFuncOp funcOp);

/// Imports GV as a GlobalOp, creating it if it doesn't exist.
GlobalOp processGlobal(llvm::GlobalVariable *gv);

Expand Down Expand Up @@ -1157,6 +1161,15 @@ FlatSymbolRefAttr Importer::getPersonalityAsAttr(llvm::Function *f) {
return FlatSymbolRefAttr();
}

void Importer::processFunctionAttributes(llvm::Function *func,
LLVMFuncOp funcOp) {
auto addNamedUnitAttr = [&](StringRef name) {
return funcOp->setAttr(name, UnitAttr::get(context));
};
if (func->hasFnAttribute(llvm::Attribute::ReadNone))
addNamedUnitAttr(LLVMDialect::getReadnoneAttrName());
}

LogicalResult Importer::processFunction(llvm::Function *f) {
blocks.clear();
instMap.clear();
Expand Down Expand Up @@ -1191,6 +1204,9 @@ LogicalResult Importer::processFunction(llvm::Function *f) {
if (f->hasGC())
fop.setGarbageCollectorAttr(b.getStringAttr(f->getGC()));

// Handle Function attributes.
processFunctionAttributes(f, fop);

if (f->isDeclaration())
return success();

Expand Down
3 changes: 3 additions & 0 deletions mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
Expand Up @@ -927,6 +927,9 @@ LogicalResult ModuleTranslation::convertFunctionSignatures() {
mapFunction(function.getName(), llvmFunc);
addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);

if (function->getAttrOfType<UnitAttr>(LLVMDialect::getReadnoneAttrName()))
llvmFunc->addFnAttr(llvm::Attribute::ReadNone);

// Forward the pass-through attributes to LLVM.
if (failed(forwardPassthroughAttributes(
function.getLoc(), function.getPassthrough(), llvmFunc)))
Expand Down
18 changes: 18 additions & 0 deletions mlir/test/Dialect/LLVMIR/func.mlir
Expand Up @@ -277,3 +277,21 @@ module {
"llvm.func"() ({
}) {sym_name = "generic_unknown_calling_convention", CConv = #llvm.cconv<cc_12>, function_type = !llvm.func<i64 (i64, i64)>} : () -> ()
}

// -----

module {
// expected-error@+3 {{'llvm.readnone' is permitted only on FunctionOpInterface operations}}
"llvm.func"() ({
^bb0:
llvm.return {llvm.readnone}
}) {sym_name = "readnone_return", function_type = !llvm.func<void ()>} : () -> ()
}

// -----

module {
// expected-error@+1 {{op expected 'llvm.readnone' to be a unit attribute}}
"llvm.func"() ({
}) {sym_name = "readnone_func", llvm.readnone = true, function_type = !llvm.func<void ()>} : () -> ()
}
17 changes: 17 additions & 0 deletions mlir/test/Target/LLVMIR/Import/function_attributes.ll
@@ -0,0 +1,17 @@
; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s

// -----

; CHECK: llvm.func @readnone_attr() attributes {llvm.readnone}
declare void @readnone_attr() #0
attributes #0 = { readnone }

// -----

; CHECK: llvm.func @readnone_attr() attributes {llvm.readnone} {
; CHECK: llvm.return
; CHECK: }
define void @readnone_attr() readnone {
entry:
ret void
}
8 changes: 8 additions & 0 deletions mlir/test/Target/LLVMIR/llvmir.mlir
Expand Up @@ -1937,3 +1937,11 @@ llvm.func @vararg_function(%arg0: i32, ...) {
// CHECK: ret void
llvm.return
}

// -----

// Function attributes: readnone

// CHECK: declare void @readnone_function() #[[ATTR:[0-9]+]]
// CHECK: attributes #[[ATTR]] = { readnone }
llvm.func @readnone_function() attributes {llvm.readnone}

0 comments on commit 13cb085

Please sign in to comment.