[flang-commits] [flang] [mlir] [OpenMP] [MLIR] [Flang] Replace all uses of variables in ALLOCATE directive to use new value which is created. (PR #212361)

Raghu Maddhipatla via flang-commits flang-commits at lists.llvm.org
Mon Jul 27 21:57:24 PDT 2026


https://github.com/raghavendhra updated https://github.com/llvm/llvm-project/pull/212361

>From a922200b820b7a1a0a74835c8d7f63724d873b7d Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Thu, 9 Jul 2026 09:39:47 -0500
Subject: [PATCH 1/5] [OpenMP] [MLIR] [Flang] Replace all uses of variables in
 ALLOCATE directive to use new value which is allocated.

---
 .../mlir/Target/LLVMIR/ModuleTranslation.h    |  3 +++
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 11 ++++++++++
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  | 10 +++++++++
 .../LLVMIR/openmp-allocate-directive.mlir     | 22 +++++++++++++++++++
 4 files changed, 46 insertions(+)

diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index c5c4b105ee152..1cdecb22482de 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -100,6 +100,9 @@ class ModuleTranslation {
     return valueMapping.lookup(value);
   }
 
+  /// Remap old value with new value.
+  void remapAllValuesWith(llvm::Value *oldValue, llvm::Value *newValue);
+
   /// Looks up remapped a list of remapped values.
   SmallVector<llvm::Value *> lookupValues(ValueRange values);
 
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 1c50ff192c3d5..9eb42adfd2528 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -9660,6 +9660,17 @@ convertAllocateDirOp(Operation &opInst, llvm::IRBuilderBase &builder,
     }
     // Record the alloc pointer keyed by the MLIR variable value.
     ompIface.registerAllocatedPtr(var, allocCall);
+
+    Value baseVar = getBaseValueForTypeLookup(var);
+    if (llvm::Value *baseLlvm = moduleTranslation.lookupValue(baseVar)) {
+      llvm::Value *boundPtr = builder.CreatePointerBitCastOrAddrSpaceCast(
+          allocCall, baseLlvm->getType());
+      moduleTranslation.remapAllValuesWith(baseLlvm, boundPtr);
+    } else if (llvm::Value *varLlvm = moduleTranslation.lookupValue(var)) {
+      llvm::Value *boundPtr = builder.CreatePointerBitCastOrAddrSpaceCast(
+          allocCall, varLlvm->getType());
+      moduleTranslation.remapAllValuesWith(varLlvm, boundPtr);
+    }
   }
 
   return success();
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index b76a803f93ad9..a8e05c669c97e 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -2437,6 +2437,16 @@ SmallVector<llvm::Value *> ModuleTranslation::lookupValues(ValueRange values) {
   return remapped;
 }
 
+void ModuleTranslation::remapAllValuesWith(llvm::Value *oldValue,
+                                           llvm::Value *newValue) {
+  if (oldValue == newValue)
+    return;
+  oldValue->replaceAllUsesWith(newValue);
+  for (auto &entry : valueMapping)
+    if (entry.second == oldValue)
+      entry.second = newValue;
+}
+
 llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
   if (!ompBuilder) {
     ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
diff --git a/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir b/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
index d8975eb512abe..69ab9b6c00616 100644
--- a/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
@@ -115,3 +115,25 @@ llvm.func @test_allocate_array_global() {
   omp.allocate_free (%z : !llvm.ptr) allocator(%alloc6 : i32)
   llvm.return
 }
+
+// -----
+
+// Verifies that loads and stores after omp.allocate_dir use the OMP-allocated
+// pointer rather than the original storage.
+//
+// CHECK-LABEL: define void @test_allocate_use
+// CHECK:   %[[TID:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   %[[ALLOC:.*]] = call ptr @__kmpc_alloc(i32 %[[TID]], i64 8, ptr null)
+// CHECK:   store i32 42, ptr %[[ALLOC]]
+// CHECK:   %[[VAL:.*]] = load i32, ptr %[[ALLOC]]
+// CHECK:   %[[TID_FREE:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   call void @__kmpc_free(i32 %[[TID_FREE]], ptr %[[ALLOC]], ptr null)
+// CHECK:   ret void
+llvm.func @test_allocate_use(%arg0: !llvm.ptr) {
+  omp.allocate_dir (%arg0 : !llvm.ptr)
+  %c42 = llvm.mlir.constant(42 : i32) : i32
+  llvm.store %c42, %arg0 : i32, !llvm.ptr
+  %v = llvm.load %arg0 : !llvm.ptr -> i32
+  omp.allocate_free (%arg0 : !llvm.ptr)
+  llvm.return
+}

>From 03e31565c428fdc4a924ae635c5e04cd450c93c3 Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Wed, 15 Jul 2026 23:38:15 -0500
Subject: [PATCH 2/5] Addressed implementation support for more test cases.

---
 .../mlir/Target/LLVMIR/ModuleTranslation.h    |  6 +-
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 81 +++++++++++++++----
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  | 54 ++++++++++++-
 .../LLVMIR/openmp-allocate-directive.mlir     | 52 ++++++++++++
 4 files changed, 172 insertions(+), 21 deletions(-)

diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 1cdecb22482de..768ed99f7c508 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -100,8 +100,10 @@ class ModuleTranslation {
     return valueMapping.lookup(value);
   }
 
-  /// Remap old value with new value.
-  void remapAllValuesWith(llvm::Value *oldValue, llvm::Value *newValue);
+  /// Remap old value with new value. When oldValue is a LLVM constant, builder
+  /// is used to materialize any constant-expression users as instructions.
+  void remapAllValuesWith(llvm::Value *oldValue, llvm::Value *newValue,
+                          llvm::IRBuilderBase *builder = nullptr);
 
   /// Looks up remapped a list of remapped values.
   SmallVector<llvm::Value *> lookupValues(ValueRange values);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 9eb42adfd2528..ae43b97306d95 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -6289,6 +6289,64 @@ static Value getBaseValueForTypeLookup(Value value) {
   return value;
 }
 
+// Determine the LLVM type whose storage size should be allocated for an
+// OpenMP allocate directive list item. Opaque pointers lose element type, so
+// trace through declare wrappers to the underlying global or stack allocation.
+static llvm::Type *
+getAllocatedLlvmTypeForVariable(Value var,
+                                LLVM::ModuleTranslation &moduleTranslation) {
+  llvm::Type *llvmVarTy = moduleTranslation.convertType(var.getType());
+  if (!llvmVarTy->isPointerTy())
+    return llvmVarTy;
+
+  Value baseVar = getBaseValueForTypeLookup(var);
+  if (Operation *globalOp = getGlobalOpFromValue(baseVar))
+    if (auto gop = dyn_cast<LLVM::GlobalOp>(globalOp))
+      return moduleTranslation.convertType(gop.getGlobalType());
+
+  if (auto allocaOp =
+          dyn_cast_if_present<LLVM::AllocaOp>(baseVar.getDefiningOp()))
+    return moduleTranslation.convertType(allocaOp.getElemType());
+
+  if (llvm::Value *baseLlvm = moduleTranslation.lookupValue(baseVar))
+    if (auto *allocaInst = dyn_cast<llvm::AllocaInst>(baseLlvm))
+      return allocaInst->getAllocatedType();
+
+  return llvmVarTy;
+}
+
+// For dynamically-sized stack allocations, compute the allocation size from
+// the alloca's element count at runtime.
+static std::optional<llvm::Value *>
+getDynamicAllocatedSize(Value var, LLVM::ModuleTranslation &moduleTranslation,
+                        llvm::IRBuilderBase &builder,
+                        const llvm::DataLayout &dataLayout) {
+  Value baseVar = getBaseValueForTypeLookup(var);
+  if (auto allocaOp =
+          dyn_cast_if_present<LLVM::AllocaOp>(baseVar.getDefiningOp())) {
+    if (Value arraySize = allocaOp.getArraySize()) {
+      llvm::Type *elemTy =
+          moduleTranslation.convertType(allocaOp.getElemType());
+      llvm::Value *numElems = moduleTranslation.lookupValue(arraySize);
+      uint64_t elemSize = dataLayout.getTypeStoreSize(elemTy).getFixedValue();
+      return builder.CreateMul(numElems, builder.getInt64(elemSize));
+    }
+  }
+  if (llvm::Value *baseLlvm = moduleTranslation.lookupValue(baseVar)) {
+    if (auto *allocaInst = dyn_cast<llvm::AllocaInst>(baseLlvm)) {
+      if (allocaInst->isArrayAllocation() &&
+          !llvm::isa<llvm::ArrayType>(allocaInst->getAllocatedType())) {
+        uint64_t elemSize =
+            dataLayout.getTypeStoreSize(allocaInst->getAllocatedType())
+                .getFixedValue();
+        return builder.CreateMul(allocaInst->getArraySize(),
+                                 builder.getInt64(elemSize));
+      }
+    }
+  }
+  return std::nullopt;
+}
+
 static llvm::SmallString<64>
 getDeclareTargetRefPtrSuffix(LLVM::GlobalOp globalOp,
                              llvm::OpenMPIRBuilder &ompBuilder,
@@ -9608,21 +9666,14 @@ convertAllocateDirOp(Operation &opInst, llvm::IRBuilderBase &builder,
   }
 
   for (Value var : vars) {
-    llvm::Type *llvmVarTy = moduleTranslation.convertType(var.getType());
-
-    // Opaque pointers lose element type. Trace to GlobalOp for type
-    // Falls back to llvmVarTy when not from a global.
-    llvm::Type *typeToInspect = llvmVarTy;
-    if (llvmVarTy->isPointerTy()) {
-      Value baseVar = getBaseValueForTypeLookup(var);
-      if (Operation *globalOp = getGlobalOpFromValue(baseVar)) {
-        if (auto gop = dyn_cast<LLVM::GlobalOp>(globalOp))
-          typeToInspect = moduleTranslation.convertType(gop.getGlobalType());
-      }
-    }
+    llvm::Type *typeToInspect =
+        getAllocatedLlvmTypeForVariable(var, moduleTranslation);
 
     llvm::Value *size;
-    if (auto arrTy = llvm::dyn_cast<llvm::ArrayType>(typeToInspect)) {
+    if (std::optional<llvm::Value *> dynamicSize = getDynamicAllocatedSize(
+            var, moduleTranslation, builder, dataLayout)) {
+      size = *dynamicSize;
+    } else if (auto arrTy = llvm::dyn_cast<llvm::ArrayType>(typeToInspect)) {
       llvm::Value *elementCount = builder.getInt64(1);
       llvm::Type *currentType = arrTy;
       while (auto nestedArrTy = llvm::dyn_cast<llvm::ArrayType>(currentType)) {
@@ -9665,11 +9716,11 @@ convertAllocateDirOp(Operation &opInst, llvm::IRBuilderBase &builder,
     if (llvm::Value *baseLlvm = moduleTranslation.lookupValue(baseVar)) {
       llvm::Value *boundPtr = builder.CreatePointerBitCastOrAddrSpaceCast(
           allocCall, baseLlvm->getType());
-      moduleTranslation.remapAllValuesWith(baseLlvm, boundPtr);
+      moduleTranslation.remapAllValuesWith(baseLlvm, boundPtr, &builder);
     } else if (llvm::Value *varLlvm = moduleTranslation.lookupValue(var)) {
       llvm::Value *boundPtr = builder.CreatePointerBitCastOrAddrSpaceCast(
           allocCall, varLlvm->getType());
-      moduleTranslation.remapAllValuesWith(varLlvm, boundPtr);
+      moduleTranslation.remapAllValuesWith(varLlvm, boundPtr, &builder);
     }
   }
 
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index a8e05c669c97e..94d3e1406e0bf 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -43,9 +43,11 @@
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -2437,14 +2439,58 @@ SmallVector<llvm::Value *> ModuleTranslation::lookupValues(ValueRange values) {
   return remapped;
 }
 
+static void remapConstantPointerUses(
+    llvm::Constant *oldPtr, llvm::Value *newPtr, llvm::IRBuilderBase &builder,
+    llvm::DenseMap<llvm::Constant *, llvm::Value *> &replacements) {
+  for (llvm::Use &use : llvm::make_early_inc_range(oldPtr->uses())) {
+    if (auto *constantExpr =
+            llvm::dyn_cast<llvm::ConstantExpr>(use.getUser())) {
+      if (constantExpr->getOpcode() == llvm::Instruction::GetElementPtr) {
+        auto *gep = llvm::cast<llvm::GEPOperator>(constantExpr);
+        llvm::SmallVector<llvm::Value *, 4> indices;
+        for (unsigned i = 1, e = constantExpr->getNumOperands(); i < e; ++i)
+          indices.push_back(constantExpr->getOperand(i));
+        llvm::Value *newGEP =
+            builder.CreateGEP(gep->getSourceElementType(), newPtr, indices);
+        replacements[constantExpr] = newGEP;
+        constantExpr->replaceAllUsesWith(newGEP);
+        continue;
+      }
+      llvm::Instruction *newInst = constantExpr->getAsInstruction();
+      builder.Insert(newInst);
+      replacements[constantExpr] = newInst;
+      constantExpr->replaceAllUsesWith(newInst);
+      continue;
+    }
+    use.set(newPtr);
+  }
+}
+
 void ModuleTranslation::remapAllValuesWith(llvm::Value *oldValue,
-                                           llvm::Value *newValue) {
+                                           llvm::Value *newValue,
+                                           llvm::IRBuilderBase *builder) {
   if (oldValue == newValue)
     return;
-  oldValue->replaceAllUsesWith(newValue);
-  for (auto &entry : valueMapping)
-    if (entry.second == oldValue)
+
+  llvm::DenseMap<llvm::Constant *, llvm::Value *> constantReplacements;
+  if (auto *constant = llvm::dyn_cast<llvm::Constant>(oldValue)) {
+    assert(builder &&
+           "IRBuilder required when remapping constant storage pointers");
+    remapConstantPointerUses(constant, newValue, *builder,
+                             constantReplacements);
+  } else {
+    oldValue->replaceAllUsesWith(newValue);
+  }
+
+  for (auto &entry : valueMapping) {
+    if (entry.second == oldValue) {
       entry.second = newValue;
+      continue;
+    }
+    if (auto *constant = llvm::dyn_cast<llvm::Constant>(entry.second))
+      if (llvm::Value *replacement = constantReplacements.lookup(constant))
+        entry.second = replacement;
+  }
 }
 
 llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
diff --git a/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir b/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
index 69ab9b6c00616..9cf2894daf8a0 100644
--- a/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
@@ -118,6 +118,25 @@ llvm.func @test_allocate_array_global() {
 
 // -----
 
+// Verifies that array size is correctly calculated from a stack alloca:
+// [10 x i32] = 40 bytes, rounded up to alignment 64 => 64 bytes.
+//
+// CHECK-LABEL: define void @test_allocate_array_stack
+// CHECK:   %[[TID:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   %[[ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %[[TID]], i64 64, i64 64, ptr null)
+// CHECK:   %[[TID_FREE:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   call void @__kmpc_free(i32 %[[TID_FREE]], ptr %[[ALLOC]], ptr null)
+// CHECK:   ret void
+llvm.func @test_allocate_array_stack() {
+  %one = llvm.mlir.constant(1 : i64) : i64
+  %arr = llvm.alloca %one x !llvm.array<10 x i32> : (i64) -> !llvm.ptr
+  omp.allocate_dir (%arr : !llvm.ptr) align(64)
+  omp.allocate_free (%arr : !llvm.ptr)
+  llvm.return
+}
+
+// -----
+
 // Verifies that loads and stores after omp.allocate_dir use the OMP-allocated
 // pointer rather than the original storage.
 //
@@ -137,3 +156,36 @@ llvm.func @test_allocate_use(%arg0: !llvm.ptr) {
   omp.allocate_free (%arg0 : !llvm.ptr)
   llvm.return
 }
+
+// -----
+
+// Verifies remapping when a global has multiple GEP users (COMMON block shape).
+//
+// CHECK-LABEL: define void @test_allocate_global_gep_users
+// CHECK:   %[[TID:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   %[[ALLOC:.*]] = call ptr @__kmpc_alloc(i32 %[[TID]], i64 8, ptr null)
+// CHECK:   %[[GEP4:.*]] = getelementptr i8, ptr %[[ALLOC]], i64 4
+// CHECK:   store i32 1, ptr %[[ALLOC]], align 4
+// CHECK:   store i32 2, ptr %[[GEP4]], align 4
+// CHECK:   %[[TID_FREE:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK:   call void @__kmpc_free(i32 %[[TID_FREE]], ptr %[[ALLOC]], ptr null)
+// CHECK:   ret void
+llvm.mlir.global internal @common_like() : !llvm.array<2 x i32> {
+  %0 = llvm.mlir.zero : !llvm.array<2 x i32>
+  llvm.return %0 : !llvm.array<2 x i32>
+}
+
+llvm.func @test_allocate_global_gep_users() {
+  %base = llvm.mlir.addressof @common_like : !llvm.ptr
+  %c0 = llvm.mlir.constant(0 : i64) : i64
+  %c1 = llvm.mlir.constant(1 : i64) : i64
+  %m0 = llvm.getelementptr %base[%c0, %c0] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<2 x i32>
+  %m1 = llvm.getelementptr %base[%c0, %c1] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<2 x i32>
+  omp.allocate_dir (%base : !llvm.ptr)
+  %one = llvm.mlir.constant(1 : i32) : i32
+  %two = llvm.mlir.constant(2 : i32) : i32
+  llvm.store %one, %m0 : i32, !llvm.ptr
+  llvm.store %two, %m1 : i32, !llvm.ptr
+  omp.allocate_free (%base : !llvm.ptr)
+  llvm.return
+}

>From 910fc5870d293f161d331dc9a54f36f6897db79d Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Mon, 27 Jul 2026 16:48:21 -0500
Subject: [PATCH 3/5] Add a TODO warning about lowering of SAVE attribute or
 named COMMON block variables are not completely supported on ALLOCATE
 directive.

---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 35 ++++++++++++++-----
 .../omp-declarative-allocate-save-warning.f90 | 34 ++++++++++++++++++
 2 files changed, 61 insertions(+), 8 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index b4fa431d42223..65bdf463f55bf 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2905,19 +2905,40 @@ static void genWsloopClauses(
 //===----------------------------------------------------------------------===//
 // Code generation functions for leaf constructs
 //===----------------------------------------------------------------------===//
-static mlir::omp::AllocateDirOp genAllocateDirOp(
+
+static void genAllocateDirOp(
     lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
     lower::StatementContext &stmtCtx, lower::pft::Evaluation &eval,
     mlir::Location loc, const ObjectList &objects, const ConstructQueue &queue,
     ConstructQueue::const_iterator item) {
+  ObjectList supportedObjects;
+  supportedObjects.reserve(objects.size());
+  for (const Object &object : objects) {
+    const semantics::Symbol *sym = object.sym();
+    assert(sym && "Expected Symbol");
+    const semantics::Symbol &ultimate = sym->GetUltimate();
+    if (semantics::omp::IsCommonBlock(ultimate) ||
+        ultimate.attrs().test(semantics::Attr::SAVE)) {
+      mlir::emitWarning(loc,
+                "TODO : OpenMP declarative ALLOCATE on SAVE variables or "
+                "COMMON blocks is not yet supported, ignoring the ALLOCATE "
+                "directive for '" + sym->name().ToString() + "'");
+      continue;
+    }
+    supportedObjects.push_back(object);
+  }
+
+  if (supportedObjects.empty())
+    return;
+
   llvm::SmallVector<mlir::Value> operandRange;
   mlir::omp::AllocateDirOperands clauseOps;
-  genAllocateClauses(converter, semaCtx, stmtCtx, objects, item->clauses, loc,
-                     operandRange, clauseOps);
+  genAllocateClauses(converter, semaCtx, stmtCtx, supportedObjects,
+                     item->clauses, loc, operandRange, clauseOps);
 
-  auto allocDirOp = mlir::omp::AllocateDirOp::create(
-      converter.getFirOpBuilder(), loc, operandRange, clauseOps.align,
-      clauseOps.allocator);
+  mlir::omp::AllocateDirOp::create(converter.getFirOpBuilder(), loc,
+                                   operandRange, clauseOps.align,
+                                   clauseOps.allocator);
 
   // Register a cleanup at the Fortran scope exit.
   fir::FirOpBuilder *builder = &converter.getFirOpBuilder();
@@ -2926,8 +2947,6 @@ static mlir::omp::AllocateDirOp genAllocateDirOp(
                                        allocator]() {
     mlir::omp::AllocateFreeOp::create(*builder, loc, operandRange, allocator);
   });
-
-  return allocDirOp;
 }
 
 static mlir::omp::BarrierOp
diff --git a/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90 b/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
new file mode 100644
index 0000000000000..f9bd360d78c36
--- /dev/null
+++ b/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
@@ -0,0 +1,34 @@
+! Verify that declarative ALLOCATE on SAVE variables or named COMMON blocks
+! emits a lowering warning and does not generate omp.allocate_dir /
+! omp.allocate_free for those variables.
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - 2>&1 | FileCheck %s
+
+subroutine save_allocate_warning
+  use omp_lib
+  implicit none
+  integer, save :: counter = 100
+
+  !$omp allocate(counter) allocator(omp_default_mem_alloc)
+end subroutine save_allocate_warning
+
+subroutine common_allocate_warning
+  use omp_lib
+  implicit none
+  real :: cb_a, cb_b
+  common /myblock/ cb_a, cb_b
+
+  !$omp allocate(/myblock/) allocator(omp_default_mem_alloc)
+end subroutine common_allocate_warning
+
+! Warnings are emitted during lowering before HLFIR is printed.
+! CHECK: warning: {{.*}}TODO : OpenMP declarative ALLOCATE on SAVE variables or COMMON blocks is not yet supported, ignoring the ALLOCATE directive for 'counter'
+! CHECK: warning: {{.*}}TODO : OpenMP declarative ALLOCATE on SAVE variables or COMMON blocks is not yet supported, ignoring the ALLOCATE directive for 'myblock'
+
+! CHECK-LABEL: func.func @_QPsave_allocate_warning
+! CHECK-NOT: omp.allocate_dir
+! CHECK-NOT: omp.allocate_free
+
+! CHECK-LABEL: func.func @_QPcommon_allocate_warning
+! CHECK-NOT: omp.allocate_dir
+! CHECK-NOT: omp.allocate_free

>From cf7aa2a0fa21f3056fe38ea1045de9b9c07cb505 Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Mon, 27 Jul 2026 16:52:12 -0500
Subject: [PATCH 4/5] Apply clang-format changes.

---
 flang/lib/Lower/OpenMP/OpenMP.cpp | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 65bdf463f55bf..7271a9c1525a9 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2906,11 +2906,13 @@ static void genWsloopClauses(
 // Code generation functions for leaf constructs
 //===----------------------------------------------------------------------===//
 
-static void genAllocateDirOp(
-    lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
-    lower::StatementContext &stmtCtx, lower::pft::Evaluation &eval,
-    mlir::Location loc, const ObjectList &objects, const ConstructQueue &queue,
-    ConstructQueue::const_iterator item) {
+static void genAllocateDirOp(lower::AbstractConverter &converter,
+                             semantics::SemanticsContext &semaCtx,
+                             lower::StatementContext &stmtCtx,
+                             lower::pft::Evaluation &eval, mlir::Location loc,
+                             const ObjectList &objects,
+                             const ConstructQueue &queue,
+                             ConstructQueue::const_iterator item) {
   ObjectList supportedObjects;
   supportedObjects.reserve(objects.size());
   for (const Object &object : objects) {
@@ -2919,10 +2921,11 @@ static void genAllocateDirOp(
     const semantics::Symbol &ultimate = sym->GetUltimate();
     if (semantics::omp::IsCommonBlock(ultimate) ||
         ultimate.attrs().test(semantics::Attr::SAVE)) {
-      mlir::emitWarning(loc,
-                "TODO : OpenMP declarative ALLOCATE on SAVE variables or "
-                "COMMON blocks is not yet supported, ignoring the ALLOCATE "
-                "directive for '" + sym->name().ToString() + "'");
+      mlir::emitWarning(
+          loc, "TODO : OpenMP declarative ALLOCATE on SAVE variables or "
+               "COMMON blocks is not yet supported, ignoring the ALLOCATE "
+               "directive for '" +
+                   sym->name().ToString() + "'");
       continue;
     }
     supportedObjects.push_back(object);

>From ac8e411f13fe1add4b692de77bab3a45999d3939 Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Mon, 27 Jul 2026 23:19:38 -0500
Subject: [PATCH 5/5] Fix windows build test failure.

---
 .../OpenMP/omp-declarative-allocate-save-warning.f90      | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90 b/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
index f9bd360d78c36..a3b145c429395 100644
--- a/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
+++ b/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
@@ -2,23 +2,21 @@
 ! emits a lowering warning and does not generate omp.allocate_dir /
 ! omp.allocate_free for those variables.
 
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir %openmp_flags %s -o - 2>&1 | FileCheck %s
 
 subroutine save_allocate_warning
-  use omp_lib
   implicit none
   integer, save :: counter = 100
 
-  !$omp allocate(counter) allocator(omp_default_mem_alloc)
+  !$omp allocate(counter) allocator(1)
 end subroutine save_allocate_warning
 
 subroutine common_allocate_warning
-  use omp_lib
   implicit none
   real :: cb_a, cb_b
   common /myblock/ cb_a, cb_b
 
-  !$omp allocate(/myblock/) allocator(omp_default_mem_alloc)
+  !$omp allocate(/myblock/) allocator(1)
 end subroutine common_allocate_warning
 
 ! Warnings are emitted during lowering before HLFIR is printed.



More information about the flang-commits mailing list