In certain situations it isn't legal to inline a call operation, but this isn't something that is possible(at least not easily) to prevent with the current hooks. This revision adds a new hook so that dialects with call operations that shouldn't be inlined can prevent it.
Differential Revision: https://reviews.llvm.org/D90359
struct ToyInlinerInterface : public DialectInlinerInterface {
using DialectInlinerInterface::DialectInlinerInterface;
+ /// This hook checks to see if the given callable operation is legal to inline
+ /// into the given call. For Toy this hook can simply return true, as the Toy
+ /// Call operation is always inlinable.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// This hook checks to see if the given operation is legal to inline into the
/// given region. For Toy this hook can simply return true, as all Toy
/// operations are inlinable.
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// All call operations within toy can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// All operations within toy can be inlined.
bool isLegalToInline(Operation *, Region *,
BlockAndValueMapping &) const final {
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// All call operations within toy can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// All operations within toy can be inlined.
bool isLegalToInline(Operation *, Region *,
BlockAndValueMapping &) const final {
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// All call operations within toy can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// All operations within toy can be inlined.
bool isLegalToInline(Operation *, Region *,
BlockAndValueMapping &) const final {
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// All call operations within toy can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// All operations within toy can be inlined.
bool isLegalToInline(Operation *, Region *,
BlockAndValueMapping &) const final {
template <typename AttrClass> AttrClass getAttrOfType(Identifier name) {
return getAttr(name).dyn_cast_or_null<AttrClass>();
}
-
template <typename AttrClass> AttrClass getAttrOfType(StringRef name) {
return getAttr(name).dyn_cast_or_null<AttrClass>();
}
+ /// Return true if the operation has an attribute with the provided name,
+ /// false otherwise.
+ bool hasAttr(Identifier name) { return static_cast<bool>(getAttr(name)); }
+ bool hasAttr(StringRef name) { return static_cast<bool>(getAttr(name)); }
+ template <typename AttrClass, typename NameT>
+ bool hasAttrOfType(NameT &&name) {
+ return static_cast<bool>(
+ getAttrOfType<AttrClass>(std::forward<NameT>(name)));
+ }
+
/// If the an attribute exists with the specified name, change it to the new
/// value. Otherwise, add a new attribute with the specified name/value.
void setAttr(Identifier name, Attribute value) { attrs.set(name, value); }
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// Returns true if the given operation 'callable', that implements the
+ /// 'CallableOpInterface', can be inlined into the position given call
+ /// operation 'call', that is registered to the current dialect and implements
+ /// the `CallOpInterface`.
+ virtual bool isLegalToInline(Operation *call, Operation *callable) const {
+ return false;
+ }
+
/// Returns true if the given region 'src' can be inlined into the region
/// 'dest' that is attached to an operation registered to the current dialect.
/// 'valueMapping' contains any remapped values from within the 'src' region.
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ virtual bool isLegalToInline(Operation *call, Operation *callable) const;
virtual bool isLegalToInline(Region *dest, Region *src,
BlockAndValueMapping &valueMapping) const;
virtual bool isLegalToInline(Operation *op, Region *dest,
struct SPIRVInlinerInterface : public DialectInlinerInterface {
using DialectInlinerInterface::DialectInlinerInterface;
+ /// All call operations within SPIRV can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// Returns true if the given region 'src' can be inlined into the region
/// 'dest' that is attached to an operation registered to the current dialect.
bool isLegalToInline(Region *dest, Region *src,
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ /// All call operations within standard ops can be inlined.
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ return true;
+ }
+
/// All operations within standard ops can be inlined.
bool isLegalToInline(Operation *, Region *,
BlockAndValueMapping &) const final {
// InlinerInterface
//===----------------------------------------------------------------------===//
+bool InlinerInterface::isLegalToInline(Operation *call,
+ Operation *callable) const {
+ auto *handler = getInterfaceFor(call);
+ return handler ? handler->isLegalToInline(call, callable) : false;
+}
+
bool InlinerInterface::isLegalToInline(
Region *dest, Region *src, BlockAndValueMapping &valueMapping) const {
// Regions can always be inlined into functions.
castResult.getDefiningOp()->replaceUsesOfWith(castResult, callResult);
}
+ // Check that it is legal to inline the callable into the call.
+ if (!interface.isLegalToInline(call, callable))
+ return cleanupState();
+
// Attempt to inline the call.
if (failed(inlineRegion(interface, src, call, mapper, callResults,
callableResultTypes, call.getLoc(),
%res = call_indirect %fn() : () -> i32
return %res : i32
}
+
+// CHECK-LABEL: func @no_inline_invalid_call
+func @no_inline_invalid_call() -> i32 {
+ %res = "test.conversion_call_op"() { callee=@convert_callee_fn_multiblock, noinline } : () -> (i32)
+ return %res : i32
+}
// Analysis Hooks
//===--------------------------------------------------------------------===//
+ bool isLegalToInline(Operation *call, Operation *callable) const final {
+ // Don't allow inlining calls that are marked `noinline`.
+ return !call->hasAttr("noinline");
+ }
bool isLegalToInline(Region *, Region *, BlockAndValueMapping &) const final {
// Inlining into test dialect regions is legal.
return true;