[flang-commits] [flang] [flang] Implement lowering for BOZ literal arguments in BGE, BLE, BGT, BLT (PR #191874)

Caroline Newcombe via flang-commits flang-commits at lists.llvm.org
Mon Apr 13 12:00:31 PDT 2026


https://github.com/cenewcombe created https://github.com/llvm/llvm-project/pull/191874

BGE/BGT/BLE/BLT allow one or both arguments to be a BOZ literal constant. Unlike other intrinsics that accept BOZ arguments, these do not convert the BOZ to a typed value during semantic analysis.

When both arguments are constants, the comparison is folded at compile time in `fold-logical.cpp`. However, when the non-BOZ argument is a variable, folding is skipped and the BOZ literal constant persists in the expression tree through to lowering.

The lowering implementation wraps the `BOZLiteralConstant]` in a `Constant<LargestInt>` and feeds it through the existing `convertConstant` infrastructure. Since BOZ is always a scalar, this always produces a trivial SSA value. This follows the same pattern as `gen(Constant<T>)` for the trivial scalar path. The `AddrOfOp` branch from that template is intentionally omitted because a scalar i128 constant never produces a global reference. The `outlineBigConstantInReadOnlyMemory` parameter is set to false to make this intent explicit.

Tests:
- Added BOZ lowering tests to bge.f90, bgt.f90, ble.f90, blt.f90 covering BOZ in first position, second position
- Wider-than-companion BOZ (z'1FFFFFFFF' with i32 companion) lowering test added to bge.f90

Issue #190818 



>From bd54760d428258462cb385176023c9076c637780 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Mon, 30 Mar 2026 08:56:45 -0500
Subject: [PATCH] [flang] Implement lowering for BOZ literal arguments in BGE,
 BLE, BGT, BLT

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp | 12 +++++++-
 flang/test/Lower/Intrinsics/bge.f90    | 42 ++++++++++++++++++++++++++
 flang/test/Lower/Intrinsics/bgt.f90    | 28 +++++++++++++++++
 flang/test/Lower/Intrinsics/ble.f90    | 28 +++++++++++++++++
 flang/test/Lower/Intrinsics/blt.f90    | 28 +++++++++++++++++
 5 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 5ee409b031357..c3e3e493bac44 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1620,7 +1620,17 @@ class HlfirBuilder {
 private:
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::BOZLiteralConstant &expr) {
-    TODO(getLoc(), "BOZ");
+    // BOZ literals reach lowering only from BGE/BGT/BLE/BLT intrinsics when at
+    // least one operand is not constant (otherwise folds). For all other
+    // intrinsics, semantics converts BOZ to the expected type before lowering.
+    Fortran::evaluate::Constant<Fortran::evaluate::LargestInt> intConstant{expr};
+    mlir::Location loc{getLoc()};
+    fir::ExtendedValue exv{Fortran::lower::convertConstant(
+        getConverter(), loc, intConstant, /*outlineBigConstantInReadOnlyMemory=*/false)};
+    if (const auto *scalarBox{exv.getUnboxed()})
+      if (fir::isa_trivial(scalarBox->getType()))
+        return hlfir::EntityWithAttributes(*scalarBox);
+    fir::emitFatalError(loc, "BOZ literal was lowered to unexpected format");
   }
 
   hlfir::EntityWithAttributes gen(const Fortran::evaluate::NullPointer &expr) {
diff --git a/flang/test/Lower/Intrinsics/bge.f90 b/flang/test/Lower/Intrinsics/bge.f90
index f4d05e38f6991..5daab71322525 100644
--- a/flang/test/Lower/Intrinsics/bge.f90
+++ b/flang/test/Lower/Intrinsics/bge.f90
@@ -197,3 +197,45 @@ subroutine bge_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: hlfir.assign %[[V]] to %[[C_DECL]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
 end subroutine bge_test11
+
+! Test BOZ literal as second argument
+! CHECK-LABEL: func.func @_QPbge_boz_second(
+subroutine bge_boz_second(a, c)
+  integer :: a
+  logical :: c
+  c = bge(a, z'FF')
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi uge, %[[EXT]], %[[BOZ]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine bge_boz_second
+
+! Test BOZ literal as first argument
+! CHECK-LABEL: func.func @_QPbge_boz_first(
+subroutine bge_boz_first(a, c)
+  integer :: a
+  logical :: c
+  c = bge(z'FF', a)
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi uge, %[[BOZ]], %[[EXT]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine bge_boz_first
+
+! Test BOZ literal wider than companion integer type
+! CHECK-LABEL: func.func @_QPbge_boz_wide(
+subroutine bge_boz_wide(a, c)
+  integer :: a
+  logical :: c
+  c = bge(a, z'1FFFFFFFF')
+  ! CHECK: %[[BOZ:.*]] = arith.constant 8589934591 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi uge, %[[EXT]], %[[BOZ]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine bge_boz_wide
diff --git a/flang/test/Lower/Intrinsics/bgt.f90 b/flang/test/Lower/Intrinsics/bgt.f90
index 95a4a875de03e..068b73956028b 100644
--- a/flang/test/Lower/Intrinsics/bgt.f90
+++ b/flang/test/Lower/Intrinsics/bgt.f90
@@ -197,3 +197,31 @@ subroutine bgt_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: hlfir.assign %[[V]] to %[[C_DECL]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
 end subroutine bgt_test11
+
+! Test BOZ literal as second argument
+! CHECK-LABEL: func.func @_QPbgt_boz_second(
+subroutine bgt_boz_second(a, c)
+  integer :: a
+  logical :: c
+  c = bgt(a, z'FF')
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ugt, %[[EXT]], %[[BOZ]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine bgt_boz_second
+
+! Test BOZ literal as first argument
+! CHECK-LABEL: func.func @_QPbgt_boz_first(
+subroutine bgt_boz_first(a, c)
+  integer :: a
+  logical :: c
+  c = bgt(z'FF', a)
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ugt, %[[BOZ]], %[[EXT]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine bgt_boz_first
diff --git a/flang/test/Lower/Intrinsics/ble.f90 b/flang/test/Lower/Intrinsics/ble.f90
index 4605227710358..f54aa56b30805 100644
--- a/flang/test/Lower/Intrinsics/ble.f90
+++ b/flang/test/Lower/Intrinsics/ble.f90
@@ -197,3 +197,31 @@ subroutine ble_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: hlfir.assign %[[V]] to %[[C_DECL]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
 end subroutine ble_test11
+
+! Test BOZ literal as second argument
+! CHECK-LABEL: func.func @_QPble_boz_second(
+subroutine ble_boz_second(a, c)
+  integer :: a
+  logical :: c
+  c = ble(a, z'FF')
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ule, %[[EXT]], %[[BOZ]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine ble_boz_second
+
+! Test BOZ literal as first argument
+! CHECK-LABEL: func.func @_QPble_boz_first(
+subroutine ble_boz_first(a, c)
+  integer :: a
+  logical :: c
+  c = ble(z'FF', a)
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ule, %[[BOZ]], %[[EXT]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine ble_boz_first
diff --git a/flang/test/Lower/Intrinsics/blt.f90 b/flang/test/Lower/Intrinsics/blt.f90
index 89e743c64a081..b7e14800a62c0 100644
--- a/flang/test/Lower/Intrinsics/blt.f90
+++ b/flang/test/Lower/Intrinsics/blt.f90
@@ -197,3 +197,31 @@ subroutine blt_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: hlfir.assign %[[V]] to %[[C_DECL]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
 end subroutine blt_test11
+
+! Test BOZ literal as second argument
+! CHECK-LABEL: func.func @_QPblt_boz_second(
+subroutine blt_boz_second(a, c)
+  integer :: a
+  logical :: c
+  c = blt(a, z'FF')
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ult, %[[EXT]], %[[BOZ]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine blt_boz_second
+
+! Test BOZ literal as first argument
+! CHECK-LABEL: func.func @_QPblt_boz_first(
+subroutine blt_boz_first(a, c)
+  integer :: a
+  logical :: c
+  c = blt(z'FF', a)
+  ! CHECK: %[[BOZ:.*]] = arith.constant 255 : i128
+  ! CHECK: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+  ! CHECK: %[[EXT:.*]] = arith.extui %[[A]] : i32 to i128
+  ! CHECK: %[[CMP:.*]] = arith.cmpi ult, %[[BOZ]], %[[EXT]] : i128
+  ! CHECK: %[[RES:.*]] = fir.convert %[[CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: hlfir.assign %[[RES]] to %{{.*}}
+end subroutine blt_boz_first



More information about the flang-commits mailing list