[flang-commits] [flang] d0ddae6 - [flang] Fix segfault in CSHIFT/EOSHIFT with dynamically optional DIM (#184431)

via flang-commits flang-commits at lists.llvm.org
Sun Mar 8 22:24:29 PDT 2026


Author: Sairudra More
Date: 2026-03-09T10:54:25+05:30
New Revision: d0ddae678e3f634c988542dfbdde1dd0afe66344

URL: https://github.com/llvm/llvm-project/commit/d0ddae678e3f634c988542dfbdde1dd0afe66344
DIFF: https://github.com/llvm/llvm-project/commit/d0ddae678e3f634c988542dfbdde1dd0afe66344.diff

LOG: [flang] Fix segfault in CSHIFT/EOSHIFT with dynamically optional DIM (#184431)

When `DIM` is passed as an optional dummy argument and is absent at
runtime, the HLFIR lowering for the `CSHIFT` and `EOSHIFT` intrinsics
treated it as unconditionally present. This resulted in an unconditional
load of the `DIM` reference, causing a null pointer dereference and a
runtime segmentation fault when absent.

The underlying issue was that the `dim` argument for `cshift` and
`eoshift` was not marked with `handleDynamicOptional` during intrinsic
argument lowering setup. As a result, the `isPresent` state was never
populated, and the lowering implementation incorrectly fell through to
an unconditional scalar load.

This patch resolves the issue by:
1. Updating the `dim` entries for `cshift` and `eoshift` in
`IntrinsicCall.cpp` to use `handleDynamicOptional`. This enables
`getOperandVector()` to appropriately emit a guarded load (via
`loadOptionalValue()`) that safely returns a 0 placeholder when `DIM` is
absent.
2. Updating the HLFIR lowering implementations (`HlfirCShiftLowering`
and `HlfirEOShiftLowering`) to use the loaded scalar. It now employs an
`arith.select` to substitute the 0 placeholder with the
standard-mandated default of 1 when `isPresent` is false, matching the
Fortran requirements (§16.9.68 and §16.9.77) without generating
redundant `fir.if` or `fir.load` operations. Explicit `DIM=0` calls
still correctly forward the 0 value to flang-rt to trigger the
appropriate runtime bounds check error.

Co-authored-by: Sairudra More <moresair at pe31.hpc.amslabs.hpecorp.net>

Added: 
    flang/test/Lower/HLFIR/cshift-optional-dim.f90

Modified: 
    flang/lib/Lower/HlfirIntrinsics.cpp
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index f63628d7824ff..9ee30e52af697 100644
--- a/flang/lib/Lower/HlfirIntrinsics.cpp
+++ b/flang/lib/Lower/HlfirIntrinsics.cpp
@@ -489,6 +489,14 @@ mlir::Value HlfirCShiftLowering::lowerImpl(
   if (!dim) {
     // If DIM is not present, drop the last element which is a null Value.
     operands.truncate(2);
+  } else if (loweredActuals[2] && loweredActuals[2]->handleDynamicOptional()) {
+    // Use getIsPresent() to select between a present DIM value or
+    // the default 1 per Fortran 16.9.68.
+    mlir::Value isPresent = loweredActuals[2]->getIsPresent();
+    mlir::Type dimType = dim.getType();
+    mlir::Value one = builder.createIntegerConstant(loc, dimType, 1);
+    dim = mlir::arith::SelectOp::create(builder, loc, isPresent, dim, one);
+    operands[2] = dim;
   } else {
     // If DIM is present, then dereference it if it is a ref.
     dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});
@@ -509,9 +517,17 @@ mlir::Value HlfirEOShiftLowering::lowerImpl(
   mlir::Value shift = operands[1];
   mlir::Value boundary = operands[2];
   mlir::Value dim = operands[3];
-  // If DIM is present, then dereference it if it is a ref.
-  if (dim)
+  if (loweredActuals[3] && loweredActuals[3]->handleDynamicOptional()) {
+    // Use getIsPresent() to select between a present DIM value or
+    // the default 1 per Fortran 16.9.77.
+    mlir::Value isPresent = loweredActuals[3]->getIsPresent();
+    mlir::Type dimType = dim.getType();
+    mlir::Value one = builder.createIntegerConstant(loc, dimType, 1);
+    dim = mlir::arith::SelectOp::create(builder, loc, isPresent, dim, one);
+  } else if (dim) {
+    // If DIM is statically present, dereference it if it is a ref.
     dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});
+  }
 
   mlir::Type resultType = computeResultType(array, stmtResultType);
 

diff  --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 9036d65f138d3..d67eebdd8c93c 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -254,7 +254,9 @@ static constexpr IntrinsicHandler handlers[]{
      /*isElemental=*/false},
     {"cshift",
      &I::genCshift,
-     {{{"array", asAddr}, {"shift", asAddr}, {"dim", asValue}}},
+     {{{"array", asAddr},
+       {"shift", asAddr},
+       {"dim", asValue, handleDynamicOptional}}},
      /*isElemental=*/false},
     {"date_and_time",
      &I::genDateAndTime,
@@ -281,7 +283,7 @@ static constexpr IntrinsicHandler handlers[]{
      {{{"array", asBox},
        {"shift", asAddr},
        {"boundary", asBox, handleDynamicOptional},
-       {"dim", asValue}}},
+       {"dim", asValue, handleDynamicOptional}}},
      /*isElemental=*/false},
     {"erfc_scaled", &I::genErfcScaled},
     {"etime",

diff  --git a/flang/test/Lower/HLFIR/cshift-optional-dim.f90 b/flang/test/Lower/HLFIR/cshift-optional-dim.f90
new file mode 100644
index 0000000000000..8f72b40910359
--- /dev/null
+++ b/flang/test/Lower/HLFIR/cshift-optional-dim.f90
@@ -0,0 +1,50 @@
+! Test lowering of CSHIFT/EOSHIFT with a dynamically optional DIM argument.
+! When DIM is an optional dummy argument that is absent at runtime, it must
+! default to 1 (Fortran standard 16.9.68, 16.9.77). Prior to the fix, the
+! absent case caused a segmentation fault because the optional reference was
+! unconditionally dereferenced without checking for presence.
+! RUN: bbc -emit-hlfir -o - -I nowhere %s 2>&1 | FileCheck %s
+
+! CSHIFT 2D with optional DIM - DIM may be absent at runtime (defaults to 1).
+subroutine cshift_optional_dim(a, sh, dim)
+  integer :: a(:,:), sh(:)
+  integer, optional :: dim
+  a = CSHIFT(a, sh, dim)
+end subroutine
+! CHECK-LABEL: func.func @_QPcshift_optional_dim(
+! CHECK-SAME:    {{.*}}: !fir.ref<i32> {fir.bindc_name = "dim", fir.optional})
+! CHECK:         %[[DECL_DIM:.*]]:2 = hlfir.declare {{.*}} {fortran_attrs = #fir.var_attrs<optional>
+! CHECK:         %[[IS_PRESENT:.*]] = fir.is_present %[[DECL_DIM]]#0 : (!fir.ref<i32>) -> i1
+! CHECK:         %[[DIM_LOADED:.*]] = fir.if %[[IS_PRESENT]] -> (i32) {
+! CHECK:           %[[LOADED:.*]] = fir.load %[[DECL_DIM]]#0 : !fir.ref<i32>
+! CHECK:           fir.result %[[LOADED]] : i32
+! CHECK:         } else {
+! CHECK:           arith.constant 0 : i32
+! CHECK:           fir.result
+! CHECK:         }
+! CHECK:         %[[ONE:.*]] = arith.constant 1 : i32
+! CHECK:         %[[DIM_VAL:.*]] = arith.select %[[IS_PRESENT]], %[[DIM_LOADED]], %[[ONE]] : i32
+! CHECK-NOT:     arith.cmpi
+! CHECK:         hlfir.cshift {{.*}} dim %[[DIM_VAL]] :
+
+! EOSHIFT 2D with optional DIM - DIM may be absent at runtime (defaults to 1).
+subroutine eoshift_optional_dim(a, sh, dim)
+  integer :: a(:,:), sh(:)
+  integer, optional :: dim
+  a = EOSHIFT(a, sh, dim=dim)
+end subroutine
+! CHECK-LABEL: func.func @_QPeoshift_optional_dim(
+! CHECK-SAME:    {{.*}}: !fir.ref<i32> {fir.bindc_name = "dim", fir.optional})
+! CHECK:         %[[DECL_DIM2:.*]]:2 = hlfir.declare {{.*}} {fortran_attrs = #fir.var_attrs<optional>
+! CHECK:         %[[IS_PRESENT2:.*]] = fir.is_present %[[DECL_DIM2]]#0 : (!fir.ref<i32>) -> i1
+! CHECK:         %[[DIM_LOADED2:.*]] = fir.if %[[IS_PRESENT2]] -> (i32) {
+! CHECK:           %[[LOADED2:.*]] = fir.load %[[DECL_DIM2]]#0 : !fir.ref<i32>
+! CHECK:           fir.result %[[LOADED2]] : i32
+! CHECK:         } else {
+! CHECK:           arith.constant 0 : i32
+! CHECK:           fir.result
+! CHECK:         }
+! CHECK:         %[[ONE2:.*]] = arith.constant 1 : i32
+! CHECK:         %[[DIM_VAL2:.*]] = arith.select %[[IS_PRESENT2]], %[[DIM_LOADED2]], %[[ONE2]] : i32
+! CHECK-NOT:     arith.cmpi
+! CHECK:         hlfir.eoshift {{.*}} dim %[[DIM_VAL2]] :


        


More information about the flang-commits mailing list