[flang-commits] [flang] 5eb4272 - [flang][CodeGen] Replace fir.select* FIR-to-LLVM patterns with stubs that emit conversion errors (#212978)
via flang-commits
flang-commits at lists.llvm.org
Fri Jul 31 00:26:31 PDT 2026
Author: Kareem Ergawy
Date: 2026-07-31T09:26:26+02:00
New Revision: 5eb4272b04144bded2ca1819c2d93b1cd4f1a26b
URL: https://github.com/llvm/llvm-project/commit/5eb4272b04144bded2ca1819c2d93b1cd4f1a26b
DIFF: https://github.com/llvm/llvm-project/commit/5eb4272b04144bded2ca1819c2d93b1cd4f1a26b.diff
LOG: [flang][CodeGen] Replace fir.select* FIR-to-LLVM patterns with stubs that emit conversion errors (#212978)
`fir.select`, `fir.select_case`, `fir.select_rank`, and
`fir.select_type` are lowered to cf.* earlier in the pipeline
(`--fir-select-ops-conversion` and `--fir-polymorphic-op`). Their
FIR-to-LLVM conversion patterns are dead in a correct pipeline. Replace
them with a single templated stub
`SelectShouldHaveBeenConvertedStub<OP>` that emits `"'fir.<op>' op
should have already been converted"` and fails legalization, so running
`--fir-to-llvm-ir` standalone on stale IR reports a clear diagnostic
instead of "unable to legalize".
`Fir/convert-to-llvm.fir`'s six select* test blocks are removed (the
lowering no longer runs; CF-level coverage lives in
`Fir/SelectOpsConversion/`). `Fir/convert-to-llvm-invalid.fir` gains a
stub-error test per op. `Fir/Todo/select_case_with_character.fir` is
retargeted to check the equivalent diagnostic now emitted by
`--fir-select-ops-conversion`.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply at anthropic.com>
PR Stack:
* https://github.com/llvm/llvm-project/pull/212977
* ▶️ https://github.com/llvm/llvm-project/pull/212978
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply at anthropic.com>
Added:
Modified:
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/test/Fir/Todo/select_case_with_character.fir
flang/test/Fir/convert-to-llvm-invalid.fir
flang/test/Fir/convert-to-llvm.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 483f839e5b666..55c6afee45996 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -101,13 +101,6 @@ static inline mlir::Type getI8Type(mlir::MLIRContext *context) {
return mlir::IntegerType::get(context, 8);
}
-static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
- mlir::Block *insertBefore) {
- assert(insertBefore && "expected valid insertion block");
- return rewriter.createBlock(insertBefore->getParent(),
- mlir::Region::iterator(insertBefore));
-}
-
/// Extract constant from a value that must be the result of one of the
/// ConstantOp operations.
static int64_t getConstantIntValue(mlir::Value val) {
@@ -3972,272 +3965,32 @@ struct ModuleDebugImportsOpConversion
}
};
-static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
- std::optional<mlir::ValueRange> destOps,
- mlir::ConversionPatternRewriter &rewriter,
- mlir::Block *newBlock) {
- if (destOps)
- mlir::LLVM::CondBrOp::create(rewriter, loc, cmp, dest, *destOps, newBlock,
- mlir::ValueRange());
- else
- mlir::LLVM::CondBrOp::create(rewriter, loc, cmp, dest, newBlock);
-}
-
-template <typename A, typename B>
-static void genBrOp(A caseOp, mlir::Block *dest, std::optional<B> destOps,
- mlir::ConversionPatternRewriter &rewriter) {
- if (destOps)
- rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, *destOps, dest);
- else
- rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, B{}, dest);
-}
-
-static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
- mlir::Block *dest,
- std::optional<mlir::ValueRange> destOps,
- mlir::ConversionPatternRewriter &rewriter) {
- auto *thisBlock = rewriter.getInsertionBlock();
- auto *newBlock = createBlock(rewriter, dest);
- rewriter.setInsertionPointToEnd(thisBlock);
- genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
- rewriter.setInsertionPointToEnd(newBlock);
-}
-
-/// Conversion of `fir.select_case`
-///
-/// The `fir.select_case` operation is converted to a if-then-else ladder.
-/// Depending on the case condition type, one or several comparison and
-/// conditional branching can be generated.
-///
-/// A point value case such as `case(4)`, a lower bound case such as
-/// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
-/// simple comparison between the selector value and the constant value in the
-/// case. The block associated with the case condition is then executed if
-/// the comparison succeed otherwise it branch to the next block with the
-/// comparison for the next case conditon.
-///
-/// A closed interval case condition such as `case(7:10)` is converted with a
-/// first comparison and conditional branching for the lower bound. If
-/// successful, it branch to a second block with the comparison for the
-/// upper bound in the same case condition.
-///
-/// TODO: lowering of CHARACTER type cases is not handled yet.
-struct SelectCaseOpConversion : public fir::FIROpConversion<fir::SelectCaseOp> {
- using FIROpConversion::FIROpConversion;
-
- llvm::LogicalResult
- matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- unsigned conds = caseOp.getNumConditions();
- llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
- // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
- auto ty = caseOp.getSelector().getType();
- if (mlir::isa<fir::CharacterType>(ty)) {
- TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
- return mlir::failure();
- }
- mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
- auto loc = caseOp.getLoc();
- for (unsigned t = 0; t != conds; ++t) {
- mlir::Block *dest = caseOp.getSuccessor(t);
- std::optional<mlir::ValueRange> destOps =
- caseOp.getSuccessorOperands(adaptor.getOperands(), t);
- // Convert block signature if needed
- if (destOps && !destOps->empty())
- if (auto conversion = getTypeConverter()->convertBlockSignature(dest))
- dest = rewriter.applySignatureConversion(dest, *conversion,
- getTypeConverter());
- std::optional<mlir::ValueRange> cmpOps =
- *caseOp.getCompareOperands(adaptor.getOperands(), t);
- mlir::Attribute attr = cases[t];
- assert(mlir::isa<mlir::UnitAttr>(attr) || cmpOps.has_value());
- if (mlir::isa<fir::PointIntervalAttr>(attr)) {
- auto cmp = mlir::LLVM::ICmpOp::create(rewriter, loc,
- mlir::LLVM::ICmpPredicate::eq,
- selector, cmpOps->front());
- genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
- continue;
- }
- if (mlir::isa<fir::LowerBoundAttr>(attr)) {
- auto cmp = mlir::LLVM::ICmpOp::create(rewriter, loc,
- mlir::LLVM::ICmpPredicate::sle,
- cmpOps->front(), selector);
- genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
- continue;
- }
- if (mlir::isa<fir::UpperBoundAttr>(attr)) {
- auto cmp = mlir::LLVM::ICmpOp::create(rewriter, loc,
- mlir::LLVM::ICmpPredicate::sle,
- selector, cmpOps->front());
- genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
- continue;
- }
- if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
- mlir::Value caseArg0 = *cmpOps->begin();
- auto cmp0 = mlir::LLVM::ICmpOp::create(
- rewriter, loc, mlir::LLVM::ICmpPredicate::sle, caseArg0, selector);
- auto *thisBlock = rewriter.getInsertionBlock();
- auto *newBlock1 = createBlock(rewriter, dest);
- auto *newBlock2 = createBlock(rewriter, dest);
- rewriter.setInsertionPointToEnd(thisBlock);
- mlir::LLVM::CondBrOp::create(rewriter, loc, cmp0, newBlock1, newBlock2);
- rewriter.setInsertionPointToEnd(newBlock1);
- mlir::Value caseArg1 = *(cmpOps->begin() + 1);
- auto cmp1 = mlir::LLVM::ICmpOp::create(
- rewriter, loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg1);
- genCondBrOp(loc, cmp1, dest, destOps, rewriter, newBlock2);
- rewriter.setInsertionPointToEnd(newBlock2);
- continue;
- }
- assert(mlir::isa<mlir::UnitAttr>(attr));
- assert((t + 1 == conds) && "unit must be last");
- genBrOp(caseOp, dest, destOps, rewriter);
- }
- return mlir::success();
- }
-};
-
-/// Base class for SelectOpConversion and SelectRankOpConversion.
+/// Defensive stub. `fir.select`, `fir.select_case`, and `fir.select_rank` are
+/// lowered to `cf.switch` / `cf.cond_br` by `--fir-select-ops-conversion`
+/// earlier in the pipeline; `fir.select_type` is lowered to a cf-based
+/// if-then-else ladder by `--fir-polymorphic-op`. If any of these ops
+/// reaches FIR-to-LLVM, we emit a clear diagnostic rather than an opaque
+/// "unable to legalize" error.
template <typename OP>
-struct SelectOpConversionBase : public fir::FIROpConversion<OP> {
+struct SelectShouldHaveBeenConvertedStub : public fir::FIROpConversion<OP> {
using fir::FIROpConversion<OP>::FIROpConversion;
-private:
- /// Helper function for converting select ops. This function converts the
- /// signature of the given block. If the new block signature is
diff erent from
- /// `expectedTypes`, returns "failure".
- llvm::FailureOr<mlir::Block *>
- getConvertedBlock(mlir::ConversionPatternRewriter &rewriter,
- mlir::Operation *branchOp, mlir::Block *block,
- mlir::TypeRange expectedTypes) const {
- const mlir::TypeConverter *converter = this->getTypeConverter();
- assert(converter && "expected non-null type converter");
- assert(!block->isEntryBlock() && "entry blocks have no predecessors");
-
- // There is nothing to do if the types already match.
- if (block->getArgumentTypes() == expectedTypes)
- return block;
-
- // Compute the new block argument types and convert the block.
- std::optional<mlir::TypeConverter::SignatureConversion> conversion =
- converter->convertBlockSignature(block);
- if (!conversion)
- return rewriter.notifyMatchFailure(branchOp,
- "could not compute block signature");
- if (expectedTypes != conversion->getConvertedTypes())
- return rewriter.notifyMatchFailure(branchOp,
- "mismatch between adaptor operand "
- "types and computed block signature");
- return rewriter.applySignatureConversion(block, *conversion, converter);
- }
-
-protected:
- llvm::LogicalResult
- selectMatchAndRewrite(OP select, typename OP::Adaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- unsigned conds = select.getNumConditions();
- auto cases = select.getCases().getValue();
- mlir::Value selector = adaptor.getSelector();
- auto loc = select.getLoc();
- assert(conds > 0 && "select must have cases");
-
- llvm::SmallVector<mlir::Block *> destinations;
- llvm::SmallVector<mlir::ValueRange> destinationsOperands;
- mlir::Block *defaultDestination;
- mlir::ValueRange defaultOperands;
- // LLVM::SwitchOp selector type and the case values types
- // must have the same bit width, so cast the selector to i64,
- // and use i64 for the case values. It is hard to imagine
- // a computed GO TO with the number of labels in the label-list
- // bigger than INT_MAX, but let's use i64 to be on the safe side.
- // Moreover, fir.select operation is more relaxed than
- // a Fortran computed GO TO, so it may specify such a case value
- // even if there is just a single label/case.
- llvm::SmallVector<int64_t> caseValues;
-
- for (unsigned t = 0; t != conds; ++t) {
- mlir::Block *dest = select.getSuccessor(t);
- auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
- const mlir::Attribute &attr = cases[t];
- if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(attr)) {
- destinationsOperands.push_back(destOps ? *destOps : mlir::ValueRange{});
- auto convertedBlock =
- getConvertedBlock(rewriter, select, dest,
- mlir::TypeRange(destinationsOperands.back()));
- if (mlir::failed(convertedBlock))
- return mlir::failure();
- destinations.push_back(*convertedBlock);
- caseValues.push_back(intAttr.getInt());
- continue;
- }
- assert(mlir::dyn_cast_or_null<mlir::UnitAttr>(attr));
- assert((t + 1 == conds) && "unit must be last");
- defaultOperands = destOps ? *destOps : mlir::ValueRange{};
- auto convertedBlock = getConvertedBlock(rewriter, select, dest,
- mlir::TypeRange(defaultOperands));
- if (mlir::failed(convertedBlock))
- return mlir::failure();
- defaultDestination = *convertedBlock;
- }
-
- // Deal with the case where there is only a default destination. Handle it
- // now because emitting empty case values is not legal.
- if (caseValues.empty()) {
- rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(select, defaultOperands,
- defaultDestination);
- return mlir::success();
- }
-
- selector =
- this->integerCast(loc, rewriter, rewriter.getI64Type(), selector);
-
- rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
- select, selector,
- /*defaultDestination=*/defaultDestination,
- /*defaultOperands=*/defaultOperands,
- /*caseValues=*/rewriter.getI64VectorAttr(caseValues),
- /*caseDestinations=*/destinations,
- /*caseOperands=*/destinationsOperands,
- /*branchWeights=*/llvm::ArrayRef<std::int32_t>());
- return mlir::success();
- }
-};
-/// conversion of fir::SelectOp to an if-then-else ladder
-struct SelectOpConversion : public SelectOpConversionBase<fir::SelectOp> {
- using SelectOpConversionBase::SelectOpConversionBase;
-
- llvm::LogicalResult
- matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- return this->selectMatchAndRewrite(op, adaptor, rewriter);
- }
-};
-
-/// conversion of fir::SelectRankOp to an if-then-else ladder
-struct SelectRankOpConversion
- : public SelectOpConversionBase<fir::SelectRankOp> {
- using SelectOpConversionBase::SelectOpConversionBase;
-
- llvm::LogicalResult
- matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- return this->selectMatchAndRewrite(op, adaptor, rewriter);
- }
-};
-
-/// Lower `fir.select_type` to LLVM IR dialect.
-struct SelectTypeOpConversion : public fir::FIROpConversion<fir::SelectTypeOp> {
- using FIROpConversion::FIROpConversion;
-
- llvm::LogicalResult
- matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const override {
- mlir::emitError(select.getLoc(),
- "fir.select_type should have already been converted");
+ llvm::LogicalResult matchAndRewrite(
+ OP op, typename OP::Adaptor /*adaptor*/,
+ mlir::ConversionPatternRewriter & /*rewriter*/) const override {
+ op.emitOpError("should have already been converted");
return mlir::failure();
}
};
+using SelectOpConversion = SelectShouldHaveBeenConvertedStub<fir::SelectOp>;
+using SelectCaseOpConversion =
+ SelectShouldHaveBeenConvertedStub<fir::SelectCaseOp>;
+using SelectRankOpConversion =
+ SelectShouldHaveBeenConvertedStub<fir::SelectRankOp>;
+using SelectTypeOpConversion =
+ SelectShouldHaveBeenConvertedStub<fir::SelectTypeOp>;
+
/// `fir.store` --> `llvm.store`
struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
using FIROpConversion::FIROpConversion;
diff --git a/flang/test/Fir/Todo/select_case_with_character.fir b/flang/test/Fir/Todo/select_case_with_character.fir
index bddcb1e18a1b3..9d3231e74df7a 100644
--- a/flang/test/Fir/Todo/select_case_with_character.fir
+++ b/flang/test/Fir/Todo/select_case_with_character.fir
@@ -1,4 +1,4 @@
-// RUN: %not_todo_cmd fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s 2>&1 | FileCheck %s
+// RUN: %not_todo_cmd fir-opt --fir-select-ops-conversion %s 2>&1 | FileCheck %s
// Test `fir.select_case` conversion to llvm with character type.
// Not implemented yet.
diff --git a/flang/test/Fir/convert-to-llvm-invalid.fir b/flang/test/Fir/convert-to-llvm-invalid.fir
index b0c66e283bf5a..c7249eed0b4b3 100644
--- a/flang/test/Fir/convert-to-llvm-invalid.fir
+++ b/flang/test/Fir/convert-to-llvm-invalid.fir
@@ -27,13 +27,50 @@ func.func @shift_not_dead(%arg0: !fir.box<!fir.array<?xf32>>, %i: index) {
// -----
-// Test `fir.select_type` conversion to llvm.
-// Should have been converted.
+// The four fir.select* terminators are lowered to cf.* earlier in the
+// pipeline (--fir-select-ops-conversion for select/select_case/select_rank,
+// --fir-polymorphic-op for select_type). Any that reach FIR-to-LLVM hit a
+// defensive stub that emits a clear "should have already been converted"
+// diagnostic.
-func.func @bar_select_type(%arg : !fir.class<!fir.type<derivedst{a:f32}>>) -> i32 {
+func.func @select_should_have_been_converted(%arg: i32) -> i32 {
+ %0 = arith.constant 1 : i32
+ // expected-error at +2{{'fir.select' op should have already been converted}}
+ // expected-error at +1{{failed to legalize operation 'fir.select'}}
+ fir.select %arg : i32 [1, ^bb1(%0:i32), unit, ^bb1(%0:i32)]
+^bb1(%a: i32):
+ return %a : i32
+}
+
+// -----
+
+func.func @select_case_should_have_been_converted(%arg: !fir.ref<i32>) -> i32 {
+ %v = fir.load %arg : !fir.ref<i32>
+ %c1 = arith.constant 1 : i32
+ // expected-error at +2{{'fir.select_case' op should have already been converted}}
+ // expected-error at +1{{failed to legalize operation 'fir.select_case'}}
+ fir.select_case %v : i32 [#fir.point, %c1, ^bb1, unit, ^bb1]
+^bb1:
+ return %v : i32
+}
+
+// -----
+
+func.func @select_rank_should_have_been_converted(%arg: i32) -> i32 {
+ %0 = arith.constant 1 : i32
+ // expected-error at +2{{'fir.select_rank' op should have already been converted}}
+ // expected-error at +1{{failed to legalize operation 'fir.select_rank'}}
+ fir.select_rank %arg : i32 [1, ^bb1(%0:i32), unit, ^bb1(%0:i32)]
+^bb1(%a: i32):
+ return %a : i32
+}
+
+// -----
+
+func.func @select_type_should_have_been_converted(%arg: !fir.class<!fir.type<derivedst{a:f32}>>) -> i32 {
%0 = arith.constant 1 : i32
%2 = arith.constant 3 : i32
- // expected-error at +2{{fir.select_type should have already been converted}}
+ // expected-error at +2{{'fir.select_type' op should have already been converted}}
// expected-error at +1{{failed to legalize operation 'fir.select_type'}}
fir.select_type %arg : !fir.class<!fir.type<derivedst{a:f32}>> [
#fir.type_is<!fir.int<4>>,^bb1(%0:i32),
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 8d67b43ffd338..6af50b963130e 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -326,98 +326,6 @@ func.func @test_unreachable() {
// -----
-// Test `fir.select` operation conversion pattern.
-// Check that the if-then-else ladder is correctly constructed and that we
-// branch to the correct block.
-
-func.func @select(%arg : index, %arg2 : i32) -> i32 {
- %0 = arith.constant 1 : i32
- %1 = arith.constant 2 : i32
- %2 = arith.constant 3 : i32
- %3 = arith.constant 4 : i32
- fir.select %arg:index [ 1, ^bb1(%0:i32),
- 2, ^bb2(%2,%arg,%arg2:i32,index,i32),
- 3, ^bb3(%arg2,%2:i32,i32),
- 4, ^bb4(%1:i32),
- unit, ^bb5 ]
- ^bb1(%a : i32) :
- return %a : i32
- ^bb2(%b : i32, %b2 : index, %b3:i32) :
- %castidx = arith.index_cast %b2 : index to i32
- %4 = arith.addi %b, %castidx : i32
- %5 = arith.addi %4, %b3 : i32
- return %5 : i32
- ^bb3(%c:i32, %c2:i32) :
- %6 = arith.addi %c, %c2 : i32
- return %6 : i32
- ^bb4(%d : i32) :
- return %d : i32
- ^bb5 :
- %zero = arith.constant 0 : i32
- return %zero : i32
-}
-
-// CHECK-LABEL: func @select(
-// CHECK-SAME: %[[SELECTVALUE:.*]]: [[IDX:.*]],
-// CHECK-SAME: %[[ARG1:.*]]: i32)
-// CHECK: %[[C0:.*]] = llvm.mlir.constant(1 : i32) : i32
-// CHECK: %[[C1:.*]] = llvm.mlir.constant(2 : i32) : i32
-// CHECK: %[[C2:.*]] = llvm.mlir.constant(3 : i32) : i32
-// CHECK: llvm.switch %[[SELECTVALUE]] : i64, ^bb5 [
-// CHECK: 1: ^bb1(%[[C0]] : i32),
-// CHECK: 2: ^bb2(%[[C2]], %[[SELECTVALUE]], %[[ARG1]] : i32, [[IDX]], i32),
-// CHECK: 3: ^bb3(%[[ARG1]], %[[C2]] : i32, i32),
-// CHECK: 4: ^bb4(%[[C1]] : i32)
-// CHECK: ]
-
-// -----
-
-// Test `fir.select_rank` operation conversion pattern.
-// Check that the if-then-else ladder is correctly constructed and that we
-// branch to the correct block.
-
-func.func @select_rank(%arg : i32, %arg2 : i32) -> i32 {
- %0 = arith.constant 1 : i32
- %1 = arith.constant 2 : i32
- %2 = arith.constant 3 : i32
- %3 = arith.constant 4 : i32
- fir.select_rank %arg:i32 [ 1, ^bb1(%0:i32),
- 2, ^bb2(%2,%arg,%arg2:i32,i32,i32),
- 3, ^bb3(%arg2,%2:i32,i32),
- 4, ^bb4(%1:i32),
- unit, ^bb5 ]
- ^bb1(%a : i32) :
- return %a : i32
- ^bb2(%b : i32, %b2 : i32, %b3:i32) :
- %4 = arith.addi %b, %b2 : i32
- %5 = arith.addi %4, %b3 : i32
- return %5 : i32
- ^bb3(%c:i32, %c2:i32) :
- %6 = arith.addi %c, %c2 : i32
- return %6 : i32
- ^bb4(%d : i32) :
- return %d : i32
- ^bb5 :
- %zero = arith.constant 0 : i32
- return %zero : i32
-}
-
-// CHECK-LABEL: func @select_rank(
-// CHECK-SAME: %[[SELECTVALUE:.*]]: i32,
-// CHECK-SAME: %[[ARG1:.*]]: i32)
-// CHECK: %[[C0:.*]] = llvm.mlir.constant(1 : i32) : i32
-// CHECK: %[[C1:.*]] = llvm.mlir.constant(2 : i32) : i32
-// CHECK: %[[C2:.*]] = llvm.mlir.constant(3 : i32) : i32
-// CHECK: %[[SELECTOR:.*]] = llvm.sext %[[SELECTVALUE]] : i{{.*}} to i64
-// CHECK: llvm.switch %[[SELECTOR]] : i64, ^bb5 [
-// CHECK: 1: ^bb1(%[[C0]] : i32),
-// CHECK: 2: ^bb2(%[[C2]], %[[SELECTVALUE]], %[[ARG1]] : i32, i32, i32),
-// CHECK: 3: ^bb3(%[[ARG1]], %[[C2]] : i32, i32),
-// CHECK: 4: ^bb4(%[[C1]] : i32)
-// CHECK: ]
-
-// -----
-
// Test fir.extract_value operation conversion with derived type.
func.func @extract_derived_type() -> f32 {
@@ -1366,159 +1274,6 @@ func.func @alloca_assumed_rank_box() -> !fir.ref<!fir.box<!fir.array<*:f32>>> {
// -----
-// Test `fir.select_case` operation conversion with INTEGER.
-
-func.func @select_case_integer(%arg0: !fir.ref<i32>) -> i32 {
- %2 = fir.load %arg0 : !fir.ref<i32>
- %c1_i32 = arith.constant 1 : i32
- %c2_i32 = arith.constant 2 : i32
- %c4_i32 = arith.constant 4 : i32
- %c5_i32 = arith.constant 5 : i32
- %c7_i32 = arith.constant 7 : i32
- %c8_i32 = arith.constant 8 : i32
- %c15_i32 = arith.constant 15 : i32
- %c21_i32 = arith.constant 21 : i32
- fir.select_case %2 : i32 [#fir.upper, %c1_i32, ^bb1,
- #fir.point, %c2_i32, ^bb2,
- #fir.interval, %c4_i32, %c5_i32, ^bb4,
- #fir.point, %c7_i32, ^bb5,
- #fir.interval, %c8_i32, %c15_i32, ^bb5,
- #fir.lower, %c21_i32, ^bb5,
- unit, ^bb3]
-^bb1: // pred: ^bb0
- %c1_i32_0 = arith.constant 1 : i32
- fir.store %c1_i32_0 to %arg0 : !fir.ref<i32>
- cf.br ^bb6
-^bb2: // pred: ^bb0
- %c2_i32_1 = arith.constant 2 : i32
- fir.store %c2_i32_1 to %arg0 : !fir.ref<i32>
- cf.br ^bb6
-^bb3: // pred: ^bb0
- %c0_i32 = arith.constant 0 : i32
- fir.store %c0_i32 to %arg0 : !fir.ref<i32>
- cf.br ^bb6
-^bb4: // pred: ^bb0
- %c4_i32_2 = arith.constant 4 : i32
- fir.store %c4_i32_2 to %arg0 : !fir.ref<i32>
- cf.br ^bb6
-^bb5: // 3 preds: ^bb0, ^bb0, ^bb0
- %c7_i32_3 = arith.constant 7 : i32
- fir.store %c7_i32_3 to %arg0 : !fir.ref<i32>
- cf.br ^bb6
-^bb6: // 5 preds: ^bb1, ^bb2, ^bb3, ^bb4, ^bb5
- %3 = fir.load %arg0 : !fir.ref<i32>
- return %3 : i32
-}
-
-// CHECK-LABEL: llvm.func @select_case_integer(
-// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr) -> i32 {
-// CHECK: %[[SELECT_VALUE:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
-// CHECK: %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
-// CHECK: %[[CST2:.*]] = llvm.mlir.constant(2 : i32) : i32
-// CHECK: %[[CST4:.*]] = llvm.mlir.constant(4 : i32) : i32
-// CHECK: %[[CST5:.*]] = llvm.mlir.constant(5 : i32) : i32
-// CHECK: %[[CST7:.*]] = llvm.mlir.constant(7 : i32) : i32
-// CHECK: %[[CST8:.*]] = llvm.mlir.constant(8 : i32) : i32
-// CHECK: %[[CST15:.*]] = llvm.mlir.constant(15 : i32) : i32
-// CHECK: %[[CST21:.*]] = llvm.mlir.constant(21 : i32) : i32
-// Check for upper bound `case (:1)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[SELECT_VALUE]], %[[CST1]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb2, ^bb1
-// CHECK-LABEL: ^bb1:
-// Check for point value `case (2)`
-// CHECK: %[[CMP_EQ:.*]] = llvm.icmp "eq" %[[SELECT_VALUE]], %[[CST2]] : i32
-// CHECK: llvm.cond_br %[[CMP_EQ]], ^bb4, ^bb3
-// Block ^bb1 in original FIR code.
-// CHECK-LABEL: ^bb2:
-// CHECK: llvm.br ^bb{{.*}}
-// CHECK-LABEL: ^bb3:
-// Check for the lower bound for the interval `case (4:5)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[CST4]], %[[SELECT_VALUE]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb[[UPPERBOUND5:.*]], ^bb7
-// Block ^bb2 in original FIR code.
-// CHECK-LABEL: ^bb4:
-// CHECK: llvm.br ^bb{{.*}}
-// Block ^bb3 in original FIR code.
-// CHECK-LABEL: ^bb5:
-// CHECK: llvm.br ^bb{{.*}}
-// CHECK: ^bb[[UPPERBOUND5]]:
-// Check for the upper bound for the interval `case (4:5)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[SELECT_VALUE]], %[[CST5]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb8, ^bb7
-// CHECK-LABEL: ^bb7:
-// Check for the point value 7 in `case (7,8:15,21:)`
-// CHECK: %[[CMP_EQ:.*]] = llvm.icmp "eq" %[[SELECT_VALUE]], %[[CST7]] : i32
-// CHECK: llvm.cond_br %[[CMP_EQ]], ^bb13, ^bb9
-// Block ^bb4 in original FIR code.
-// CHECK-LABEL: ^bb8:
-// CHECK: llvm.br ^bb{{.*}}
-// CHECK-LABEL: ^bb9:
-// Check for lower bound 8 in `case (7,8:15,21:)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[CST8]], %[[SELECT_VALUE]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb[[INTERVAL8_15:.*]], ^bb11
-// CHECK: ^bb[[INTERVAL8_15]]:
-// Check for upper bound 15 in `case (7,8:15,21:)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[SELECT_VALUE]], %[[CST15]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb13, ^bb11
-// CHECK-LABEL: ^bb11:
-// Check for lower bound 21 in `case (7,8:15,21:)`
-// CHECK: %[[CMP_SLE:.*]] = llvm.icmp "sle" %[[CST21]], %[[SELECT_VALUE]] : i32
-// CHECK: llvm.cond_br %[[CMP_SLE]], ^bb13, ^bb12
-// CHECK-LABEL: ^bb12:
-// CHECK: llvm.br ^bb5
-// Block ^bb5 in original FIR code.
-// CHECK-LABEL: ^bb13:
-// CHECK: llvm.br ^bb14
-// Block ^bb6 in original FIR code.
-// CHECK-LABEL: ^bb14:
-// CHECK: %[[RET:.*]] = llvm.load %[[ARG0:.*]] : !llvm.ptr -> i32
-// CHECK: llvm.return %[[RET]] : i32
-
-// -----
-
-// Test `fir.select_case` operation conversion with LOGICAL.
-
-func.func @select_case_logical(%arg0: !fir.ref<!fir.logical<4>>) {
- %1 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
- %2 = fir.convert %1 : (!fir.logical<4>) -> i1
- %false = arith.constant false
- %true = arith.constant true
- fir.select_case %2 : i1 [#fir.point, %false, ^bb1,
- #fir.point, %true, ^bb2,
- unit, ^bb3]
-^bb1:
- %c1_i32 = arith.constant 1 : i32
- cf.br ^bb3
-^bb2:
- %c2_i32 = arith.constant 2 : i32
- cf.br ^bb3
-^bb3:
- return
-}
-
-// CHECK-LABEL: llvm.func @select_case_logical(
-// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr
-// CHECK: %[[LOAD_ARG0:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
-// CHECK: %[[CST_ZERO:.*]] = llvm.mlir.constant(0 : i32) : i32
-// CHECK: %[[SELECT_VALUE:.*]] = llvm.icmp "ne" %[[LOAD_ARG0]], %[[CST_ZERO]] : i32
-// CHECK: %[[CST_FALSE:.*]] = llvm.mlir.constant(false) : i1
-// CHECK: %[[CST_TRUE:.*]] = llvm.mlir.constant(true) : i1
-// CHECK: %[[CMPEQ:.*]] = llvm.icmp "eq" %[[SELECT_VALUE]], %[[CST_FALSE]] : i1
-// CHECK: llvm.cond_br %[[CMPEQ]], ^bb2, ^bb1
-// CHECK-LABEL: ^bb1:
-// CHECK: %[[CMPEQ:.*]] = llvm.icmp "eq" %[[SELECT_VALUE]], %[[CST_TRUE]] : i1
-// CHECK: llvm.cond_br %[[CMPEQ]], ^bb4, ^bb3
-// CHECK-LABEL: ^bb2:
-// CHECK: llvm.br ^bb5
-// CHECK-LABEL: ^bb3:
-// CHECK: llvm.br ^bb5
-// CHECK-LABEL: ^bb4:
-// CHECK: llvm.br ^bb5
-// CHECK-LABEL: ^bb5:
-// CHECK: llvm.return
-
-// -----
-
// Test `fir.is_present`
func.func @test_is_present_i64(%arg0: !fir.ref<i64>) -> () {
@@ -2929,72 +2684,6 @@ func.func @test_sret(%arg0: (!fir.ref<!fir.type<t{a:!fir.array<5xf64>}>>, f64) -
// -----
-func.func @select_with_cast(%arg1 : i8, %arg2 : i16, %arg3: i64, %arg4: index) -> () {
- fir.select %arg1 : i8 [ 1, ^bb1, unit, ^bb1 ]
- ^bb1:
- fir.select %arg2 : i16 [ 1, ^bb2, unit, ^bb2 ]
- ^bb2:
- fir.select %arg3 : i64 [ 1, ^bb3, unit, ^bb3 ]
- ^bb3:
- fir.select %arg4 : index [ 1, ^bb4, unit, ^bb4 ]
- ^bb4:
- fir.select %arg3 : i64 [ 4294967296, ^bb5, unit, ^bb5 ]
- ^bb5:
- return
-}
-// CHECK-LABEL: llvm.func @select_with_cast(
-// CHECK-SAME: %[[ARG0:.*]]: i8,
-// CHECK-SAME: %[[ARG1:.*]]: i16,
-// CHECK-SAME: %[[ARG2:.*]]: i64,
-// CHECK-SAME: %[[ARG3:.*]]: i64) {
-// CHECK: %[[VAL_0:.*]] = llvm.sext %[[ARG0]] : i8 to i64
-// CHECK: llvm.switch %[[VAL_0]] : i64, ^bb1 [
-// CHECK: 1: ^bb1
-// CHECK: ]
-// CHECK: ^bb1:
-// CHECK: %[[VAL_1:.*]] = llvm.sext %[[ARG1]] : i16 to i64
-// CHECK: llvm.switch %[[VAL_1]] : i64, ^bb2 [
-// CHECK: 1: ^bb2
-// CHECK: ]
-// CHECK: ^bb2:
-// CHECK: llvm.switch %[[ARG2]] : i64, ^bb3 [
-// CHECK: 1: ^bb3
-// CHECK: ]
-// CHECK: ^bb3:
-// CHECK: llvm.switch %[[ARG3]] : i64, ^bb4 [
-// CHECK: 1: ^bb4
-// CHECK: ]
-// CHECK: ^bb4:
-// CHECK: llvm.switch %[[ARG2]] : i64, ^bb5 [
-// CHECK: 4294967296: ^bb5
-// CHECK: ]
-// CHECK: ^bb5:
-// CHECK: llvm.return
-// CHECK: }
-
-// -----
-
-// Test `fir.select_case` with block arguments requiring type conversion.
-
-func.func @select_case_block_args(%arg0: !fir.ref<i32>, %arg1: !fir.ref<!fir.array<2xi32>>, %arg2: !fir.ref<!fir.array<2xi32>>) {
- %0 = fir.load %arg0 : !fir.ref<i32>
- %c1 = arith.constant 1 : i32
- %c2 = arith.constant 2 : i32
- fir.select_case %0 : i32 [#fir.point, %c1, ^bb1(%arg1 : !fir.ref<!fir.array<2xi32>>),
- #fir.point, %c2, ^bb1(%arg2 : !fir.ref<!fir.array<2xi32>>),
- unit, ^bb2]
-^bb1(%1: !fir.ref<!fir.array<2xi32>>):
- cf.br ^bb2
-^bb2:
- return
-}
-
-// CHECK-LABEL: llvm.func @select_case_block_args
-// CHECK: llvm.cond_br %{{.*}}, ^{{.*}}(%{{.*}} : !llvm.ptr), ^{{.*}}
-// CHECK: ^{{.*}}(%{{.*}}: !llvm.ptr):
-
-// -----
-
// Check memcpy alignment
func.func @test_load_box_alignment(%addr : !fir.ref<!fir.box<!fir.array<10xf32>>>) {
More information about the flang-commits
mailing list