[flang-commits] [flang] [flang] add nsw to operations in subscripts (PR #110060)

Yusuke MINATO via flang-commits flang-commits at lists.llvm.org
Wed Sep 25 17:18:49 PDT 2024


https://github.com/yus3710-fj created https://github.com/llvm/llvm-project/pull/110060

This patch adds nsw to operations when lowering subscripts.

See also the discussion in the following discourse post.
https://discourse.llvm.org/t/rfc-add-nsw-flags-to-arithmetic-integer-operations-using-the-option-fno-wrapv/77584/9

>From 11ce92bc5f738e134bf00048ed78cb942ea37c29 Mon Sep 17 00:00:00 2001
From: Yusuke MINATO <minato.yusuke at fujitsu.com>
Date: Tue, 3 Sep 2024 18:28:26 +0900
Subject: [PATCH] [flang] add nsw to operations in subscripts

This patch adds nsw to operations when lowering subscripts.

See also the discussion in the following discourse post.
https://discourse.llvm.org/t/rfc-add-nsw-flags-to-arithmetic-integer-operations-using-the-option-fno-wrapv/77584/9
---
 flang/docs/Extensions.md                      |   6 +
 flang/include/flang/Lower/LoweringOptions.def |   5 +
 .../flang/Optimizer/Builder/FIRBuilder.h      |  21 ++-
 flang/lib/Lower/ConvertCall.cpp               |  17 ++
 flang/lib/Lower/ConvertExpr.cpp               |  20 ++-
 flang/lib/Lower/ConvertExprToHLFIR.cpp        |  25 ++-
 flang/test/Lower/HLFIR/binary-ops.f90         |  27 +++
 .../Lower/HLFIR/vector-subscript-as-value.f90 |  40 +++++
 .../test/Lower/HLFIR/vector-subscript-lhs.f90 |  37 ++++
 flang/test/Lower/Intrinsics/bge.f90           |  17 ++
 flang/test/Lower/Intrinsics/bgt.f90           |  17 ++
 flang/test/Lower/Intrinsics/ble.f90           |  17 ++
 flang/test/Lower/Intrinsics/blt.f90           |  17 ++
 flang/test/Lower/array.f90                    | 162 ++++++++++++++++++
 flang/test/Lower/forall/array-pointer.f90     |  54 +++++-
 flang/tools/bbc/bbc.cpp                       |   7 +
 16 files changed, 481 insertions(+), 8 deletions(-)

diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index ed1ef49f8b77a5..3ffd2949e45bf4 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -780,6 +780,12 @@ character j
 print *, [(j,j=1,10)]
 ```
 
+* The Fortran standard doesn't mention integer overflow explicitly. In many cases,
+  however, integer overflow makes programs non-conforming.
+  F18 follows other widely-used Fortran compilers. Specifically, f18 assumes
+  integer overflow never occurs in address calculations and increment of
+  do-variable unless the option `-fwrapv` is enabled.
+
 ## De Facto Standard Features
 
 * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 7594a57a262914..1b24af5f97d1ee 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -34,8 +34,13 @@ ENUM_LOWERINGOPT(NoPPCNativeVecElemOrder, unsigned, 1, 0)
 /// On by default.
 ENUM_LOWERINGOPT(Underscoring, unsigned, 1, 1)
 
+/// If true, assume the behavior of integer overflow is defined
+/// (i.e. wraps around as two's complement). On by default.
+ENUM_LOWERINGOPT(IntegerWrapAround, unsigned, 1, 1)
+
 /// If true, add nsw flags to loop variable increments.
 /// Off by default.
+/// TODO: integrate this option with the above
 ENUM_LOWERINGOPT(NSWOnLoopVarInc, unsigned, 1, 0)
 
 #undef LOWERINGOPT
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 180e2c8ab33ea2..09f7b892f1ecbe 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -85,13 +85,16 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
   // The listener self-reference has to be updated in case of copy-construction.
   FirOpBuilder(const FirOpBuilder &other)
       : OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap},
-        fastMathFlags{other.fastMathFlags}, symbolTable{other.symbolTable} {
+        fastMathFlags{other.fastMathFlags},
+        integerOverflowFlags{other.integerOverflowFlags},
+        symbolTable{other.symbolTable} {
     setListener(this);
   }
 
   FirOpBuilder(FirOpBuilder &&other)
       : OpBuilder(other), OpBuilder::Listener(),
         kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags},
+        integerOverflowFlags{other.integerOverflowFlags},
         symbolTable{other.symbolTable} {
     setListener(this);
   }
@@ -521,6 +524,18 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
     return fmfString;
   }
 
+  /// Set default IntegerOverflowFlags value for all operations
+  /// supporting mlir::arith::IntegerOverflowFlagsAttr that will be created
+  /// by this builder.
+  void setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags flags) {
+    integerOverflowFlags = flags;
+  }
+
+  /// Get current IntegerOverflowFlags value.
+  mlir::arith::IntegerOverflowFlags getIntegerOverflowFlags() const {
+    return integerOverflowFlags;
+  }
+
   /// Dump the current function. (debug)
   LLVM_DUMP_METHOD void dumpFunc();
 
@@ -547,6 +562,10 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
   /// mlir::arith::FastMathAttr.
   mlir::arith::FastMathFlags fastMathFlags{};
 
+  /// IntegerOverflowFlags that need to be set for operations that support
+  /// mlir::arith::IntegerOverflowFlagsAttr.
+  mlir::arith::IntegerOverflowFlags integerOverflowFlags{};
+
   /// fir::GlobalOp and func::FuncOp symbol table to speed-up
   /// lookups.
   mlir::SymbolTable *symbolTable = nullptr;
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 017bfd049d3dc5..1ca265fe7f9870 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -2574,9 +2574,26 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
           hlfir::Entity{*var}, /*isPresent=*/std::nullopt});
       continue;
     }
+    // arguments of bitwise comparison functions may not have nsw flag
+    // even if -fno-wrapv is enabled
+    mlir::arith::IntegerOverflowFlags iofBackup{};
+    auto isBitwiseComparison = [](const std::string intrinsicName) -> bool {
+      if (intrinsicName == "bge" || intrinsicName == "bgt" ||
+          intrinsicName == "ble" || intrinsicName == "blt")
+        return true;
+      return false;
+    };
+    if (isBitwiseComparison(callContext.getProcedureName())) {
+      iofBackup = callContext.getBuilder().getIntegerOverflowFlags();
+      callContext.getBuilder().setIntegerOverflowFlags(
+          mlir::arith::IntegerOverflowFlags::none);
+    }
     auto loweredActual = Fortran::lower::convertExprToHLFIR(
         loc, callContext.converter, *expr, callContext.symMap,
         callContext.stmtCtx);
+    if (isBitwiseComparison(callContext.getProcedureName()))
+      callContext.getBuilder().setIntegerOverflowFlags(iofBackup);
+
     std::optional<mlir::Value> isPresent;
     if (argLowering) {
       fir::ArgLoweringRule argRules =
diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 62a7615e1af13c..dd8c43588b7018 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -1065,7 +1065,15 @@ class ScalarExprLowering {
     mlir::Value lhs = fir::getBase(left);
     mlir::Value rhs = fir::getBase(right);
     assert(lhs.getType() == rhs.getType() && "types must be the same");
-    return builder.create<OpTy>(getLoc(), lhs, rhs);
+    if constexpr (std::is_same_v<OpTy, mlir::arith::AddIOp> ||
+                  std::is_same_v<OpTy, mlir::arith::SubIOp> ||
+                  std::is_same_v<OpTy, mlir::arith::MulIOp>) {
+      auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
+          builder.getContext(), builder.getIntegerOverflowFlags());
+      return builder.create<OpTy>(getLoc(), lhs, rhs, iofAttr);
+    } else {
+      return builder.create<OpTy>(getLoc(), lhs, rhs);
+    }
   }
 
   template <typename OpTy, typename A>
@@ -1397,7 +1405,15 @@ class ScalarExprLowering {
     fir::emitFatalError(getLoc(), "subscript triple notation is not scalar");
   }
   ExtValue genSubscript(const Fortran::evaluate::Subscript &subs) {
-    return genval(subs);
+    mlir::arith::IntegerOverflowFlags iofBackup{};
+    if (!converter.getLoweringOptions().getIntegerWrapAround()) {
+      iofBackup = builder.getIntegerOverflowFlags();
+      builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw);
+    }
+    auto val = genval(subs);
+    if (!converter.getLoweringOptions().getIntegerWrapAround())
+      builder.setIntegerOverflowFlags(iofBackup);
+    return val;
   }
 
   ExtValue gen(const Fortran::evaluate::DataRef &dref) {
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 1933f38f735b57..5db3b08afb7490 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -968,8 +968,17 @@ struct BinaryOp {};
                                            fir::FirOpBuilder &builder,         \
                                            const Op &, hlfir::Entity lhs,      \
                                            hlfir::Entity rhs) {                \
-      return hlfir::EntityWithAttributes{                                      \
-          builder.create<GenBinFirOp>(loc, lhs, rhs)};                         \
+      if constexpr (std::is_same_v<GenBinFirOp, mlir::arith::AddIOp> ||        \
+                    std::is_same_v<GenBinFirOp, mlir::arith::SubIOp> ||        \
+                    std::is_same_v<GenBinFirOp, mlir::arith::MulIOp>) {        \
+        auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(             \
+            builder.getContext(), builder.getIntegerOverflowFlags());          \
+        return hlfir::EntityWithAttributes{                                    \
+            builder.create<GenBinFirOp>(loc, lhs, rhs, iofAttr)};              \
+      } else {                                                                 \
+        return hlfir::EntityWithAttributes{                                    \
+            builder.create<GenBinFirOp>(loc, lhs, rhs)};                       \
+      }                                                                        \
     }                                                                          \
   };
 
@@ -1584,9 +1593,12 @@ class HlfirBuilder {
       auto rightVal = hlfir::loadTrivialScalar(l, b, rightElement);
       return binaryOp.gen(l, b, op.derived(), leftVal, rightVal);
     };
+    auto iofBackup = builder.getIntegerOverflowFlags();
+    builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::none);
     mlir::Value elemental = hlfir::genElementalOp(loc, builder, elementType,
                                                   shape, typeParams, genKernel,
                                                   /*isUnordered=*/true);
+    builder.setIntegerOverflowFlags(iofBackup);
     fir::FirOpBuilder *bldr = &builder;
     getStmtCtx().attachCleanup(
         [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); });
@@ -1899,10 +1911,17 @@ class HlfirBuilder {
 template <typename T>
 hlfir::Entity
 HlfirDesignatorBuilder::genSubscript(const Fortran::evaluate::Expr<T> &expr) {
+  fir::FirOpBuilder &builder = getBuilder();
+  mlir::arith::IntegerOverflowFlags iofBackup{};
+  if (!getConverter().getLoweringOptions().getIntegerWrapAround()) {
+    iofBackup = builder.getIntegerOverflowFlags();
+    builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw);
+  }
   auto loweredExpr =
       HlfirBuilder(getLoc(), getConverter(), getSymMap(), getStmtCtx())
           .gen(expr);
-  fir::FirOpBuilder &builder = getBuilder();
+  if (!getConverter().getLoweringOptions().getIntegerWrapAround())
+    builder.setIntegerOverflowFlags(iofBackup);
   // Skip constant conversions that litters designators and makes generated
   // IR harder to read: directly use index constants for constant subscripts.
   mlir::Type idxTy = builder.getIndexType();
diff --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90
index 912cea0f5e0e66..20300cfce4aa5c 100644
--- a/flang/test/Lower/HLFIR/binary-ops.f90
+++ b/flang/test/Lower/HLFIR/binary-ops.f90
@@ -1,5 +1,6 @@
 ! Test lowering of binary intrinsic operations to HLFIR
 ! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
+! RUN: bbc -emit-hlfir -o - -fwrapv %s 2>&1 | FileCheck %s --check-prefix=NO-NSW
 
 subroutine int_add(x, y, z)
  integer :: x, y, z
@@ -209,6 +210,32 @@ subroutine extremum(c, n, l)
 ! CHECK:  %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64
 ! CHECK:  arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64
 
+subroutine subscript(a, i, j, k)
+  integer :: a(:,:,:), i, j, k
+  a(i+1, j-2, k*3) = 5
+end subroutine
+! CHECK-LABEL: func.func @_QPsubscript(
+! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}i"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}j"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:  %[[VAL_6:.*]]:2 = hlfir.declare %{{.*}}k"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
+! CHECK:  %[[VAL_8:.*]] = arith.addi %[[VAL_7]], %c1{{[^ ]*}} overflow<nsw> : i32
+! CHECK:  %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
+! CHECK:  %[[VAL_10:.*]] = arith.subi %[[VAL_9]], %c2{{[^ ]*}} overflow<nsw> : i32
+! CHECK:  %[[VAL_11:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<i32>
+! CHECK:  %[[VAL_12:.*]] = arith.muli %c3{{[^ ]*}}, %[[VAL_11]] overflow<nsw> : i32
+
+! NO-NSW-LABEL: func.func @_QPsubscript(
+! NO-NSW:  %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}i"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! NO-NSW:  %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}j"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! NO-NSW:  %[[VAL_6:.*]]:2 = hlfir.declare %{{.*}}k"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! NO-NSW:  %[[VAL_7:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
+! NO-NSW:  %[[VAL_8:.*]] = arith.addi %[[VAL_7]], %c1{{[^ ]*}} : i32
+! NO-NSW:  %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
+! NO-NSW:  %[[VAL_10:.*]] = arith.subi %[[VAL_9]], %c2{{[^ ]*}} : i32
+! NO-NSW:  %[[VAL_11:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<i32>
+! NO-NSW:  %[[VAL_12:.*]] = arith.muli %c3{{[^ ]*}}, %[[VAL_11]] : i32
+
 subroutine cmp_int(l, x, y)
   logical :: l
   integer :: x, y
diff --git a/flang/test/Lower/HLFIR/vector-subscript-as-value.f90 b/flang/test/Lower/HLFIR/vector-subscript-as-value.f90
index 7161ee088b57a4..850ace1a8d9dec 100644
--- a/flang/test/Lower/HLFIR/vector-subscript-as-value.f90
+++ b/flang/test/Lower/HLFIR/vector-subscript-as-value.f90
@@ -1,6 +1,7 @@
 ! Test lowering of vector subscript designators outside of the
 ! assignment left-and side and input IO context.
 ! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s
+! RUN: bbc -emit-hlfir -o - -I nw -fwrapv %s 2>&1 | FileCheck %s
 
 subroutine foo(x, y)
   integer :: x(100)
@@ -150,6 +151,45 @@ subroutine foo4(at1, vector, i, j, k, l, step)
 ! CHECK:    hlfir.yield_element %[[VAL_50]] : f32
 ! CHECK:  }
 
+subroutine foo5(x, y, z)
+  integer :: x(100)
+  integer(8) :: y(20), z(20)
+  call bar(x(y+z))
+end subroutine
+! CHECK-LABEL:   func.func @_QPfoo5(
+! CHECK:  %[[VAL_3:.*]] = arith.constant 100 : index
+! CHECK:  %[[VAL_4:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_0:[a-z0-9]*]](%[[VAL_4]])  {{.*}}Ex
+! CHECK:  %[[VAL_6:.*]] = arith.constant 20 : index
+! CHECK:  %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_1:[a-z0-9]*]](%[[VAL_7]])  {{.*}}Ey
+! CHECK:  %[[VAL_9:.*]] = arith.constant 20 : index
+! CHECK:  %[[VAL_10:.*]] = fir.shape %[[VAL_9]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_2:[a-z0-9]*]](%[[VAL_10]])  {{.*}}Ez
+! CHECK:  %[[VAL_12:.*]] = hlfir.elemental %[[VAL_7]] unordered : (!fir.shape<1>) -> !hlfir.expr<20xi64> {
+! CHECK:  ^bb0(%[[VAL_13:.*]]: index):
+! CHECK:    %[[VAL_14:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_13]])  : (!fir.ref<!fir.array<20xi64>>, index) -> !fir.ref<i64>
+! CHECK:    %[[VAL_15:.*]] = hlfir.designate %[[VAL_11]]#0 (%[[VAL_13]])  : (!fir.ref<!fir.array<20xi64>>, index) -> !fir.ref<i64>
+! CHECK:    %[[VAL_16:.*]] = fir.load %[[VAL_14]] : !fir.ref<i64>
+! CHECK:    %[[VAL_17:.*]] = fir.load %[[VAL_15]] : !fir.ref<i64>
+! CHECK:    %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i64
+! CHECK:    hlfir.yield_element %[[VAL_18]] : i64
+! CHECK:  }
+! CHECK:  %[[VAL_19:.*]] = arith.constant 20 : index
+! CHECK:  %[[VAL_20:.*]] = fir.shape %[[VAL_19]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_21:.*]] = hlfir.elemental %[[VAL_20]] unordered : (!fir.shape<1>) -> !hlfir.expr<20xi32> {
+! CHECK:  ^bb0(%[[VAL_22:.*]]: index):
+! CHECK:    %[[VAL_23:.*]] = hlfir.apply %[[VAL_12]], %[[VAL_22]] : (!hlfir.expr<20xi64>, index) -> i64
+! CHECK:    %[[VAL_24:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_23]])  : (!fir.ref<!fir.array<100xi32>>, i64) -> !fir.ref<i32>
+! CHECK:    %[[VAL_25:.*]] = fir.load %[[VAL_24]] : !fir.ref<i32>
+! CHECK:    hlfir.yield_element %[[VAL_25]] : i32
+! CHECK:  }
+! CHECK:  %[[VAL_26:.*]]:3 = hlfir.associate %[[VAL_21]](%[[VAL_20]]) {adapt.valuebyref} : (!hlfir.expr<20xi32>, !fir.shape<1>) -> (!fir.ref<!fir.array<20xi32>>, !fir.ref<!fir.array<20xi32>>, i1)
+! CHECK:  fir.call @_QPbar(%[[VAL_26]]#1) fastmath<contract> : (!fir.ref<!fir.array<20xi32>>) -> ()
+! CHECK:  hlfir.end_associate %[[VAL_26]]#1, %[[VAL_26]]#2 : !fir.ref<!fir.array<20xi32>>, i1
+! CHECK:  hlfir.destroy %[[VAL_21]] : !hlfir.expr<20xi32>
+! CHECK:  hlfir.destroy %[[VAL_12]] : !hlfir.expr<20xi64>
+
 subroutine substring(c, vector, i, j)
   character(*) :: c(:)
   integer(8) :: vector(:), step, i, j
diff --git a/flang/test/Lower/HLFIR/vector-subscript-lhs.f90 b/flang/test/Lower/HLFIR/vector-subscript-lhs.f90
index 74236b39ebf4f6..1885e7c2fecb0b 100644
--- a/flang/test/Lower/HLFIR/vector-subscript-lhs.f90
+++ b/flang/test/Lower/HLFIR/vector-subscript-lhs.f90
@@ -1,6 +1,7 @@
 ! Test lowering of vector subscripted designators in assignment
 ! left-hand sides.
 ! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s
+! RUN: bbc -emit-hlfir -o - -I nw -fwrapv %s 2>&1 | FileCheck %s
 
 subroutine test_simple(x, vector)
   integer(8) :: vector(10)
@@ -97,6 +98,42 @@ subroutine test_nested_vectors(x, vector1, vector2, vector3)
 ! CHECK:    }
 ! CHECK:  }
 
+subroutine test_added_vectors(x, vector1, vector2)
+  integer(8) :: vector1(10), vector2(10)
+  real :: x(:)
+  x(vector1+vector2) = 42.
+end subroutine
+! CHECK-LABEL:   func.func @_QPtest_added_vectors(
+! CHECK:  %[[VAL_2:.*]] = arith.constant 10 : index
+! CHECK:  %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Evector1
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}Evector2
+! CHECK:  %[[VAL_6:.*]]:2 = hlfir.declare {{.*}}Ex
+! CHECK:  hlfir.region_assign {
+! CHECK:    %[[VAL_7:.*]] = arith.constant 4.200000e+01 : f32
+! CHECK:    hlfir.yield %[[VAL_7]] : f32
+! CHECK:  } to {
+! CHECK:    %[[VAL_8:.*]] = hlfir.elemental %[[VAL_3]] unordered : (!fir.shape<1>) -> !hlfir.expr<10xi64> {
+! CHECK:    ^bb0(%[[VAL_9:.*]]: index):
+! CHECK:      %[[VAL_10:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_9]])  : (!fir.ref<!fir.array<10xi64>>, index) -> !fir.ref<i64>
+! CHECK:      %[[VAL_11:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]])  : (!fir.ref<!fir.array<10xi64>>, index) -> !fir.ref<i64>
+! CHECK:      %[[VAL_12:.*]] = fir.load %[[VAL_10]] : !fir.ref<i64>
+! CHECK:      %[[VAL_13:.*]] = fir.load %[[VAL_11]] : !fir.ref<i64>
+! CHECK:      %[[VAL_14:.*]] = arith.addi %[[VAL_12]], %[[VAL_13]] : i64
+! CHECK:      hlfir.yield_element %[[VAL_14]] : i64
+! CHECK:    }
+! CHECK:    %[[VAL_27:.*]] = arith.constant 10 : index
+! CHECK:    %[[VAL_28:.*]] = fir.shape %[[VAL_27]] : (index) -> !fir.shape<1>
+! CHECK:    hlfir.elemental_addr %[[VAL_28]] unordered : !fir.shape<1> {
+! CHECK:    ^bb0(%[[VAL_29:.*]]: index):
+! CHECK:      %[[VAL_31:.*]] = hlfir.apply %[[VAL_8]], %[[VAL_29]] : (!hlfir.expr<10xi64>, index) -> i64
+! CHECK:      %[[VAL_32:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_31]])  : (!fir.box<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
+! CHECK:      hlfir.yield %[[VAL_32]] : !fir.ref<f32>
+! CHECK:    } cleanup {
+! CHECK:      hlfir.destroy %[[VAL_8]] : !hlfir.expr<10xi64>
+! CHECK:    }
+! CHECK:  }
+
 subroutine test_substring(x, vector)
   integer(8) :: vector(10), ifoo, ibar
   external :: ifoo, ibar
diff --git a/flang/test/Lower/Intrinsics/bge.f90 b/flang/test/Lower/Intrinsics/bge.f90
index 19ddf7d95c3881..ccd5a7152f4fbb 100644
--- a/flang/test/Lower/Intrinsics/bge.f90
+++ b/flang/test/Lower/Intrinsics/bge.f90
@@ -156,3 +156,20 @@ subroutine bge_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: fir.store %[[V]] to %[[C]] : !fir.ref<!fir.logical<4>>
 end subroutine bge_test11
+
+! CHECK-LABEL: bge_test12
+! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}, %[[C:.*]]: !fir.ref<!fir.logical<4>>{{.*}}
+subroutine bge_test12(a, b, c)
+  integer :: a, b
+  logical :: c
+  ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[LHS:.*]] = arith.addi %[[A_VAL]], %[[B_VAL]] : i32
+  ! CHECK: %[[A_VAL2:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL2:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[RHS:.*]] = arith.subi %[[A_VAL2]], %[[B_VAL2]] : i32
+  c = bge(a+b, a-b)
+  ! CHECK: %[[C_CMP:.*]] = arith.cmpi uge, %[[LHS]], %[[RHS]] : i32
+  ! CHECK: %[[C_VAL:.*]] = fir.convert %[[C_CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: fir.store %[[C_VAL]] to %[[C]] : !fir.ref<!fir.logical<4>>
+end subroutine bge_test12
diff --git a/flang/test/Lower/Intrinsics/bgt.f90 b/flang/test/Lower/Intrinsics/bgt.f90
index fea8611c17014e..18c2afeae13d8f 100644
--- a/flang/test/Lower/Intrinsics/bgt.f90
+++ b/flang/test/Lower/Intrinsics/bgt.f90
@@ -156,3 +156,20 @@ subroutine bgt_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: fir.store %[[V]] to %[[C]] : !fir.ref<!fir.logical<4>>
 end subroutine bgt_test11
+
+! CHECK-LABEL: bgt_test12
+! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}, %[[C:.*]]: !fir.ref<!fir.logical<4>>{{.*}}
+subroutine bgt_test12(a, b, c)
+  integer :: a, b
+  logical :: c
+  ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[LHS:.*]] = arith.addi %[[A_VAL]], %[[B_VAL]] : i32
+  ! CHECK: %[[A_VAL2:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL2:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[RHS:.*]] = arith.subi %[[A_VAL2]], %[[B_VAL2]] : i32
+  c = bgt(a+b, a-b)
+  ! CHECK: %[[C_CMP:.*]] = arith.cmpi ugt, %[[LHS]], %[[RHS]] : i32
+  ! CHECK: %[[C_VAL:.*]] = fir.convert %[[C_CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: fir.store %[[C_VAL]] to %[[C]] : !fir.ref<!fir.logical<4>>
+end subroutine bgt_test12
diff --git a/flang/test/Lower/Intrinsics/ble.f90 b/flang/test/Lower/Intrinsics/ble.f90
index 1c996a963e4309..8a92efd3153dfb 100644
--- a/flang/test/Lower/Intrinsics/ble.f90
+++ b/flang/test/Lower/Intrinsics/ble.f90
@@ -156,3 +156,20 @@ subroutine ble_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: fir.store %[[V]] to %[[C]] : !fir.ref<!fir.logical<4>>
 end subroutine ble_test11
+
+! CHECK-LABEL: ble_test12
+! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}, %[[C:.*]]: !fir.ref<!fir.logical<4>>{{.*}}
+subroutine ble_test12(a, b, c)
+  integer :: a, b
+  logical :: c
+  ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[LHS:.*]] = arith.addi %[[A_VAL]], %[[B_VAL]] : i32
+  ! CHECK: %[[A_VAL2:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL2:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[RHS:.*]] = arith.subi %[[A_VAL2]], %[[B_VAL2]] : i32
+  c = ble(a+b, a-b)
+  ! CHECK: %[[C_CMP:.*]] = arith.cmpi ule, %[[LHS]], %[[RHS]] : i32
+  ! CHECK: %[[C_VAL:.*]] = fir.convert %[[C_CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: fir.store %[[C_VAL]] to %[[C]] : !fir.ref<!fir.logical<4>>
+end subroutine ble_test12
diff --git a/flang/test/Lower/Intrinsics/blt.f90 b/flang/test/Lower/Intrinsics/blt.f90
index 06a57fb579e6bb..58f5fb12d0883e 100644
--- a/flang/test/Lower/Intrinsics/blt.f90
+++ b/flang/test/Lower/Intrinsics/blt.f90
@@ -156,3 +156,20 @@ subroutine blt_test11(c)
   ! CHECK: %[[V:.*]] = fir.convert %[[R]] : (i1) -> !fir.logical<4>
   ! CHECK: fir.store %[[V]] to %[[C]] : !fir.ref<!fir.logical<4>>
 end subroutine blt_test11
+
+! CHECK-LABEL: blt_test12
+! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}, %[[C:.*]]: !fir.ref<!fir.logical<4>>{{.*}}
+subroutine blt_test12(a, b, c)
+  integer :: a, b
+  logical :: c
+  ! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[LHS:.*]] = arith.addi %[[A_VAL]], %[[B_VAL]] : i32
+  ! CHECK: %[[A_VAL2:.*]] = fir.load %[[A]] : !fir.ref<i32>
+  ! CHECK: %[[B_VAL2:.*]] = fir.load %[[B]] : !fir.ref<i32>
+  ! CHECK: %[[RHS:.*]] = arith.subi %[[A_VAL2]], %[[B_VAL2]] : i32
+  c = blt(a+b, a-b)
+  ! CHECK: %[[C_CMP:.*]] = arith.cmpi ult, %[[LHS]], %[[RHS]] : i32
+  ! CHECK: %[[C_VAL:.*]] = fir.convert %[[C_CMP]] : (i1) -> !fir.logical<4>
+  ! CHECK: fir.store %[[C_VAL]] to %[[C]] : !fir.ref<!fir.logical<4>>
+end subroutine blt_test12
diff --git a/flang/test/Lower/array.f90 b/flang/test/Lower/array.f90
index a2ab3d1384955b..f0c95d950766ca 100644
--- a/flang/test/Lower/array.f90
+++ b/flang/test/Lower/array.f90
@@ -1,4 +1,5 @@
 ! RUN: bbc -hlfir=false -o - %s | FileCheck %s
+! RUN: bbc -hlfir=false -fwrapv -o - %s | FileCheck %s --check-prefix=NO-NSW
 
 ! CHECK-LABEL: fir.global @block_
 ! CHECK-DAG: %[[VAL_1:.*]] = arith.constant 1.000000e+00 : f32
@@ -96,6 +97,167 @@ subroutine s(i,j,k,ii,jj,kk,a1,a2,a3,a4,a5,a6,a7)
   
 end subroutine s
 
+! CHECK-LABEL: func.func @_QPs2
+! NO-NSW-LABEL: func.func @_QPs2
+subroutine s2(i,j,k,ii,jj,kk,a1,a2,a3,a4,a5,a6,a7)
+  integer i, j, k, ii, jj, kk
+
+  ! extents are compile-time constant
+  real a1(10,20)
+  integer a2(30,*)
+  real a3(2:40,3:50)
+  integer a4(4:60, 5:*)
+
+  ! extents computed at run-time
+  real a5(i:j)
+  integer a6(6:i,j:*)
+  real a7(i:70,7:j,k:80)
+
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: fir.load %arg3 :
+  ! CHECK: arith.subi %{{.*}}, %[[one32:c1[^ ]*]] overflow<nsw> : i32
+  ! CHECK: %[[i1:.*]] = arith.subi %{{.*}}, %[[one64:c1[^ ]*]] : i64
+  ! CHECK: fir.load %arg4 :
+  ! CHECK: arith.addi %{{.*}}, %[[one32]] overflow<nsw> : i32
+  ! CHECK: %[[j1:.*]] = arith.subi %{{.*}}, %[[one64]] : i64
+  ! CHECK: fir.coordinate_of %arg6, %[[i1]], %[[j1]] :
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: fir.load %arg3 :
+  ! NO-NSW: arith.subi %{{.*}}, %[[one32:c1[^ ]*]] : i32
+  ! NO-NSW: %[[i1:.*]] = arith.subi %{{.*}}, %[[one64:c1[^ ]*]] : i64
+  ! NO-NSW: fir.load %arg4 :
+  ! NO-NSW: arith.addi %{{.*}}, %[[one32]] : i32
+  ! NO-NSW: %[[j1:.*]] = arith.subi %{{.*}}, %[[one64]] : i64
+  ! NO-NSW: fir.coordinate_of %arg6, %[[i1]], %[[j1]] :
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a1(ii-1,jj+1)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: arith.muli %{{.*}}, %[[two32:c2[^ ]*]] overflow<nsw> : i32
+  ! CHECK: fir.coordinate_of %{{[0-9]+}}, %{{[0-9]+}} : {{.*}} -> !fir.ref<i32>
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: arith.muli %{{.*}}, %[[two32:c2[^ ]*]] : i32
+  ! NO-NSW: fir.coordinate_of %{{[0-9]+}}, %{{[0-9]+}} : {{.*}} -> !fir.ref<i32>
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a2(ii,2*jj)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: fir.load %arg3 :
+  ! CHECK: arith.subi %c40{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[cc2:.*]] = fir.convert %c2{{.*}} :
+  ! CHECK: %[[i2:.*]] = arith.subi %{{.*}}, %[[cc2]] : i64
+  ! CHECK: fir.load %arg4 :
+  ! CHECK: arith.subi %{{.*}}, %[[three32:c3[^ ]*]] overflow<nsw> : i32
+  ! CHECK: %[[cc3:.*]] = fir.convert %c3{{.*}} :
+  ! CHECK: %[[j2:.*]] = arith.subi %{{.*}}, %[[cc3]] : i64
+  ! CHECK: fir.coordinate_of %arg8, %[[i2]], %[[j2]] :
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: fir.load %arg3 :
+  ! NO-NSW: arith.subi %c40{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[cc2:.*]] = fir.convert %c2{{.*}} :
+  ! NO-NSW: %[[i2:.*]] = arith.subi %{{.*}}, %[[cc2]] : i64
+  ! NO-NSW: fir.load %arg4 :
+  ! NO-NSW: arith.subi %{{.*}}, %[[three32:c3[^ ]*]] : i32
+  ! NO-NSW: %[[cc3:.*]] = fir.convert %c3{{.*}} :
+  ! NO-NSW: %[[j2:.*]] = arith.subi %{{.*}}, %[[cc3]] : i64
+  ! NO-NSW: fir.coordinate_of %arg8, %[[i2]], %[[j2]] :
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a3(40-ii,jj-3)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: arith.muli %{{.*}}, %[[two32]] overflow<nsw> : i32
+  ! CHECK: arith.subi %{{.*}}, %[[one32]] overflow<nsw> : i32
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: arith.muli %{{.*}}, %[[two32]] : i32
+  ! NO-NSW: arith.subi %{{.*}}, %[[one32]] : i32
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a4(ii*2,jj-1)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: fir.load %arg5 :
+  ! CHECK: arith.addi %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[x5:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : i64
+  ! CHECK: fir.coordinate_of %arg10, %[[x5]] :
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: fir.load %arg5 :
+  ! NO-NSW: arith.addi %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[x5:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : i64
+  ! NO-NSW: fir.coordinate_of %arg10, %[[x5]] :
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a5(kk+i)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: %[[a6:.*]] = fir.convert %arg11 : {{.*}} -> !fir.ref<!fir.array<?xi32>>
+  ! CHECK: fir.load %arg3 :
+  ! CHECK: arith.muli %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[x6:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! CHECK: fir.load %arg4 :
+  ! CHECK: arith.subi %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[y6:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! CHECK: %[[z6:.*]] = arith.muli %{{.}}, %[[y6]] : index
+  ! CHECK: %[[w6:.*]] = arith.addi %[[z6]], %[[x6]] : index
+  ! CHECK: fir.coordinate_of %[[a6]], %[[w6]] :
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: %[[a6:.*]] = fir.convert %arg11 : {{.*}} -> !fir.ref<!fir.array<?xi32>>
+  ! NO-NSW: fir.load %arg3 :
+  ! NO-NSW: arith.muli %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[x6:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! NO-NSW: fir.load %arg4 :
+  ! NO-NSW: arith.subi %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[y6:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! NO-NSW: %[[z6:.*]] = arith.muli %{{.}}, %[[y6]] : index
+  ! NO-NSW: %[[w6:.*]] = arith.addi %[[z6]], %[[x6]] : index
+  ! NO-NSW: fir.coordinate_of %[[a6]], %[[w6]] :
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a6(ii*i, jj-j)
+  ! CHECK-LABEL: BeginExternalListOutput
+  ! CHECK: %[[a7:.*]] = fir.convert %arg12 : {{.*}} -> !fir.ref<!fir.array<?xf32>>
+  ! CHECK: fir.load %arg5 :
+  ! CHECK: arith.addi %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[x7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! CHECK: fir.load %arg4 :
+  ! CHECK: arith.subi %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[y7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! CHECK: %[[z7:.*]] = arith.muli %[[u7:.*]], %[[y7]] : index
+  ! CHECK: %[[w7:.*]] = arith.addi %[[z7]], %[[x7]] : index
+  ! CHECK: %[[v7:.*]] = arith.muli %[[u7]], %{{.*}} : index
+  ! CHECK: fir.load %arg3 :
+  ! CHECK: arith.muli %{{.*}}, %{{[^ ]*}} overflow<nsw> : i32
+  ! CHECK: %[[r7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! CHECK: %[[s7:.*]] = arith.muli %[[v7]], %[[r7]] : index
+  ! CHECK: %[[t7:.*]] = arith.addi %[[s7]], %[[w7]] : index
+  ! CHECK: fir.coordinate_of %[[a7]], %[[t7]] :
+  ! CHECK-LABEL: EndIoStatement
+
+  ! NO-NSW-LABEL: BeginExternalListOutput
+  ! NO-NSW: %[[a7:.*]] = fir.convert %arg12 : {{.*}} -> !fir.ref<!fir.array<?xf32>>
+  ! NO-NSW: fir.load %arg5 :
+  ! NO-NSW: arith.addi %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[x7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! NO-NSW: fir.load %arg4 :
+  ! NO-NSW: arith.subi %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[y7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! NO-NSW: %[[z7:.*]] = arith.muli %[[u7:.*]], %[[y7]] : index
+  ! NO-NSW: %[[w7:.*]] = arith.addi %[[z7]], %[[x7]] : index
+  ! NO-NSW: %[[v7:.*]] = arith.muli %[[u7]], %{{.*}} : index
+  ! NO-NSW: fir.load %arg3 :
+  ! NO-NSW: arith.muli %{{.*}}, %{{[^ ]*}} : i32
+  ! NO-NSW: %[[r7:.*]] = arith.subi %{{.*}}, %{{[^ ]*}} : index
+  ! NO-NSW: %[[s7:.*]] = arith.muli %[[v7]], %[[r7]] : index
+  ! NO-NSW: %[[t7:.*]] = arith.addi %[[s7]], %[[w7]] : index
+  ! NO-NSW: fir.coordinate_of %[[a7]], %[[t7]] :
+  ! NO-NSW-LABEL: EndIoStatement
+  print *, a7(kk+k, jj-j, ii*i)
+
+end subroutine s2
+
 ! CHECK-LABEL range
 subroutine range()
   ! Compile-time initalized arrays
diff --git a/flang/test/Lower/forall/array-pointer.f90 b/flang/test/Lower/forall/array-pointer.f90
index 1e8f7a6a55002c..82adb6dad86b1d 100644
--- a/flang/test/Lower/forall/array-pointer.f90
+++ b/flang/test/Lower/forall/array-pointer.f90
@@ -7,6 +7,7 @@
 ! Fortran.
 
 ! RUN: bbc --use-desc-for-alloc=false -emit-fir -hlfir=false %s -o - | FileCheck %s
+! RUN: bbc --use-desc-for-alloc=false -emit-fir -hlfir=false -fwrapv %s -o - | FileCheck %s --check-prefix=NO-NSW
 
 module array_of_pointer_test
   type t
@@ -651,9 +652,9 @@ end subroutine s7
 ! CHECK:           %[[VAL_15:.*]] = arith.constant 1 : index
 ! CHECK:           %[[VAL_16:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
 ! CHECK:           %[[VAL_17:.*]] = arith.constant 1 : i32
-! CHECK:           %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
+! CHECK:           %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] overflow<nsw> : i32
 ! CHECK:           %[[VAL_19:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
-! CHECK:           %[[VAL_20:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] : i32
+! CHECK:           %[[VAL_20:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] overflow<nsw> : i32
 ! CHECK:           %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i32) -> i64
 ! CHECK:           %[[VAL_22:.*]] = arith.constant 1 : i64
 ! CHECK:           %[[VAL_23:.*]] = arith.subi %[[VAL_21]], %[[VAL_22]] : i64
@@ -682,6 +683,55 @@ end subroutine s7
 ! CHECK:         return
 ! CHECK:       }
 
+! NO-NSW-LABEL: func @_QPs7(
+! NO-NSW-SAME:              %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>> {fir.bindc_name = "x"},
+! NO-NSW-SAME:              %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "y", fir.target},
+! NO-NSW-SAME:              %[[VAL_2:.*]]: !fir.ref<i32> {fir.bindc_name = "n"}) {
+! NO-NSW:         %[[VAL_3:.*]] = fir.alloca i32 {adapt.valuebyref, bindc_name = "i"}
+! NO-NSW:         %[[VAL_4:.*]] = arith.constant 1 : i32
+! NO-NSW:         %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> index
+! NO-NSW:         %[[VAL_6:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
+! NO-NSW:         %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> index
+! NO-NSW:         %[[VAL_8:.*]] = arith.constant 1 : index
+! NO-NSW:         %[[VAL_9:.*]] = fir.array_load %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>>) -> !fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>
+! NO-NSW:         %[[VAL_10:.*]] = fir.array_load %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.array<?xi32>
+! NO-NSW:         %[[VAL_11:.*]] = fir.do_loop %[[VAL_12:.*]] = %[[VAL_5]] to %[[VAL_7]] step %[[VAL_8]] unordered iter_args(%[[VAL_13:.*]] = %[[VAL_9]]) -> (!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>) {
+! NO-NSW:           %[[VAL_14:.*]] = fir.convert %[[VAL_12]] : (index) -> i32
+! NO-NSW:           fir.store %[[VAL_14]] to %[[VAL_3]] : !fir.ref<i32>
+! NO-NSW:           %[[VAL_15:.*]] = arith.constant 1 : index
+! NO-NSW:           %[[VAL_16:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
+! NO-NSW:           %[[VAL_17:.*]] = arith.constant 1 : i32
+! NO-NSW:           %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
+! NO-NSW:           %[[VAL_19:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
+! NO-NSW:           %[[VAL_20:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] : i32
+! NO-NSW:           %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i32) -> i64
+! NO-NSW:           %[[VAL_22:.*]] = arith.constant 1 : i64
+! NO-NSW:           %[[VAL_23:.*]] = arith.subi %[[VAL_21]], %[[VAL_22]] : i64
+! NO-NSW:           %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_23]] : (!fir.box<!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>>, i64) -> !fir.ref<!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>
+! NO-NSW:           %[[VAL_25:.*]] = fir.field_index ip, !fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>
+! NO-NSW:           %[[VAL_26:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_25]] : (!fir.ref<!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>, !fir.field) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+! NO-NSW:           %[[VAL_27:.*]] = fir.load %[[VAL_26]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+! NO-NSW:           %[[VAL_28:.*]] = fir.box_addr %[[VAL_27]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
+! NO-NSW:           %[[VAL_29:.*]] = fir.load %[[VAL_28]] : !fir.ptr<i32>
+! NO-NSW:           %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i32) -> i64
+! NO-NSW:           %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> index
+! NO-NSW:           %[[VAL_32:.*]] = arith.subi %[[VAL_31]], %[[VAL_15]] : index
+! NO-NSW:           %[[VAL_33:.*]] = fir.array_access %[[VAL_10]], %[[VAL_32]] : (!fir.array<?xi32>, index) -> !fir.ref<i32>
+! NO-NSW:           %[[VAL_34:.*]] = fir.convert %[[VAL_33]] : (!fir.ref<i32>) -> !fir.ptr<i32>
+! NO-NSW:           %[[VAL_35:.*]] = fir.embox %[[VAL_34]] : (!fir.ptr<i32>) -> !fir.box<!fir.ptr<i32>>
+! NO-NSW:           %[[VAL_36:.*]] = arith.constant 1 : index
+! NO-NSW:           %[[VAL_37:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
+! NO-NSW:           %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (i32) -> i64
+! NO-NSW:           %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (i64) -> index
+! NO-NSW:           %[[VAL_40:.*]] = arith.subi %[[VAL_39]], %[[VAL_36]] : index
+! NO-NSW:           %[[VAL_41:.*]] = fir.field_index ip, !fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>
+! NO-NSW:           %[[VAL_42:.*]] = fir.array_update %[[VAL_13]], %[[VAL_35]], %[[VAL_40]], %[[VAL_41]] : (!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>, !fir.box<!fir.ptr<i32>>, index, !fir.field) -> !fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>
+! NO-NSW:           fir.result %[[VAL_42]] : !fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>
+! NO-NSW:         }
+! NO-NSW:         fir.array_merge_store %[[VAL_9]], %[[VAL_43:.*]] to %[[VAL_0]] : !fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>, !fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>, !fir.box<!fir.array<?x!fir.type<_QMarray_of_pointer_testTt{ip:!fir.box<!fir.ptr<i32>>}>>>
+! NO-NSW:         return
+! NO-NSW:       }
+
 subroutine s8(x,y,n)
   use array_of_pointer_test
   type(ta) x(:)
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index dcff4503f16571..fa02aacd842f90 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -227,6 +227,12 @@ static llvm::cl::opt<std::string>
                          llvm::cl::desc("Override host target triple"),
                          llvm::cl::init(""));
 
+static llvm::cl::opt<bool> integerWrapAround(
+    "fwrapv",
+    llvm::cl::desc("Treat signed integer overflow as two's complement"),
+    llvm::cl::init(false));
+
+// TODO: integrate this option with the above
 static llvm::cl::opt<bool>
     setNSW("integer-overflow",
            llvm::cl::desc("add nsw flag to internal operations"),
@@ -371,6 +377,7 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
   Fortran::lower::LoweringOptions loweringOptions{};
   loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder);
   loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);
+  loweringOptions.setIntegerWrapAround(integerWrapAround);
   loweringOptions.setNSWOnLoopVarInc(setNSW);
   std::vector<Fortran::lower::EnvironmentDefault> envDefaults = {};
   constexpr const char *tuneCPU = "";



More information about the flang-commits mailing list