[Mlir-commits] [mlir] ed114b6 - [MLIR][LLVM] Copy byval attributes during inlining.
Tobias Gysi
llvmlistbot at llvm.org
Wed Mar 22 07:39:11 PDT 2023
Author: Johannes de Fine Licht
Date: 2023-03-22T15:38:16+01:00
New Revision: ed114b6ffc953ac2c648f64287c44456a7d19d0c
URL: https://github.com/llvm/llvm-project/commit/ed114b6ffc953ac2c648f64287c44456a7d19d0c
DIFF: https://github.com/llvm/llvm-project/commit/ed114b6ffc953ac2c648f64287c44456a7d19d0c.diff
LOG: [MLIR][LLVM] Copy byval attributes during inlining.
Support inlining of function calls with the byval attribute on function
arguments by copying the pointee into a newly alloca'ed pointer at the
callsite before inlining.
The alignment attribute is not yet taken into account.
Reviewed By: ftynse, gysit
Differential Revision: https://reviews.llvm.org/D146616
Added:
Modified:
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/test/Dialect/LLVMIR/inlining.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 1336ad1169c12..ca439ab8cc15e 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "TypeDetail.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/IR/Builders.h"
@@ -2854,6 +2855,39 @@ static void moveConstantAllocasToEntryBlock(
}
}
+static Value handleByValArgument(OpBuilder &builder, Operation *callable,
+ Value argument,
+ NamedAttribute byValAttribute) {
+ auto func = cast<LLVM::LLVMFuncOp>(callable);
+ LLVM::MemoryEffectsAttr memoryEffects = func.getMemoryAttr();
+ // If there is no memory effects attribute, assume that the function is
+ // not read-only.
+ bool isReadOnly = memoryEffects &&
+ memoryEffects.getArgMem() != ModRefInfo::ModRef &&
+ memoryEffects.getArgMem() != ModRefInfo::Mod;
+ if (isReadOnly)
+ return argument;
+ // Resolve the pointee type and its size.
+ auto ptrType = cast<LLVM::LLVMPointerType>(argument.getType());
+ Type elementType = cast<TypeAttr>(byValAttribute.getValue()).getValue();
+ unsigned int typeSize =
+ DataLayout(callable->getParentOfType<DataLayoutOpInterface>())
+ .getTypeSize(elementType);
+ // Allocate the new value on the stack.
+ Value one = builder.create<LLVM::ConstantOp>(
+ func.getLoc(), builder.getI64Type(), builder.getI64IntegerAttr(1));
+ Value allocaOp =
+ builder.create<LLVM::AllocaOp>(func.getLoc(), ptrType, elementType, one);
+ // Copy the pointee to the newly allocated value.
+ Value copySize = builder.create<LLVM::ConstantOp>(
+ func.getLoc(), builder.getI64Type(), builder.getI64IntegerAttr(typeSize));
+ Value isVolatile = builder.create<LLVM::ConstantOp>(
+ func.getLoc(), builder.getI1Type(), builder.getBoolAttr(false));
+ builder.create<LLVM::MemcpyOp>(func.getLoc(), allocaOp, argument, copySize,
+ isVolatile);
+ return allocaOp;
+}
+
namespace {
struct LLVMInlinerInterface : public DialectInlinerInterface {
using DialectInlinerInterface::DialectInlinerInterface;
@@ -2866,8 +2900,19 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(callable);
if (!callOp || !funcOp)
return false;
- // TODO: Handle argument and result attributes;
- if (funcOp.getArgAttrs() || funcOp.getResAttrs())
+ if (auto attrs = funcOp.getArgAttrs()) {
+ for (Attribute attr : *attrs) {
+ auto attrDict = cast<DictionaryAttr>(attr);
+ for (NamedAttribute attr : attrDict) {
+ if (attr.getName() == LLVMDialect::getByValAttrName())
+ continue;
+ // TODO: Handle all argument attributes;
+ return false;
+ }
+ }
+ }
+ // TODO: Handle result attributes;
+ if (funcOp.getResAttrs())
return false;
// TODO: Handle exceptions.
if (funcOp.getPersonality())
@@ -2942,6 +2987,14 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
dst.replaceAllUsesWith(src);
}
+ Value handleArgument(OpBuilder &builder, Operation *call, Operation *callable,
+ Value argument, Type targetType,
+ DictionaryAttr argumentAttrs) const final {
+ if (auto attr = argumentAttrs.getNamed(LLVMDialect::getByValAttrName()))
+ return handleByValArgument(builder, callable, argument, *attr);
+ return argument;
+ }
+
void processInlinedCallBlocks(
Operation *call,
iterator_range<Region::iterator> inlinedBlocks) const override {
diff --git a/mlir/test/Dialect/LLVMIR/inlining.mlir b/mlir/test/Dialect/LLVMIR/inlining.mlir
index ab28f4236af97..cefb8d5e461d4 100644
--- a/mlir/test/Dialect/LLVMIR/inlining.mlir
+++ b/mlir/test/Dialect/LLVMIR/inlining.mlir
@@ -187,20 +187,6 @@ llvm.func @caller() {
// -----
-llvm.func @callee(%ptr : !llvm.ptr {llvm.byval = !llvm.ptr}) -> (!llvm.ptr) {
- llvm.return %ptr : !llvm.ptr
-}
-
-// CHECK-LABEL: llvm.func @caller
-// CHECK-NEXT: llvm.call @callee
-// CHECK-NEXT: return
-llvm.func @caller(%ptr : !llvm.ptr) -> (!llvm.ptr) {
- %0 = llvm.call @callee(%ptr) : (!llvm.ptr) -> (!llvm.ptr)
- llvm.return %0 : !llvm.ptr
-}
-
-// -----
-
llvm.func @static_alloca() -> f32 {
%0 = llvm.mlir.constant(4 : i32) : i32
%1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
@@ -349,3 +335,47 @@ llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {
^bb3(%blockArg: f32):
llvm.return %blockArg : f32
}
+
+// -----
+
+llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) {
+ llvm.return
+}
+
+// CHECK-LABEL: llvm.func @test_byval
+// CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]: !llvm.ptr
+// CHECK: %[[ALLOCA:.+]] = llvm.alloca %{{.+}} x f64
+// CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[PTR]]
+llvm.func @test_byval(%ptr : !llvm.ptr) {
+ llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()
+ llvm.return
+}
+
+// -----
+
+llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) attributes {memory = #llvm.memory_effects<other = readwrite, argMem = read, inaccessibleMem = readwrite>} {
+ llvm.return
+}
+
+// CHECK-LABEL: llvm.func @test_byval_read_only
+// CHECK-NOT: llvm.call
+// CHECK-NEXT: llvm.return
+llvm.func @test_byval_read_only(%ptr : !llvm.ptr) {
+ llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()
+ llvm.return
+}
+
+// -----
+
+llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) attributes {memory = #llvm.memory_effects<other = readwrite, argMem = write, inaccessibleMem = readwrite>} {
+ llvm.return
+}
+
+// CHECK-LABEL: llvm.func @test_byval_write_only
+// CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]: !llvm.ptr
+// CHECK: %[[ALLOCA:.+]] = llvm.alloca %{{.+}} x f64
+// CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[PTR]]
+llvm.func @test_byval_write_only(%ptr : !llvm.ptr) {
+ llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()
+ llvm.return
+}
More information about the Mlir-commits
mailing list