[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