[flang-commits] [flang] 129267e - [Flang][OpenMP] Add nsw flags to OMPIRBuilder loop IV arithmetic (#214165)

via flang-commits flang-commits at lists.llvm.org
Sun Aug 9 23:41:00 PDT 2026


Author: Kaviya Rajendiran
Date: 2026-08-10T12:10:53+05:30
New Revision: 129267e8fcfca0bc68509817f944eea6b6910ac5

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

LOG: [Flang][OpenMP] Add nsw flags to OMPIRBuilder loop IV arithmetic (#214165)

- Extended the support of `-fno-wrapv` flag setting from frontend to the
OMPIRBuilder via `omp.integer_wrap_around` module attribute.
- When this attribute `omp.integer_wrap_around` is false (-fno-wrapv),
the OMPIRBuilder attaches `nsw` to all loop IV arithmetic.
- This enables SCEV to form proper `AddRec` expressions for the loop IV,
allowing `IndVarSimplify pass` to widen it from i32 to i64 and eliminate
the in-loop sext instruction which helps some backend optimizations and
also producing IR similar to Clang.

Fixes https://github.com/llvm/llvm-project/issues/213718

Added: 
    flang/test/Lower/OpenMP/integer-wrap-around.f90
    mlir/test/Target/LLVMIR/openmp-integer-wrap-around.mlir
    mlir/test/Target/LLVMIR/openmp-nsw-collapsed.mlir

Modified: 
    flang/include/flang/Tools/CrossToolHelpers.h
    flang/lib/Frontend/FrontendActions.cpp
    flang/test/Integration/OpenMP/host-ir-flag.f90
    flang/tools/bbc/bbc.cpp
    llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
    llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
    mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td
    mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h
index 6569d34e0f255..fb8007637b114 100644
--- a/flang/include/flang/Tools/CrossToolHelpers.h
+++ b/flang/include/flang/Tools/CrossToolHelpers.h
@@ -206,4 +206,10 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
       Opts.NoGPULib);
 }
 
+[[maybe_unused]] static void setOpenMPIntegerWrapAround(
+    mlir::ModuleOp module, bool value) {
+  module.getOperation()->setAttr("omp.integer_wrap_around",
+      mlir::omp::IntegerWrapAroundAttr::get(module.getContext(), value));
+}
+
 #endif // FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H

diff  --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 8955a8f61e513..e21590cc9fa7f 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -277,6 +277,8 @@ bool CodeGenAction::beginSourceFileAction() {
         makeOffloadModuleOpts(ci.getInvocation().getLangOpts()));
     mlir::omp::setOpenMPVersionAttribute(
         lb.getModule(), ci.getInvocation().getLangOpts().OpenMPVersion);
+    if (!ci.getInvocation().getLoweringOpts().getIntegerWrapAround())
+      setOpenMPIntegerWrapAround(lb.getModule(), false);
   }
 
   if (ci.getInvocation().getLangOpts().FastRealMod) {

diff  --git a/flang/test/Integration/OpenMP/host-ir-flag.f90 b/flang/test/Integration/OpenMP/host-ir-flag.f90
index 734b446fcccd4..db06b773d39f6 100644
--- a/flang/test/Integration/OpenMP/host-ir-flag.f90
+++ b/flang/test/Integration/OpenMP/host-ir-flag.f90
@@ -9,6 +9,6 @@
 !RUN: %flang_fc1 -emit-llvm-bc -fopenmp -o %t.bc %s 2>&1
 !RUN: %flang_fc1 -emit-mlir -fopenmp -fopenmp-is-target-device -fopenmp-host-ir-file-path %t.bc -o - %s 2>&1 | FileCheck %s
 
-!CHECK: module attributes {{{.*}}, omp.host_ir_filepath = "{{.*}}.bc", omp.is_gpu = false, omp.is_target_device = true{{.*}}}
+!CHECK: module attributes {{{.*}}, omp.host_ir_filepath = "{{.*}}.bc",{{.*}}omp.is_gpu = false, omp.is_target_device = true{{.*}}}
 subroutine omp_subroutine()
 end subroutine omp_subroutine

diff  --git a/flang/test/Lower/OpenMP/integer-wrap-around.f90 b/flang/test/Lower/OpenMP/integer-wrap-around.f90
new file mode 100644
index 0000000000000..9e7c847096197
--- /dev/null
+++ b/flang/test/Lower/OpenMP/integer-wrap-around.f90
@@ -0,0 +1,16 @@
+! Tests that the omp.integer_wrap_around module attribute is set when -fno-wrapv (default) is active with OpenMP enabled and absent when -fwrapv is specified.
+
+! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s --check-prefix=NOWRAPV
+! RUN: %flang_fc1 -emit-fir -fopenmp -fwrapv %s -o - | FileCheck %s --check-prefix=WRAPV
+
+! NOWRAPV: module attributes {{{.*}}omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>{{.*}}}
+! WRAPV-NOT: omp.integer_wrap_around
+
+subroutine omp_loop(a, b, n)
+  integer :: n, i
+  real(8) :: a(n), b(n)
+  !$omp parallel do
+  do i = 1, n
+    a(i) = b(i)
+  end do
+end subroutine

diff  --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index cfb3d20be6955..4d6b0a22f426e 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -541,6 +541,8 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
     mlir::omp::setOffloadModuleInterfaceAttributes(mlirModule,
                                                    offloadModuleOpts);
     mlir::omp::setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);
+    if (!integerWrapAround)
+      setOpenMPIntegerWrapAround(mlirModule, false);
   }
   burnside.lower(parseTree, semanticsContext);
   std::error_code ec;

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
index 1965f7b983805..38a56e975a807 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -132,6 +132,11 @@ class OpenMPIRBuilderConfig {
   /// Separator used between all of the rest consecutive parts of s name.
   std::optional<StringRef> Separator;
 
+  /// Flag for specifying whether the no-signed-wrap (nsw) flag should be added
+  /// to loop induction variable arithmetic. Set when the frontend guarantees
+  /// that signed integer overflow is undefined (with -fno-wrapv).
+  std::optional<bool> NoSignedWrap;
+
   // Grid Value for the GPU target.
   std::optional<omp::GV> GridValue;
 
@@ -176,6 +181,9 @@ class OpenMPIRBuilderConfig {
 
   unsigned getDefaultTargetAS() const { return DefaultTargetAS; }
 
+  bool hasNoSignedWrap() const { return NoSignedWrap.value_or(false); }
+  void setNoSignedWrap(bool Value) { NoSignedWrap = Value; }
+
   CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
 
   bool hasRequiresFlags() const { return RequiresFlags; }
@@ -4198,13 +4206,13 @@ class OpenMPIRBuilder {
   /// \param PostInsertBefore Where to insert BBs that execute after the body.
   /// \param Name      Base name used to derive BB
   ///                  and instruction names.
+  /// \param IsCollapsed  Whether this is a collapsed loop.
   ///
   /// \returns The CanonicalLoopInfo that represents the emitted loop.
-  LLVM_ABI CanonicalLoopInfo *createLoopSkeleton(DebugLoc DL, Value *TripCount,
-                                                 Function *F,
-                                                 BasicBlock *PreInsertBefore,
-                                                 BasicBlock *PostInsertBefore,
-                                                 const Twine &Name = {});
+  LLVM_ABI CanonicalLoopInfo *
+  createLoopSkeleton(DebugLoc DL, Value *TripCount, Function *F,
+                     BasicBlock *PreInsertBefore, BasicBlock *PostInsertBefore,
+                     const Twine &Name = {}, bool IsCollapsed = false);
   /// OMP Offload Info Metadata name string
   const std::string ompOffloadInfoName = "omp_offload.info";
 

diff  --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 5a363d0ac3dbd..63eab978b1db0 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -5766,7 +5766,7 @@ void OpenMPIRBuilder::createScanBBs(ScanInfo *ScanRedInfo) {
 }
 CanonicalLoopInfo *OpenMPIRBuilder::createLoopSkeleton(
     DebugLoc DL, Value *TripCount, Function *F, BasicBlock *PreInsertBefore,
-    BasicBlock *PostInsertBefore, const Twine &Name) {
+    BasicBlock *PostInsertBefore, const Twine &Name, bool IsCollapsed) {
   Module *M = F->getParent();
   LLVMContext &Ctx = M->getContext();
   Type *IndVarTy = TripCount->getType();
@@ -5807,8 +5807,29 @@ CanonicalLoopInfo *OpenMPIRBuilder::createLoopSkeleton(
   Builder.CreateBr(Latch);
 
   Builder.SetInsertPoint(Latch);
-  Value *Next = Builder.CreateAdd(IndVarPHI, ConstantInt::get(IndVarTy, 1),
-                                  "omp_" + Name + ".next", /*HasNUW=*/true);
+  // Decide whether the induction variable increment can carry nsw.
+  //
+  // Single loops: nsw is always kept (matching Clang). Any Fortran program
+  // whose trip count overflows i32 is non-conforming per F2018 11.1.7.4.1, so
+  // for valid programs 0 <= count <= INT_MAX always holds.
+  //
+  // Collapsed loops: the trip count is a product that can overflow i32 even for
+  // a conforming program, so nsw is kept only when the product is a constant
+  // that provably fits, dropped otherwise.
+  bool HasNSW = Config.hasNoSignedWrap();
+  if (HasNSW) {
+    if (auto *CI = dyn_cast<ConstantInt>(TripCount)) {
+      unsigned BitWidth = CI->getType()->getIntegerBitWidth();
+      APInt SignedMax = APInt::getSignedMaxValue(BitWidth);
+      if (CI->getValue().ugt(SignedMax))
+        HasNSW = false;
+    } else if (IsCollapsed) {
+      HasNSW = false;
+    }
+  }
+  Value *Next =
+      Builder.CreateAdd(IndVarPHI, ConstantInt::get(IndVarTy, 1),
+                        "omp_" + Name + ".next", /*HasNUW=*/true, HasNSW);
   Builder.CreateBr(Header);
   IndVarPHI->addIncoming(Next, Latch);
 
@@ -6004,8 +6025,10 @@ Expected<CanonicalLoopInfo *> OpenMPIRBuilder::createCanonicalLoop(
 
   auto BodyGen = [=](InsertPointTy CodeGenIP, Value *IV) {
     Builder.restoreIP(CodeGenIP);
-    Value *Span = Builder.CreateMul(IV, Step);
-    Value *IndVar = Builder.CreateAdd(Span, Start);
+    Value *Span = Builder.CreateMul(IV, Step, "", /*HasNUW=*/false,
+                                    /*HasNSW=*/Config.hasNoSignedWrap());
+    Value *IndVar = Builder.CreateAdd(Span, Start, "", /*HasNUW=*/false,
+                                      /*HasNSW=*/Config.hasNoSignedWrap());
     if (InScan)
       ScanRedInfo->IV = IndVar;
     return BodyGenCB(Builder.saveIP(), IndVar);
@@ -6160,7 +6183,8 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::applyStaticWorkshareLoop(
     Builder.SetInsertPoint(CLI->getBody(),
                            CLI->getBody()->getFirstInsertionPt());
     Builder.SetCurrentDebugLocation(DL);
-    return Builder.CreateAdd(OldIV, LowerBound);
+    return Builder.CreateAdd(OldIV, LowerBound, "", /*HasNUW=*/false,
+                             /*HasNSW=*/Config.hasNoSignedWrap());
   });
 
   // In the "exit" block, call the "fini" function.
@@ -7005,7 +7029,8 @@ OpenMPIRBuilder::collapseLoops(DebugLoc DL, ArrayRef<CanonicalLoopInfo *> Loops,
   // Create the collapsed loop control flow.
   CanonicalLoopInfo *Result =
       createLoopSkeleton(DL, CollapsedTripCount, F,
-                         OrigPreheader->getNextNode(), OrigAfter, "collapsed");
+                         OrigPreheader->getNextNode(), OrigAfter, "collapsed",
+                         /*IsCollapsed=*/true);
 
   // Build the collapsed loop body code.
   // Start with deriving the input loop induction variables from the collapsed

diff  --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td
index f6bc8f11ccccb..8d8fcf9e381e8 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPAttrDefs.td
@@ -101,4 +101,15 @@ def VersionAttr : OpenMP_Attr<"Version", "version"> {
   let assemblyFormat = "`<` struct(params) `>`";
 }
 
+//===----------------------------------------------------------------------===//
+// IntegerWrapAroundAttr
+//===----------------------------------------------------------------------===//
+
+def IntegerWrapAroundAttr
+    : OpenMP_Attr<"IntegerWrapAround", "integer_wrap_around"> {
+  let parameters = (ins "bool":$integer_wrap_around);
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
 #endif // OPENMP_ATTR_DEFS

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 2c81c9231a9b7..4c4f8ba9bce3d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -9512,6 +9512,16 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::amendOperation(
               }
               return failure();
             })
+      .Case("omp.integer_wrap_around",
+            [&](Attribute attr) {
+              if (auto wrapAttr = dyn_cast<omp::IntegerWrapAroundAttr>(attr)) {
+                llvm::OpenMPIRBuilderConfig &config =
+                    moduleTranslation.getOpenMPBuilder()->Config;
+                config.setNoSignedWrap(!wrapAttr.getIntegerWrapAround());
+                return success();
+              }
+              return failure();
+            })
       .Default([](Attribute) {
         // Fall through for omp attributes that do not require lowering.
         return success();

diff  --git a/mlir/test/Target/LLVMIR/openmp-integer-wrap-around.mlir b/mlir/test/Target/LLVMIR/openmp-integer-wrap-around.mlir
new file mode 100644
index 0000000000000..a2f42aa1f7bd9
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-integer-wrap-around.mlir
@@ -0,0 +1,77 @@
+// Tests how the omp.integer_wrap_around module attribute controls nsw flags on IV arithmetic in the generated LLVM IR:
+//   - <omp.integer_wrap_around = absent>  -> default behaviour, no nsw
+//   - <omp.integer_wrap_around = true>    -> wrap around allowed (-fwrapv), no nsw
+//   - <omp.integer_wrap_around = false>   -> wrap around disallowed, nsw emitted
+
+// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
+
+//-------------------------------------------------------------------------//
+// Default behaviour: without the attribute, IV increment should NOT have nsw.
+//-------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @wsloop_default_no_nsw
+// CHECK: omp_loop.header:
+// CHECK: %omp_loop.iv = phi i32 [ 0, %omp_loop.preheader ], [ %omp_loop.next, %omp_loop.inc ]
+// CHECK: omp_loop.body:
+// CHECK-NOT: add nsw
+// CHECK: omp_loop.inc:
+// CHECK: %omp_loop.next = add nuw i32 %omp_loop.iv, 1
+llvm.func @wsloop_default_no_nsw(%lb : i32, %ub : i32, %step : i32) {
+  omp.wsloop {
+    omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+      omp.yield
+    }
+  }
+  llvm.return
+}
+
+// -----
+
+//-----------------------------------------------------------------------------------//
+// With omp.integer_wrap_around = true (-fwrapv), IV increment should NOT have nsw.
+//----------------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @wsloop_wrapv_no_nsw
+// CHECK: omp_loop.header:
+// CHECK: %omp_loop.iv = phi i32 [ 0, %omp_loop.preheader ], [ %omp_loop.next, %omp_loop.inc ]
+// CHECK: omp_loop.body:
+// CHECK-NOT: add nsw
+// CHECK: omp_loop.inc:
+// CHECK: %omp_loop.next = add nuw i32 %omp_loop.iv, 1
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = true>} {
+  llvm.func @wsloop_wrapv_no_nsw(%lb : i32, %ub : i32, %step : i32) {
+    omp.wsloop {
+      omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}
+
+// -----
+
+//-----------------------------------------------------------------------//
+// With omp.integer_wrap_around = false, IV increment should have nsw.
+//-----------------------------------------------------------------------//
+// CHECK-LABEL: define void @wsloop_nsw_iv
+// CHECK: omp_loop.header:
+// CHECK: %omp_loop.iv = phi i32 [ 0, %omp_loop.preheader ], [ %omp_loop.next, %omp_loop.inc ]
+
+// CHECK: omp_loop.body:
+// CHECK: %[[IV_ADD:[0-9]+]] = add nsw i32 %omp_loop.iv, %{{[0-9]+}}
+// CHECK: %[[MUL:[0-9]+]] = mul nsw i32 %[[IV_ADD]], %{{[0-9]+}}
+// CHECK: %{{[0-9]+}} = add nsw i32 %[[MUL]], %{{[0-9]+}}
+
+// CHECK: omp_loop.inc:
+// CHECK: %omp_loop.next = add nuw nsw i32 %omp_loop.iv, 1
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>} {
+  llvm.func @wsloop_nsw_iv(%lb : i32, %ub : i32, %step : i32) {
+    omp.wsloop {
+      omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}

diff  --git a/mlir/test/Target/LLVMIR/openmp-nsw-collapsed.mlir b/mlir/test/Target/LLVMIR/openmp-nsw-collapsed.mlir
new file mode 100644
index 0000000000000..3a801951c4be4
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-nsw-collapsed.mlir
@@ -0,0 +1,90 @@
+// Test the behavior of nsw on loop IV increment for collapsed loops.
+
+// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
+
+//-------------------------------------------------------------------------//
+// Case 1: Collapsed loop with trip count > INT_MAX (46341*46341)
+//-------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @collapsed_overflow_no_nsw
+// CHECK: omp_collapsed.inc:
+// CHECK: %omp_collapsed.next = add nuw i32 %omp_collapsed.iv, 1
+// CHECK-NOT: nsw
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>} {
+  llvm.func @collapsed_overflow_no_nsw() {
+    %lb = llvm.mlir.constant(0 : i32) : i32
+    %ub1 = llvm.mlir.constant(46340 : i32) : i32
+    %ub2 = llvm.mlir.constant(46340 : i32) : i32
+    %step = llvm.mlir.constant(1 : i32) : i32
+    omp.wsloop {
+      omp.loop_nest (%iv1, %iv2) : i32 = (%lb, %lb) to (%ub1, %ub2) inclusive step (%step, %step) collapse(2) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}
+
+// -----
+
+//-------------------------------------------------------------------------//
+// Case 2: Collapsed loop with trip count <= INT_MAX (99*99)
+//-------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @collapsed_small_with_nsw
+// CHECK: omp_collapsed.inc:
+// CHECK: %omp_collapsed.next = add nuw nsw i32 %omp_collapsed.iv, 1
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>} {
+  llvm.func @collapsed_small_with_nsw() {
+    %lb = llvm.mlir.constant(0 : i32) : i32
+    %ub = llvm.mlir.constant(99 : i32) : i32
+    %step = llvm.mlir.constant(1 : i32) : i32
+    omp.wsloop {
+      omp.loop_nest (%iv1, %iv2) : i32 = (%lb, %lb) to (%ub, %ub) inclusive step (%step, %step) collapse(2) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}
+
+// -----
+
+//-------------------------------------------------------------------------//
+// Case 3: Collapsed loop with dynamic trip count
+//-------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @collapsed_dynamic_no_nsw
+// CHECK: omp_collapsed.inc:
+// CHECK: %omp_collapsed.next = add nuw i32 %omp_collapsed.iv, 1
+// CHECK-NOT: nsw
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>} {
+  llvm.func @collapsed_dynamic_no_nsw(%lb : i32, %ub1 : i32, %ub2 : i32, %step : i32) {
+    omp.wsloop {
+      omp.loop_nest (%iv1, %iv2) : i32 = (%lb, %lb) to (%ub1, %ub2) step (%step, %step) collapse(2) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}
+
+// -----
+
+//-------------------------------------------------------------------------//
+// Case 4: Single loop with dynamic trip count
+//-------------------------------------------------------------------------//
+
+// CHECK-LABEL: define void @single_loop_with_nsw
+// CHECK: omp_loop.inc:
+// CHECK: %omp_loop.next = add nuw nsw i32 %omp_loop.iv, 1
+module attributes {omp.integer_wrap_around = #omp.integer_wrap_around<integer_wrap_around = false>} {
+  llvm.func @single_loop_with_nsw(%lb : i32, %ub : i32, %step : i32) {
+    omp.wsloop {
+      omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+        omp.yield
+      }
+    }
+    llvm.return
+  }
+}


        


More information about the flang-commits mailing list