From bc4267d2b20d2cd3ee9ed6c292706a2ab92ea3f9 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes 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, + 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 > : !llvm.ptr + llvm.indirectbr %dest : !llvm.ptr, [ + ^head + ] + ^head: + llvm.blocktag + 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:$succOperands, + DenseI32ArrayAttr:$indbr_operand_segments + ); + let successors = (successor VariadicSuccessor:$successors); + let assemblyFormat = [{ + $addr `:` type($addr) `,` + custom(ref(type($addr)), + $successors, + $succOperands, + type($succOperands)) + attr-dict + }]; + + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder<(ins "Value":$addr, + CArg<"ArrayRef", "{}">:$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 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 succOperands, + BlockRange successors) { + odsState.addOperands(addr); + for (ValueRange range : succOperands) + odsState.addOperands(range); + SmallVector rangeSegments; + for (ValueRange range : succOperands) + rangeSegments.push_back(range.size()); + odsState.getOrAddProperties().indbr_operand_segments = + odsBuilder.getDenseI32ArrayAttr(rangeSegments); + odsState.addSuccessors(successors); +} + +static ParseResult parseIndirectBrOpSucessors( + OpAsmParser &parser, Type &flagType, + SmallVectorImpl &succOperandBlocks, + SmallVectorImpl> &succOperands, + SmallVectorImpl> &succOperandsTypes) { + if (failed(parser.parseCommaSeparatedList( + OpAsmParser::Delimiter::Square, + [&]() { + Block *destination = nullptr; + SmallVector operands; + SmallVector 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(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(inst); + + FailureOr basePtr = convertValue(indBrInst->getAddress()); + if (failed(basePtr)) + return failure(); + + SmallVector succBlocks; + SmallVector> succBlockArgs; + for (auto i : llvm::seq(0, indBrInst->getNumSuccessors())) { + llvm::BasicBlock *succ = indBrInst->getSuccessor(i); + SmallVector blockArgs; + if (failed(convertBranchArgs(indBrInst, succ, blockArgs))) + return failure(); + succBlocks.push_back(lookupBlock(succ)); + succBlockArgs.push_back(blockArgs); + } + SmallVector succBlockArgsRange = + llvm::to_vector_of(succBlockArgs); + Location loc = translateLoc(inst->getDebugLoc()); + auto indBrOp = builder.create( + 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(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(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(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 > : !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 > : !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 + 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: -; 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() +@addr = global ptr null + +; CHECK-LABEL: llvm.func @test_indirectbr() { +define void @test_indirectbr() { + ; CHECK: %[[BA:.*]] = llvm.blockaddress > : !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 + ; 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 > : !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 + 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)