/// 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
//===----------------------------------------------------------------------===//
#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"
} // 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.
//===----------------------------------------------------------------------===//
// Support unknown operations because not all LLVM operations are registered.
allowUnknownOperations();
- addInterfaces<LLVMOpAsmDialectInterface>();
+ // clang-format off
+ addInterfaces<LLVMOpAsmDialectInterface,
+ LLVMInlinerInterface>();
+ // clang-format on
}
#define GET_OP_CLASSES
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);
+}
--- /dev/null
+// 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<f64> {
+// CHECK-NEXT: %[[RES:.*]] = call @inner_func_not_inlinable() : () -> !llvm.ptr<f64>
+// CHECK-NEXT: return %[[RES]] : !llvm.ptr<f64>
+func.func @test_not_inline() -> !llvm.ptr<f64> {
+ %0 = call @inner_func_not_inlinable() : () -> !llvm.ptr<f64>
+ return %0 : !llvm.ptr<f64>
+}
+
+func.func @inner_func_not_inlinable() -> !llvm.ptr<f64> {
+ %0 = llvm.mlir.constant(0 : i32) : i32
+ %1 = llvm.alloca %0 x f64 : (i32) -> !llvm.ptr<f64>
+ return %1 : !llvm.ptr<f64>
+}