Skip to content

Commit b39c5cb

Browse files
authored
[MLIR][LLVM] Fix inlining of a single block ending with unreachable (#122646)
alternate option to #122615
1 parent 9844bad commit b39c5cb

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed

mlir/include/mlir/Transforms/InliningUtils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ class DialectInlinerInterface
176176
/// is invoked before inlined terminator operations have been processed.
177177
virtual void processInlinedCallBlocks(
178178
Operation *call, iterator_range<Region::iterator> inlinedBlocks) const {}
179+
180+
/// Returns true if the inliner can assume a fast path of not creating a new
181+
/// block, if there is only one block.
182+
virtual bool allowSingleBlockOptimization(
183+
iterator_range<Region::iterator> inlinedBlocks) const {
184+
return true;
185+
}
179186
};
180187

181188
/// This interface provides the hooks into the inlining interface.
@@ -223,6 +230,9 @@ class InlinerInterface
223230

224231
virtual void processInlinedCallBlocks(
225232
Operation *call, iterator_range<Region::iterator> inlinedBlocks) const;
233+
234+
virtual bool allowSingleBlockOptimization(
235+
iterator_range<Region::iterator> inlinedBlocks) const;
226236
};
227237

228238
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,14 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
744744
op->erase();
745745
}
746746

747+
bool allowSingleBlockOptimization(
748+
iterator_range<Region::iterator> inlinedBlocks) const final {
749+
if (!inlinedBlocks.empty() &&
750+
isa<LLVM::UnreachableOp>(inlinedBlocks.begin()->getTerminator()))
751+
return false;
752+
return true;
753+
}
754+
747755
/// Handle the given inlined return by replacing the uses of the call with the
748756
/// operands of the return. This overload is called when the inlined region
749757
/// only contains one block.

mlir/lib/Transforms/Utils/InliningUtils.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ void InlinerInterface::handleTerminator(Operation *op,
118118
handler->handleTerminator(op, valuesToRepl);
119119
}
120120

121+
/// Returns true if the inliner can assume a fast path of not creating a
122+
/// new block, if there is only one block.
123+
bool InlinerInterface::allowSingleBlockOptimization(
124+
iterator_range<Region::iterator> inlinedBlocks) const {
125+
if (inlinedBlocks.empty()) {
126+
return true;
127+
}
128+
auto *handler = getInterfaceFor(inlinedBlocks.begin()->getParentOp());
129+
assert(handler && "expected valid dialect handler");
130+
return handler->allowSingleBlockOptimization(inlinedBlocks);
131+
}
132+
121133
Value InlinerInterface::handleArgument(OpBuilder &builder, Operation *call,
122134
Operation *callable, Value argument,
123135
DictionaryAttr argumentAttrs) const {
@@ -294,8 +306,10 @@ inlineRegionImpl(InlinerInterface &interface, Region *src, Block *inlineBlock,
294306
interface.processInlinedCallBlocks(call, newBlocks);
295307
interface.processInlinedBlocks(newBlocks);
296308

309+
bool singleBlockFastPath = interface.allowSingleBlockOptimization(newBlocks);
310+
297311
// Handle the case where only a single block was inlined.
298-
if (std::next(newBlocks.begin()) == newBlocks.end()) {
312+
if (singleBlockFastPath && std::next(newBlocks.begin()) == newBlocks.end()) {
299313
// Run the result attribute handler on the terminator operands.
300314
Operation *firstBlockTerminator = firstNewBlock->getTerminator();
301315
builder.setInsertionPoint(firstBlockTerminator);

mlir/test/Dialect/LLVMIR/inlining.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,3 +676,19 @@ llvm.func @caller(%x : i32) -> i32 {
676676
%z = llvm.call @private_func(%x) : (i32) -> (i32)
677677
llvm.return %z : i32
678678
}
679+
680+
// -----
681+
682+
llvm.func @unreachable_func(%a : i32) -> i32 {
683+
"llvm.intr.trap"() : () -> ()
684+
llvm.unreachable
685+
}
686+
687+
// CHECK-LABEL: func @caller
688+
llvm.func @caller(%x : i32) -> i32 {
689+
// CHECK-NOT: llvm.call @unreachable_func
690+
// CHECK: llvm.intr.trap
691+
// CHECK: llvm.unreachable
692+
%z = llvm.call @unreachable_func(%x) : (i32) -> (i32)
693+
llvm.return %z : i32
694+
}

0 commit comments

Comments
 (0)