[Mlir-commits] [mlir] Reapply [MLIR][LLVM] Support for indirectbr (PR #136378)
Bruno Cardoso Lopes
llvmlistbot at llvm.org
Fri Apr 18 15:39:13 PDT 2025
https://github.com/bcardosolopes updated https://github.com/llvm/llvm-project/pull/136378
>From bc4267d2b20d2cd3ee9ed6c292706a2ab92ea3f9 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Mon, 14 Apr 2025 14:11:30 -0700
Subject: [PATCH] Reapply [MLIR][LLVM] Support for indirectbr
Fix msan issues that cause revert in https://github.com/llvm/llvm-project/pull/135695
Original message:
Now that LLVM dialect has `blockaddress` support, introduce import/translation for `indirectbr` instruction.
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 63 ++++++++++-
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 103 +++++++++++++++---
.../LLVMIR/LLVMToLLVMIRTranslation.cpp | 9 ++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 31 +++++-
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 8 ++
.../LLVMIR/blockaddress-canonicalize.mlir | 2 +-
mlir/test/Dialect/LLVMIR/indirectbr.mlir | 83 ++++++++++++++
.../Target/LLVMIR/Import/import-failure.ll | 12 --
mlir/test/Target/LLVMIR/Import/indirectbr.ll | 86 +++++++++++++++
mlir/test/Target/LLVMIR/indirectbr.mlir | 40 +++++++
.../test/mlir-translate/import-diagnostics.ll | 14 ++-
11 files changed, 411 insertions(+), 40 deletions(-)
create mode 100644 mlir/test/Dialect/LLVMIR/indirectbr.mlir
create mode 100644 mlir/test/Target/LLVMIR/Import/indirectbr.ll
create mode 100644 mlir/test/Target/LLVMIR/indirectbr.mlir
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 76a2ec47b3a22..5745d370f7268 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1690,8 +1690,7 @@ def LLVM_BlockTagOp : LLVM_Op<"blocktag"> {
the target address.
A given function should have at most one `llvm.blocktag` operation with a
- given `tag`. This operation cannot be used as a terminator but can be
- placed everywhere else in a block.
+ given `tag`. This operation cannot be used as a terminator.
Example:
@@ -1711,6 +1710,66 @@ def LLVM_BlockTagOp : LLVM_Op<"blocktag"> {
let hasVerifier = 0;
}
+//===----------------------------------------------------------------------===//
+// IndirectBrOp
+//===----------------------------------------------------------------------===//
+
+def LLVM_IndirectBrOp : LLVM_TerminatorOp<"indirectbr",
+ [SameVariadicOperandSize, DeclareOpInterfaceMethods<BranchOpInterface>,
+ Pure]> {
+ let description = [{
+ Transfer control flow to address in `$addr`. A list of possible target
+ blocks in `$successors` can be provided and maybe used as a hint in LLVM:
+
+ ```mlir
+ ...
+ llvm.func @g(...
+ %dest = llvm.blockaddress <function = @g, tag = <id = 0>> : !llvm.ptr
+ llvm.indirectbr %dest : !llvm.ptr, [
+ ^head
+ ]
+ ^head:
+ llvm.blocktag <id = 0>
+ llvm.return %arg0 : i32
+ ...
+ ```
+
+ It also supports a list of operands that can be passed to a target block:
+
+ ```mlir
+ llvm.indirectbr %dest : !llvm.ptr, [
+ ^head(%arg0 : i32),
+ ^tail(%arg1, %arg0 : i32, i32)
+ ]
+ ^head(%r0 : i32):
+ llvm.return %r0 : i32
+ ^tail(%r1 : i32, %r2 : i32):
+ ...
+ ```
+ }];
+ let arguments = (ins LLVM_AnyPointer:$addr,
+ VariadicOfVariadic<AnyType, "indbr_operand_segments">:$succOperands,
+ DenseI32ArrayAttr:$indbr_operand_segments
+ );
+ let successors = (successor VariadicSuccessor<AnySuccessor>:$successors);
+ let assemblyFormat = [{
+ $addr `:` type($addr) `,`
+ custom<IndirectBrOpSucessors>(ref(type($addr)),
+ $successors,
+ $succOperands,
+ type($succOperands))
+ attr-dict
+ }];
+
+ let skipDefaultBuilders = 1;
+ let builders = [
+ OpBuilder<(ins "Value":$addr,
+ CArg<"ArrayRef<ValueRange>", "{}">:$succOperands,
+ CArg<"BlockRange", "{}">:$successors
+ )>
+ ];
+}
+
def LLVM_ComdatSelectorOp : LLVM_Op<"comdat_selector", [Symbol]> {
let arguments = (ins
SymbolNameAttr:$sym_name,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index d1d00ca9681ec..0022be84c212e 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -2240,24 +2240,21 @@ static LogicalResult verifyComdat(Operation *op,
static LogicalResult verifyBlockTags(LLVMFuncOp funcOp) {
llvm::DenseSet<BlockTagAttr> blockTags;
- BlockTagOp badBlockTagOp;
- if (funcOp
- .walk([&](BlockTagOp blockTagOp) {
- if (blockTags.contains(blockTagOp.getTag())) {
- badBlockTagOp = blockTagOp;
- return WalkResult::interrupt();
- }
- blockTags.insert(blockTagOp.getTag());
- return WalkResult::advance();
- })
- .wasInterrupted()) {
- badBlockTagOp.emitError()
- << "duplicate block tag '" << badBlockTagOp.getTag().getId()
- << "' in the same function: ";
- return failure();
- }
+ // Note that presence of `BlockTagOp`s currently can't prevent an unrecheable
+ // block to be removed by canonicalizer's region simplify pass, which needs to
+ // be dialect aware to allow extra constraints to be described.
+ WalkResult res = funcOp.walk([&](BlockTagOp blockTagOp) {
+ if (blockTags.contains(blockTagOp.getTag())) {
+ blockTagOp.emitError()
+ << "duplicate block tag '" << blockTagOp.getTag().getId()
+ << "' in the same function: ";
+ return WalkResult::interrupt();
+ }
+ blockTags.insert(blockTagOp.getTag());
+ return WalkResult::advance();
+ });
- return success();
+ return failure(res.wasInterrupted());
}
/// Parse common attributes that might show up in the same order in both
@@ -3818,6 +3815,78 @@ LogicalResult BlockAddressOp::verify() {
/// attribute.
OpFoldResult BlockAddressOp::fold(FoldAdaptor) { return getBlockAddr(); }
+//===----------------------------------------------------------------------===//
+// LLVM::IndirectBrOp
+//===----------------------------------------------------------------------===//
+
+SuccessorOperands IndirectBrOp::getSuccessorOperands(unsigned index) {
+ assert(index < getNumSuccessors() && "invalid successor index");
+ return SuccessorOperands(getSuccOperandsMutable()[index]);
+}
+
+void IndirectBrOp::build(OpBuilder &odsBuilder, OperationState &odsState,
+ Value addr, ArrayRef<ValueRange> succOperands,
+ BlockRange successors) {
+ odsState.addOperands(addr);
+ for (ValueRange range : succOperands)
+ odsState.addOperands(range);
+ SmallVector<int32_t> rangeSegments;
+ for (ValueRange range : succOperands)
+ rangeSegments.push_back(range.size());
+ odsState.getOrAddProperties<Properties>().indbr_operand_segments =
+ odsBuilder.getDenseI32ArrayAttr(rangeSegments);
+ odsState.addSuccessors(successors);
+}
+
+static ParseResult parseIndirectBrOpSucessors(
+ OpAsmParser &parser, Type &flagType,
+ SmallVectorImpl<Block *> &succOperandBlocks,
+ SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>> &succOperands,
+ SmallVectorImpl<SmallVector<Type>> &succOperandsTypes) {
+ if (failed(parser.parseCommaSeparatedList(
+ OpAsmParser::Delimiter::Square,
+ [&]() {
+ Block *destination = nullptr;
+ SmallVector<OpAsmParser::UnresolvedOperand> operands;
+ SmallVector<Type> operandTypes;
+
+ if (parser.parseSuccessor(destination).failed())
+ return failure();
+
+ if (succeeded(parser.parseOptionalLParen())) {
+ if (failed(parser.parseOperandList(
+ operands, OpAsmParser::Delimiter::None)) ||
+ failed(parser.parseColonTypeList(operandTypes)) ||
+ failed(parser.parseRParen()))
+ return failure();
+ }
+ succOperandBlocks.push_back(destination);
+ succOperands.emplace_back(operands);
+ succOperandsTypes.emplace_back(operandTypes);
+ return success();
+ },
+ "successor blocks")))
+ return failure();
+ return success();
+}
+
+static void
+printIndirectBrOpSucessors(OpAsmPrinter &p, IndirectBrOp op, Type flagType,
+ SuccessorRange succs, OperandRangeRange succOperands,
+ const TypeRangeRange &succOperandsTypes) {
+ p << "[";
+ llvm::interleave(
+ llvm::zip(succs, succOperands),
+ [&](auto i) {
+ p.printNewline();
+ p.printSuccessorAndUseList(std::get<0>(i), std::get<1>(i));
+ },
+ [&] { p << ','; });
+ if (!succOperands.empty())
+ p.printNewline();
+ p << "]";
+}
+
//===----------------------------------------------------------------------===//
// AssumeOp (intrinsic)
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index ad48ca2ce8ad3..7038b5d73d266 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -505,6 +505,15 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
moduleTranslation.mapBranch(&opInst, switchInst);
return success();
}
+ if (auto indBrOp = dyn_cast<LLVM::IndirectBrOp>(opInst)) {
+ llvm::IndirectBrInst *indBr = builder.CreateIndirectBr(
+ moduleTranslation.lookupValue(indBrOp.getAddr()),
+ indBrOp->getNumSuccessors());
+ for (auto *succ : indBrOp.getSuccessors())
+ indBr->addDestination(moduleTranslation.lookupBlock(succ));
+ moduleTranslation.mapBranch(&opInst, indBr);
+ return success();
+ }
// Emit addressof. We need to look up the global value referenced by the
// operation and store it in the MLIR-to-LLVM value mapping. This does not
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 481d719787397..df7c8d6ea3579 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1988,6 +1988,33 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
return success();
}
+ if (inst->getOpcode() == llvm::Instruction::IndirectBr) {
+ auto *indBrInst = cast<llvm::IndirectBrInst>(inst);
+
+ FailureOr<Value> basePtr = convertValue(indBrInst->getAddress());
+ if (failed(basePtr))
+ return failure();
+
+ SmallVector<Block *> succBlocks;
+ SmallVector<SmallVector<Value>> succBlockArgs;
+ for (auto i : llvm::seq<unsigned>(0, indBrInst->getNumSuccessors())) {
+ llvm::BasicBlock *succ = indBrInst->getSuccessor(i);
+ SmallVector<Value> blockArgs;
+ if (failed(convertBranchArgs(indBrInst, succ, blockArgs)))
+ return failure();
+ succBlocks.push_back(lookupBlock(succ));
+ succBlockArgs.push_back(blockArgs);
+ }
+ SmallVector<ValueRange> succBlockArgsRange =
+ llvm::to_vector_of<ValueRange>(succBlockArgs);
+ Location loc = translateLoc(inst->getDebugLoc());
+ auto indBrOp = builder.create<LLVM::IndirectBrOp>(
+ loc, *basePtr, succBlockArgsRange, succBlocks);
+
+ mapNoResultOp(inst, indBrOp);
+ return success();
+ }
+
// Convert all instructions that have an mlirBuilder.
if (succeeded(convertInstructionImpl(builder, inst, *this, iface)))
return success();
@@ -1998,8 +2025,8 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
LogicalResult ModuleImport::processInstruction(llvm::Instruction *inst) {
// FIXME: Support uses of SubtargetData.
// FIXME: Add support for call / operand attributes.
- // FIXME: Add support for the indirectbr, cleanupret, catchret, catchswitch,
- // callbr, vaarg, catchpad, cleanuppad instructions.
+ // FIXME: Add support for the cleanupret, catchret, catchswitch, callbr,
+ // vaarg, catchpad, cleanuppad instructions.
// Convert LLVM intrinsics calls to MLIR intrinsics.
if (auto *intrinsic = dyn_cast<llvm::IntrinsicInst>(inst))
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index d39ec0e801437..44899c4576a20 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -805,6 +805,14 @@ static Value getPHISourceValue(Block *current, Block *pred,
return switchOp.getCaseOperands(i.index())[index];
}
+ if (auto indBrOp = dyn_cast<LLVM::IndirectBrOp>(terminator)) {
+ // For indirect branches we take operands for each successor.
+ for (const auto &i : llvm::enumerate(indBrOp->getSuccessors())) {
+ if (indBrOp->getSuccessor(i.index()) == current)
+ return indBrOp.getSuccessorOperands(i.index())[index];
+ }
+ }
+
if (auto invokeOp = dyn_cast<LLVM::InvokeOp>(terminator)) {
return invokeOp.getNormalDest() == current
? invokeOp.getNormalDestOperands()[index]
diff --git a/mlir/test/Dialect/LLVMIR/blockaddress-canonicalize.mlir b/mlir/test/Dialect/LLVMIR/blockaddress-canonicalize.mlir
index 11dd6f0d97f78..241a2ea2edc66 100644
--- a/mlir/test/Dialect/LLVMIR/blockaddress-canonicalize.mlir
+++ b/mlir/test/Dialect/LLVMIR/blockaddress-canonicalize.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -pass-pipeline='builtin.module(llvm.func(canonicalize{region-simplify=aggressive}))' -split-input-file | FileCheck %s
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(llvm.func(canonicalize{region-simplify=aggressive}))' -verify-diagnostics -split-input-file | FileCheck %s
llvm.mlir.global private @x() {addr_space = 0 : i32, dso_local} : !llvm.ptr {
%0 = llvm.blockaddress <function = @ba, tag = <id = 2>> : !llvm.ptr
diff --git a/mlir/test/Dialect/LLVMIR/indirectbr.mlir b/mlir/test/Dialect/LLVMIR/indirectbr.mlir
new file mode 100644
index 0000000000000..63bdfea0c3095
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/indirectbr.mlir
@@ -0,0 +1,83 @@
+// RUN: mlir-opt -split-input-file --verify-roundtrip %s | FileCheck %s
+
+llvm.func @ib0(%dest : !llvm.ptr, %arg0 : i32, %arg1 : i32) -> i32 {
+ llvm.indirectbr %dest : !llvm.ptr, [
+ ^head(%arg0 : i32),
+ ^tail(%arg1, %arg0 : i32, i32)
+ ]
+^head(%r0 : i32):
+ llvm.return %r0 : i32
+^tail(%r1 : i32, %r2 : i32):
+ %r = llvm.add %r1, %r2 : i32
+ llvm.return %r : i32
+}
+
+// CHECK: llvm.func @ib0(%[[Addr:.*]]: !llvm.ptr, %[[A0:.*]]: i32, %[[A1:.*]]: i32) -> i32 {
+// CHECK: llvm.indirectbr %[[Addr]] : !llvm.ptr, [
+// CHECK: ^bb1(%[[A0:.*]] : i32)
+// CHECK: ^bb2(%[[A1:.*]], %[[A0]] : i32, i32)
+// CHECK: ]
+// CHECK: ^bb1(%[[Op0:.*]]: i32):
+// CHECK: llvm.return %[[Op0]] : i32
+// CHECK: ^bb2(%[[Op1:.*]]: i32, %[[Op2:.*]]: i32):
+// CHECK: %[[Op3:.*]] = llvm.add %[[Op1]], %[[Op2]] : i32
+// CHECK: llvm.return %[[Op3]] : i32
+// CHECK: }
+
+// -----
+
+llvm.func @ib1(%dest : !llvm.ptr) {
+ llvm.indirectbr %dest : !llvm.ptr, []
+}
+
+// CHECK: llvm.func @ib1(%[[Addr:.*]]: !llvm.ptr) {
+// CHECK: llvm.indirectbr %[[Addr]] : !llvm.ptr, []
+// CHECK: }
+
+// -----
+
+// CHECK: llvm.func @test_indirectbr_phi(
+// CHECK-SAME: %arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: i32) -> i32 {
+llvm.func @callee(!llvm.ptr, i32, i32) -> i32
+llvm.func @test_indirectbr_phi(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: i32) -> i32 {
+ %0 = llvm.mlir.undef : i1
+ %1 = llvm.mlir.addressof @test_indirectbr_phi : !llvm.ptr
+ %2 = llvm.blockaddress <function = @test_indirectbr_phi, tag = <id = 1>> : !llvm.ptr
+ // CHECK: %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
+ %3 = llvm.mlir.constant(1 : i32) : i32
+ // CHECK: %[[TWO:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %4 = llvm.mlir.constant(2 : i32) : i32
+ %5 = llvm.select %0, %2, %arg0 : i1, !llvm.ptr
+ // CHECK: llvm.indirectbr {{.*}} : !llvm.ptr, [
+ // CHECK: ^[[HEAD_BB:.*]],
+ // CHECK: ^[[TAIL_BB:.*]](%[[ONE]] : i32)
+ // CHECK: ]
+ llvm.indirectbr %5 : !llvm.ptr, [
+ ^bb1,
+ ^bb2(%3 : i32)
+ ]
+^bb1:
+ // CHECK: ^[[HEAD_BB]]:
+ // CHECK: llvm.indirectbr {{.*}} : !llvm.ptr, [
+ // CHECK: ^[[TAIL_BB]](%[[TWO]] : i32),
+ // CHECK: ^[[END_BB:.*]]
+ // CHECK: ]
+ %6 = llvm.select %0, %2, %arg0 : i1, !llvm.ptr
+ llvm.indirectbr %6 : !llvm.ptr, [
+ ^bb2(%4 : i32),
+ ^bb3
+ ]
+^bb2(%7: i32):
+ // CHECK: ^[[TAIL_BB]](%[[BLOCK_ARG:.*]]: i32):
+ // CHECK: {{.*}} = llvm.call @callee({{.*}}, %[[BLOCK_ARG]])
+ // CHECK: llvm.return
+ %8 = llvm.call @callee(%arg1, %arg3, %7) : (!llvm.ptr, i32, i32) -> i32
+ llvm.return %8 : i32
+^bb3:
+ // CHECK: ^[[END_BB]]:
+ // CHECK: llvm.blocktag
+ // CHECK: llvm.return
+ // CHECK: }
+ llvm.blocktag <id = 1>
+ llvm.return %arg3 : i32
+}
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 4fbf187659a7b..782925a0a938e 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -1,17 +1,5 @@
; RUN: not mlir-translate -import-llvm -emit-expensive-warnings -split-input-file %s 2>&1 -o /dev/null | FileCheck %s
-; CHECK: <unknown>
-; CHECK-SAME: error: unhandled instruction: indirectbr ptr %dst, [label %bb1, label %bb2]
-define i32 @unhandled_instruction(ptr %dst) {
- indirectbr ptr %dst, [label %bb1, label %bb2]
-bb1:
- ret i32 0
-bb2:
- ret i32 1
-}
-
-; // -----
-
; Check that debug intrinsics with an unsupported argument are dropped.
declare void @llvm.dbg.value(metadata, metadata, metadata)
diff --git a/mlir/test/Target/LLVMIR/Import/indirectbr.ll b/mlir/test/Target/LLVMIR/Import/indirectbr.ll
new file mode 100644
index 0000000000000..7c197a5281ddd
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/indirectbr.ll
@@ -0,0 +1,86 @@
+; RUN: mlir-translate --import-llvm %s -split-input-file | FileCheck %s
+
+; CHECK: llvm.func @basic(%[[arg0:.*]]: !llvm.ptr)
+define i32 @basic(ptr %dst) {
+ ; CHECK: llvm.indirectbr %[[arg0]] : !llvm.ptr, [
+ ; CHECK: ^[[bb1:.*]],
+ ; CHECK: ^[[bb2:.*]]
+ ; CHECK: ]
+ indirectbr ptr %dst, [label %bb1, label %bb2]
+bb1:
+ ; CHECK: ^[[bb1]]:
+ ; CHECK: llvm.return
+ ret i32 0
+bb2:
+ ; CHECK: ^[[bb2]]:
+ ; CHECK: llvm.return
+ ret i32 1
+}
+
+; // -----
+
+; CHECK: llvm.mlir.global external @addr()
+ at addr = global ptr null
+
+; CHECK-LABEL: llvm.func @test_indirectbr() {
+define void @test_indirectbr() {
+ ; CHECK: %[[BA:.*]] = llvm.blockaddress <function = @test_indirectbr, tag = <id = 1>> : !llvm.ptr
+ ; CHECK: {{.*}} = llvm.mlir.addressof @addr : !llvm.ptr
+ ; CHECK: llvm.store %[[BA]], {{.*}} : !llvm.ptr, !llvm.ptr
+ store ptr blockaddress(@test_indirectbr, %block), ptr @addr
+ ; CHECK: %[[TARGET_ADDR:.*]] = llvm.load {{.*}} : !llvm.ptr -> !llvm.ptr
+ %val = load ptr, ptr @addr
+ ; CHECK: llvm.indirectbr %[[TARGET_ADDR]] : !llvm.ptr, [
+ ; CHECK: ^[[TARGET_BB:.*]]
+ ; CHECK: ]
+ indirectbr ptr %val, [label %block]
+ ; CHECK: ^[[TARGET_BB]]:
+ ; CHECK: llvm.blocktag <id = 1>
+ ; CHECK: llvm.return
+ ; CHECK: }
+block:
+ ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @callee(!llvm.ptr, i32, i32) -> i32
+declare i32 @callee(ptr %a, i32 %v, i32 %p)
+
+; CHECK: llvm.func @test_indirectbr_phi(
+; CHECK-SAME: %arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr, %arg3: i32) -> i32 {
+define i32 @test_indirectbr_phi(ptr %address, ptr %a, ptr %b, i32 %v) {
+entry:
+ ; CHECK: %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
+ ; CHECK: %[[TWO:.*]] = llvm.mlir.constant(2 : i32) : i32
+ %dest = select i1 poison, ptr blockaddress(@test_indirectbr_phi, %end), ptr %address
+ ; CHECK: llvm.indirectbr {{.*}} : !llvm.ptr, [
+ ; CHECK: ^[[HEAD_BB:.*]],
+ ; CHECK: ^[[TAIL_BB:.*]](%[[ONE]] : i32)
+ ; CHECK: ]
+ indirectbr ptr %dest, [label %head, label %tail]
+
+head:
+ ; CHECK: ^[[HEAD_BB]]:
+ ; CHECK: llvm.indirectbr {{.*}} : !llvm.ptr, [
+ ; CHECK: ^[[TAIL_BB]](%[[TWO]] : i32),
+ ; CHECK: ^[[END_BB:.*]]
+ ; CHECK: ]
+ %dest2 = select i1 poison, ptr blockaddress(@test_indirectbr_phi, %end), ptr %address
+ indirectbr ptr %dest2, [label %tail, label %end]
+
+tail:
+ ; CHECK: ^[[TAIL_BB]](%[[BLOCK_ARG:.*]]: i32):
+ ; CHECK: {{.*}} = llvm.call @callee({{.*}}, %[[BLOCK_ARG]])
+ ; CHECK: llvm.return
+ %p = phi i32 [1, %entry], [2, %head]
+ %r = call i32 @callee(ptr %a, i32 %v, i32 %p)
+ ret i32 %r
+
+end:
+ ; CHECK: ^[[END_BB]]:
+ ; CHECK: llvm.blocktag
+ ; CHECK: llvm.return
+ ; CHECK: }
+ ret i32 %v
+}
diff --git a/mlir/test/Target/LLVMIR/indirectbr.mlir b/mlir/test/Target/LLVMIR/indirectbr.mlir
new file mode 100644
index 0000000000000..538220721e9eb
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/indirectbr.mlir
@@ -0,0 +1,40 @@
+// RUN: mlir-translate -mlir-to-llvmir %s -split-input-file | FileCheck %s
+
+llvm.func @callee(!llvm.ptr, i32, i32) -> i32
+
+// CHECK: define i32 @test_indirectbr_phi(ptr %[[IN_PTR:.*]], ptr %[[ARG1:.*]], i32 %[[ARG2:.*]]) {
+llvm.func @test_indirectbr_phi(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg3: i32) -> i32 {
+ %0 = llvm.mlir.undef : i1
+ %2 = llvm.blockaddress <function = @test_indirectbr_phi, tag = <id = 1>> : !llvm.ptr
+ %3 = llvm.mlir.constant(1 : i32) : i32
+ %4 = llvm.mlir.constant(2 : i32) : i32
+ %5 = llvm.select %0, %2, %arg0 : i1, !llvm.ptr
+ // CHECK: %[[BA0:.*]] = select i1 undef, ptr blockaddress(@test_indirectbr_phi, %[[RET_BB:.*]]), ptr %[[IN_PTR]]
+ // CHECK: indirectbr ptr %[[BA0]], [label %[[BB1:.*]], label %[[BB2:.*]]]
+ llvm.indirectbr %5 : !llvm.ptr, [
+ ^bb1,
+ ^bb2(%3 : i32)
+ ]
+^bb1:
+ // CHECK: [[BB1]]:
+ // CHECK: %[[BA1:.*]] = select i1 undef, ptr blockaddress(@test_indirectbr_phi, %[[RET_BB]]), ptr %[[IN_PTR]]
+ // CHECK: indirectbr ptr %[[BA1]], [label %[[BB2]], label %[[RET_BB]]]
+ %6 = llvm.select %0, %2, %arg0 : i1, !llvm.ptr
+ llvm.indirectbr %6 : !llvm.ptr, [
+ ^bb2(%4 : i32),
+ ^bb3
+ ]
+^bb2(%7: i32):
+ // CHECK: [[BB2]]:
+ // CHECK: %[[PHI:.*]] = phi i32 [ 2, %[[BB1]] ], [ 1, {{.*}} ]
+ // CHECK: %[[CALL:.*]] = call i32 @callee(ptr %[[ARG1]], i32 %[[ARG2]], i32 %[[PHI]])
+ // CHECK: ret i32 %[[CALL]]
+ %8 = llvm.call @callee(%arg1, %arg3, %7) : (!llvm.ptr, i32, i32) -> i32
+ llvm.return %8 : i32
+^bb3:
+ // CHECK: [[RET_BB]]:
+ // CHECK: ret i32 %[[ARG2]]
+ // CHECK: }
+ llvm.blocktag <id = 1>
+ llvm.return %arg3 : i32
+}
diff --git a/mlir/test/mlir-translate/import-diagnostics.ll b/mlir/test/mlir-translate/import-diagnostics.ll
index acf45eb1c7c5d..6767d948e3bbd 100644
--- a/mlir/test/mlir-translate/import-diagnostics.ll
+++ b/mlir/test/mlir-translate/import-diagnostics.ll
@@ -21,14 +21,16 @@ end:
; ERROR: error:
; DEFAULT: error:
; EXPENSIVE: error:
-define i32 @error(ptr %dst) {
- indirectbr ptr %dst, [label %bb1, label %bb2]
-bb1:
- ret i32 0
-bb2:
- ret i32 1
+define dso_local void @tbaa(ptr %0) {
+ store i32 1, ptr %0, align 4, !tbaa !2
+ ret void
}
+!2 = !{!3, !3, i64 0, i64 4}
+!3 = !{!4, i64 4, !"int"}
+!4 = !{!5, i64 1, !"omnipotent char"}
+!5 = !{!"Simple C++ TBAA"}
+
; // -----
declare void @llvm.dbg.value(metadata, metadata, metadata)
More information about the Mlir-commits
mailing list