diff --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h --- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h +++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h @@ -337,6 +337,12 @@ /// getSpeculatability hook in the ConditionallySpeculatable op interface. bool isSpeculatable(Operation *op); +/// Returns true if the given operation is pure, i.e., is speculatable that does +/// not touch memory. +/// +/// This function is the C++ equivalent of the `Pure` trait. +bool isPure(Operation *op); + } // namespace mlir //===----------------------------------------------------------------------===// 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 @@ -20,6 +20,7 @@ #include "mlir/IR/FunctionImplementation.h" #include "mlir/IR/MLIRContext.h" #include "mlir/IR/Matchers.h" +#include "mlir/Transforms/InliningUtils.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/AsmParser/Parser.h" @@ -2583,6 +2584,22 @@ }; } // namespace +//===----------------------------------------------------------------------===// +// DialectInlinerInterface +//===----------------------------------------------------------------------===// + +namespace { +struct LLVMInlinerInterface : public DialectInlinerInterface { + using DialectInlinerInterface::DialectInlinerInterface; + + /// Conservatively only allow inlining of pure ops. + bool isLegalToInline(Operation *op, Region *, bool, + BlockAndValueMapping &) const final { + return isPure(op); + } +}; +} // end anonymous namespace + //===----------------------------------------------------------------------===// // LLVMDialect initialization, type parsing, and registration. //===----------------------------------------------------------------------===// @@ -2611,7 +2628,10 @@ // Support unknown operations because not all LLVM operations are registered. allowUnknownOperations(); - addInterfaces(); + // clang-format off + addInterfaces(); + // clang-format on } #define GET_OP_CLASSES diff --git a/mlir/lib/Interfaces/SideEffectInterfaces.cpp b/mlir/lib/Interfaces/SideEffectInterfaces.cpp --- a/mlir/lib/Interfaces/SideEffectInterfaces.cpp +++ b/mlir/lib/Interfaces/SideEffectInterfaces.cpp @@ -202,3 +202,9 @@ llvm_unreachable("Unhandled enum in mlir::isSpeculatable!"); } + +/// The implementation of this function replicates the `def Pure : TraitList` +/// in `SideEffectInterfaces.td` and has to be kept in sync manually. +bool mlir::isPure(Operation *op) { + return isSpeculatable(op) && isMemoryEffectFree(op); +} diff --git a/mlir/test/Dialect/LLVMIR/inlining.mlir b/mlir/test/Dialect/LLVMIR/inlining.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/inlining.mlir @@ -0,0 +1,28 @@ +// RUN: mlir-opt %s -inline | FileCheck %s + +// CHECK-LABEL: func.func @test_inline() -> i32 { +// CHECK-NEXT: %[[RES:.*]] = llvm.mlir.constant(42 : i32) : i32 +// CHECK-NEXT: return %[[RES]] : i32 +func.func @test_inline() -> i32 { + %0 = call @inner_func_inlinable() : () -> i32 + return %0 : i32 +} + +func.func @inner_func_inlinable() -> i32 { + %0 = llvm.mlir.constant(42 : i32) : i32 + return %0 : i32 +} + +// CHECK-LABEL: func.func @test_not_inline() -> !llvm.ptr { +// CHECK-NEXT: %[[RES:.*]] = call @inner_func_not_inlinable() : () -> !llvm.ptr +// CHECK-NEXT: return %[[RES]] : !llvm.ptr +func.func @test_not_inline() -> !llvm.ptr { + %0 = call @inner_func_not_inlinable() : () -> !llvm.ptr + return %0 : !llvm.ptr +} + +func.func @inner_func_not_inlinable() -> !llvm.ptr { + %0 = llvm.mlir.constant(0 : i32) : i32 + %1 = llvm.alloca %0 x f64 : (i32) -> !llvm.ptr + return %1 : !llvm.ptr +}