[flang-commits] [flang] e5064d7 - [flang] preserve representation of logical constants from TRANSFER (#192417)
via flang-commits
flang-commits at lists.llvm.org
Mon Apr 20 01:19:53 PDT 2026
Author: jeanPerier
Date: 2026-04-20T10:19:48+02:00
New Revision: e5064d7c6c7a1b9dcb9da1106980495f6f131bc2
URL: https://github.com/llvm/llvm-project/commit/e5064d7c6c7a1b9dcb9da1106980495f6f131bc2
DIFF: https://github.com/llvm/llvm-project/commit/e5064d7c6c7a1b9dcb9da1106980495f6f131bc2.diff
LOG: [flang] preserve representation of logical constants from TRANSFER (#192417)
This patch fixes the reproducer from
https://github.com/llvm/llvm-project/issues/192234.
Logical constant have canonical representation in flang (0 and 1, which
is compiler specific), but other values can be obtained via TRANSFER
from integer (in which case they are true if and only if different from
zero, which is a compiler specific interpretation).
While using TRANSFER to obtain logical is not recommended because it is
not portable, the standard at guarantee that round trips should preserve
the value.
This was not the case with constants because lowering was always
lowering logical constants to either 0 or 1 even when they are obtained
via TRANSFER. This patch fixes this by lowering non canonical logical
constants to an integer constant + bitcast. A folder is added to fold
converts to i1 of such bitcast so that usage of such TRANSFER in
branches for instance can still be optimized at the MLIR level.
Added:
flang/test/Lower/constant-logical-transfer.f90
Modified:
flang/lib/Lower/ConvertConstant.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/test/Fir/bitcast-fold.fir
Removed:
################################################################################
diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp
index f786673c606fc..0feb78e7fe9a1 100644
--- a/flang/lib/Lower/ConvertConstant.cpp
+++ b/flang/lib/Lower/ConvertConstant.cpp
@@ -63,7 +63,10 @@ static mlir::Attribute convertToAttribute(
{value.ToUInt64(), value.SHIFTR(64).ToUInt64()}));
}
} else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
- return builder.getIntegerAttr(type, value.IsTrue());
+ if (value.IsCanonical())
+ return builder.getIntegerAttr(type, value.IsTrue());
+ else
+ return builder.getIntegerAttr(type, value.word().ToInt64());
} else {
auto getFloatAttr = [&](const auto &value, mlir::Type type) {
std::string str = value.DumpHexadecimal();
@@ -262,7 +265,15 @@ static mlir::Value genScalarLit(
}
return builder.createIntegerConstant(loc, ty, value.ToInt64());
} else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
- return builder.createBool(loc, value.IsTrue());
+ if (value.IsCanonical())
+ return builder.createBool(loc, value.IsTrue());
+ mlir::Type logicalType = Fortran::lower::getFIRType(
+ builder.getContext(), Fortran::common::TypeCategory::Logical, KIND, {});
+ mlir::Type intType = Fortran::lower::getFIRType(
+ builder.getContext(), Fortran::common::TypeCategory::Integer, KIND, {});
+ mlir::Value integer =
+ builder.createIntegerConstant(loc, intType, value.word().ToInt64());
+ return fir::BitcastOp::create(builder, loc, logicalType, integer);
} else if constexpr (TC == Fortran::common::TypeCategory::Real) {
std::string str = value.DumpHexadecimal();
if constexpr (KIND == 2) {
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 405ada36a0037..4705033945611 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1694,6 +1694,12 @@ void fir::ConvertOp::getCanonicalizationPatterns(
context);
}
+static bool isI1(mlir::Type ty) {
+ if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(ty))
+ return intTy.getWidth() == 1;
+ return false;
+}
+
mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) {
if (getValue().getType() == getType())
return getValue();
@@ -1713,6 +1719,13 @@ mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) {
(fromTy.getWidth() == 1))
return inner.getValue();
}
+ // (convert (bitcast 'cst : int -> logical) : logical -> i1) ==> `'cst != 0`
+ if (isI1(getType()) &&
+ matchPattern(getValue(), mlir::m_Op<fir::BitcastOp>())) {
+ auto bitcast = mlir::cast<fir::BitcastOp>(getValue().getDefiningOp());
+ if (auto cst = fir::getIntIfConstant(bitcast.getValue()))
+ return mlir::IntegerAttr::get(getType(), cst != 0 ? 1 : 0);
+ }
return {};
}
diff --git a/flang/test/Fir/bitcast-fold.fir b/flang/test/Fir/bitcast-fold.fir
index 18b7a5e2e3daa..431230ec0d1e9 100644
--- a/flang/test/Fir/bitcast-fold.fir
+++ b/flang/test/Fir/bitcast-fold.fir
@@ -24,3 +24,23 @@ func.func @bitcast_chain_collapse(%x : i32) -> !fir.logical<4> {
// CHECK-NEXT: return %[[RES]]
return %1 : !fir.logical<4>
}
+
+func.func @bitcast_convert_fold_true() -> i1 {
+ %c3_i32 = arith.constant 3 : i32
+ %1 = fir.bitcast %c3_i32 : (i32) -> !fir.logical<4>
+ %2 = fir.convert %1 : (!fir.logical<4>) -> i1
+ return %2 : i1
+}
+// CHECK-LABEL: func.func @bitcast_convert_fold_true() -> i1 {
+// CHECK: %[[CONSTANT_0:.*]] = arith.constant true
+// CHECK: return %[[CONSTANT_0]] : i1
+
+func.func @bitcast_convert_fold_false() -> i1 {
+ %c0_i32 = arith.constant 0 : i32
+ %1 = fir.bitcast %c0_i32 : (i32) -> !fir.logical<4>
+ %2 = fir.convert %1 : (!fir.logical<4>) -> i1
+ return %2 : i1
+}
+// CHECK-LABEL: func.func @bitcast_convert_fold_false() -> i1 {
+// CHECK: %[[CONSTANT_0:.*]] = arith.constant false
+// CHECK: return %[[CONSTANT_0]] : i1
diff --git a/flang/test/Lower/constant-logical-transfer.f90 b/flang/test/Lower/constant-logical-transfer.f90
new file mode 100644
index 0000000000000..8f06de2086016
--- /dev/null
+++ b/flang/test/Lower/constant-logical-transfer.f90
@@ -0,0 +1,23 @@
+! Test lowering of non canonical LOGICAL constants.
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test_transfer_constant(l4, l8)
+ logical(4) :: l4
+ logical(8) :: l8
+ l4 = transfer(3, .true._4)
+ l8 = transfer(7, .true._8)
+end subroutine
+
+module constant_logical
+ logical(4) :: var(3) = [.true., transfer(3, .true._4), .false.]
+end module
+
+! CHECK-LABEL: func.func @_QPtest_transfer_constant(
+! CHECK: %[[CONSTANT_0:.*]] = arith.constant 3 : i32
+! CHECK: %[[BITCAST_0:.*]] = fir.bitcast %[[CONSTANT_0]] : (i32) -> !fir.logical<4>
+! CHECK: hlfir.assign %[[BITCAST_0]] to %{{.*}} : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+! CHECK: %[[CONSTANT_1:.*]] = arith.constant 7 : i64
+! CHECK: %[[BITCAST_1:.*]] = fir.bitcast %[[CONSTANT_1]] : (i64) -> !fir.logical<8>
+! CHECK: hlfir.assign %[[BITCAST_1]] to %{{.*}} : !fir.logical<8>, !fir.ref<!fir.logical<8>>
+
+! CHECK: fir.global @_QMconstant_logicalEvar(dense<[1, 3, 0]> : tensor<3xi32>) : !fir.array<3x!fir.logical<4>>
More information about the flang-commits
mailing list