[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
Tue Sep 1 09:15:06 PDT 2026
https://github.com/raghavendhra updated https://github.com/llvm/llvm-project/pull/212361
>From 4e73a5f22f45f6161101bd16be06933910c70c07 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/7] [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 6db1951dbdd35..0bb679d53c8fd 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -102,6 +102,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 e23cda41ded81..24f9bafbc3fca 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -10282,6 +10282,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 5bb42575a0955..063f2ecd550cc 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -2538,6 +2538,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 31353fbcbaa85b94c4a194abc8fcce59c55da1d6 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/7] 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 0bb679d53c8fd..1693ec82cd392 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -102,8 +102,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 24f9bafbc3fca..fe0efa4dd99c4 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -6919,6 +6919,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,
@@ -10230,21 +10288,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)) {
@@ -10287,11 +10338,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 063f2ecd550cc..18b1c48c0172d 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"
@@ -2538,14 +2540,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 106871ac8930b2134b33e849678f828cf6e27695 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/7] 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 3b121a4673c23..3e29030a47223 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2791,19 +2791,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();
@@ -2812,8 +2833,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 ca08a9e501558fd6fadcdca0d09577b9647e1d8d 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/7] 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 3e29030a47223..708585441997e 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2792,11 +2792,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) {
@@ -2805,10 +2807,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 b387043ebef9288bce549c944b952cd276befca2 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/7] 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.
>From 2b0a3c6daea26811979a1db92230ec38a5bb2ede Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Thu, 13 Aug 2026 17:01:21 -0500
Subject: [PATCH 6/7] Addressed review comments.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 2 +-
.../OpenMP/omp-declarative-allocate-align.f90 | 10 +--
.../omp-declarative-allocate-save-warning.f90 | 12 ++++
.../mlir/Target/LLVMIR/ModuleTranslation.h | 8 +--
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 23 +++----
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 52 +-------------
.../LLVMIR/openmp-allocate-directive.mlir | 67 +++++++++++++------
7 files changed, 83 insertions(+), 91 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 708585441997e..acaef6554dfc9 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2806,7 +2806,7 @@ static void genAllocateDirOp(lower::AbstractConverter &converter,
assert(sym && "Expected Symbol");
const semantics::Symbol &ultimate = sym->GetUltimate();
if (semantics::omp::IsCommonBlock(ultimate) ||
- ultimate.attrs().test(semantics::Attr::SAVE)) {
+ semantics::IsSaved(ultimate)) {
mlir::emitWarning(
loc, "TODO : OpenMP declarative ALLOCATE on SAVE variables or "
"COMMON blocks is not yet supported, ignoring the ALLOCATE "
diff --git a/flang/test/Lower/OpenMP/omp-declarative-allocate-align.f90 b/flang/test/Lower/OpenMP/omp-declarative-allocate-align.f90
index fdcc4ac1fef20..95e07f23adc20 100644
--- a/flang/test/Lower/OpenMP/omp-declarative-allocate-align.f90
+++ b/flang/test/Lower/OpenMP/omp-declarative-allocate-align.f90
@@ -10,7 +10,7 @@
program main
integer :: x, y
- integer :: z(10)
+ integer :: z(5)
character c
real :: r
complex :: cmplx
@@ -35,17 +35,17 @@ program main
! CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_ALLOC]] {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[Y_ALLOC:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"}
! CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y_ALLOC]] {uniq_name = "_QFEy"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[Z_REF:.*]] = fir.address_of(@_QFEz) : !fir.ref<!fir.array<10xi32>>
-! CHECK: %[[Z_DECL:.*]]:2 = hlfir.declare %[[Z_REF]]({{.*}}) {uniq_name = "_QFEz"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+! CHECK: %[[Z_ALLOC:.*]] = fir.alloca !fir.array<5xi32> {bindc_name = "z", uniq_name = "_QFEz"}
+! CHECK: %[[Z_DECL:.*]]:2 = hlfir.declare %[[Z_ALLOC]]({{.*}}) {uniq_name = "_QFEz"} : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>)
! CHECK: omp.allocate_dir(%[[X_DECL]]#0 : !fir.ref<i32>) align(16)
! CHECK: %[[ALLOC1:.*]] = arith.constant 1 : i32
! CHECK: omp.allocate_dir(%[[Y_DECL]]#0 : !fir.ref<i32>) allocator(%[[ALLOC1]] : i32)
! CHECK: %[[ALLOC6:.*]] = arith.constant 6 : i32
-! CHECK: omp.allocate_dir(%[[Z_DECL]]#0 : !fir.ref<!fir.array<10xi32>>) align(64) allocator(%[[ALLOC6]] : i32)
+! CHECK: omp.allocate_dir(%[[Z_DECL]]#0 : !fir.ref<!fir.array<5xi32>>) align(64) allocator(%[[ALLOC6]] : i32)
! CHECK: %[[ALLOC3:.*]] = arith.constant 3 : i32
! CHECK: omp.allocate_dir(%[[C_DECL]]#0, %[[R_DECL]]#0, %[[CMPLX_DECL]]#0 : !fir.ref<!fir.char<1>>, !fir.ref<f32>, !fir.ref<complex<f32>>) align(32) allocator(%[[ALLOC3]] : i32)
! CHECK: omp.allocate_free(%[[C_DECL]]#0, %[[R_DECL]]#0, %[[CMPLX_DECL]]#0 : !fir.ref<!fir.char<1>>, !fir.ref<f32>, !fir.ref<complex<f32>>) allocator(%[[ALLOC3]] : i32)
-! CHECK: omp.allocate_free(%[[Z_DECL]]#0 : !fir.ref<!fir.array<10xi32>>) allocator(%[[ALLOC6]] : i32)
+! CHECK: omp.allocate_free(%[[Z_DECL]]#0 : !fir.ref<!fir.array<5xi32>>) allocator(%[[ALLOC6]] : i32)
! CHECK: omp.allocate_free(%[[Y_DECL]]#0 : !fir.ref<i32>) allocator(%[[ALLOC1]] : i32)
! CHECK: omp.allocate_free(%[[X_DECL]]#0 : !fir.ref<i32>)
! CHECK: return
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 a3b145c429395..f70cae6ebeefb 100644
--- a/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
+++ b/flang/test/Lower/OpenMP/omp-declarative-allocate-save-warning.f90
@@ -11,6 +11,13 @@ subroutine save_allocate_warning
!$omp allocate(counter) allocator(1)
end subroutine save_allocate_warning
+subroutine implicit_save_allocate_warning
+ implicit none
+ integer :: implicit_counter = 100
+
+ !$omp allocate(implicit_counter) allocator(1)
+end subroutine implicit_save_allocate_warning
+
subroutine common_allocate_warning
implicit none
real :: cb_a, cb_b
@@ -21,12 +28,17 @@ 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 'implicit_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 @_QPimplicit_save_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
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 1693ec82cd392..b6823a21ebd96 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -102,10 +102,10 @@ class ModuleTranslation {
return valueMapping.lookup(value);
}
- /// 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);
+ /// Remap old value with new value in the MLIR-to-LLVM value map so later
+ /// translations use the replacement. Existing LLVM instructions are not
+ /// rewritten.
+ 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 fe0efa4dd99c4..84c4784e1f268 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -6923,13 +6923,12 @@ static Value getBaseValueForTypeLookup(Value value) {
// 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,
+getAllocatedLlvmTypeForVariable(Value var, Value baseVar,
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());
@@ -6947,17 +6946,17 @@ getAllocatedLlvmTypeForVariable(Value var,
// 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);
+static std::optional<llvm::Value *> getDynamicAllocatedSize(
+ Value var, Value baseVar, LLVM::ModuleTranslation &moduleTranslation,
+ llvm::IRBuilderBase &builder, const llvm::DataLayout &dataLayout) {
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);
+ if (!numElems->getType()->isIntegerTy(64))
+ numElems = builder.CreateZExt(numElems, builder.getInt64Ty());
uint64_t elemSize = dataLayout.getTypeStoreSize(elemTy).getFixedValue();
return builder.CreateMul(numElems, builder.getInt64(elemSize));
}
@@ -10288,12 +10287,13 @@ convertAllocateDirOp(Operation &opInst, llvm::IRBuilderBase &builder,
}
for (Value var : vars) {
+ Value baseVar = getBaseValueForTypeLookup(var);
llvm::Type *typeToInspect =
- getAllocatedLlvmTypeForVariable(var, moduleTranslation);
+ getAllocatedLlvmTypeForVariable(var, baseVar, moduleTranslation);
llvm::Value *size;
if (std::optional<llvm::Value *> dynamicSize = getDynamicAllocatedSize(
- var, moduleTranslation, builder, dataLayout)) {
+ var, baseVar, moduleTranslation, builder, dataLayout)) {
size = *dynamicSize;
} else if (auto arrTy = llvm::dyn_cast<llvm::ArrayType>(typeToInspect)) {
llvm::Value *elementCount = builder.getInt64(1);
@@ -10334,15 +10334,14 @@ 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, &builder);
+ moduleTranslation.remapAllValuesWith(baseLlvm, boundPtr);
} else if (llvm::Value *varLlvm = moduleTranslation.lookupValue(var)) {
llvm::Value *boundPtr = builder.CreatePointerBitCastOrAddrSpaceCast(
allocCall, varLlvm->getType());
- moduleTranslation.remapAllValuesWith(varLlvm, boundPtr, &builder);
+ moduleTranslation.remapAllValuesWith(varLlvm, boundPtr);
}
}
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 18b1c48c0172d..f0390d5a5f642 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -43,11 +43,9 @@
#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"
@@ -2540,58 +2538,14 @@ 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::IRBuilderBase *builder) {
+ llvm::Value *newValue) {
if (oldValue == newValue)
return;
- 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) {
+ 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 9cf2894daf8a0..c9e33432918ca 100644
--- a/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-allocate-directive.mlir
@@ -159,33 +159,60 @@ llvm.func @test_allocate_use(%arg0: !llvm.ptr) {
// -----
-// Verifies remapping when a global has multiple GEP users (COMMON block shape).
+// Verifies that a use before omp.allocate_dir keeps the original storage while
+// later uses go through the OMP-allocated pointer.
//
-// CHECK-LABEL: define void @test_allocate_global_gep_users
+// CHECK-LABEL: define void @test_allocate_use_before
+// CHECK-SAME: (ptr %[[ARG0:.*]])
+// CHECK: %[[PRE:.*]] = load i32, ptr %[[ARG0]]
// 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: store i32 42, 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.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_use_before(%arg0: !llvm.ptr) {
+ %pre = llvm.load %arg0 : !llvm.ptr -> i32
+ omp.allocate_dir (%arg0 : !llvm.ptr)
+ %c42 = llvm.mlir.constant(42 : i32) : i32
+ llvm.store %c42, %arg0 : i32, !llvm.ptr
+ omp.allocate_free (%arg0 : !llvm.ptr)
+ llvm.return
}
-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)
+// -----
+
+// Verifies dynamic array size with an i32 element count on llvm.alloca.
+//
+// CHECK-LABEL: define void @test_allocate_dynamic_i32_count
+// CHECK: %[[TID:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_alloc(i32 %[[TID]], i64 40, 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_dynamic_i32_count() {
+ %count = llvm.mlir.constant(10 : i32) : i32
+ %arr = llvm.alloca %count x i32 : (i32) -> !llvm.ptr
+ omp.allocate_dir (%arr : !llvm.ptr)
+ omp.allocate_free (%arr : !llvm.ptr)
+ llvm.return
+}
+
+// -----
+
+// Verifies runtime dynamic array size from a stack alloca: count * 4 bytes.
+//
+// CHECK-LABEL: define void @test_allocate_dynamic_runtime_count
+// CHECK-SAME: (i64 %[[COUNT:.*]])
+// CHECK: %[[MUL:.*]] = mul i64 %[[COUNT]], 4
+// CHECK: %[[TID:.*]] = call i32 @__kmpc_global_thread_num(
+// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_alloc(i32 %[[TID]], i64 {{.*}}, 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_dynamic_runtime_count(%count: i64) {
+ %arr = llvm.alloca %count x i32 : (i64) -> !llvm.ptr
+ omp.allocate_dir (%arr : !llvm.ptr)
+ omp.allocate_free (%arr : !llvm.ptr)
llvm.return
}
>From 001f1e07b1d472eb3a0902c988b07a4e55d7f1ee Mon Sep 17 00:00:00 2001
From: Raghu Maddhipatla <Raghu.Maddhipatla at amd.com>
Date: Mon, 31 Aug 2026 10:44:08 -0500
Subject: [PATCH 7/7] Add a warning for list items which are derived-type that
require initialization or finalization.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 20 ++++++++
...p-declarative-allocate-derived-warning.f90 | 46 +++++++++++++++++++
2 files changed, 66 insertions(+)
create mode 100644 flang/test/Lower/OpenMP/omp-declarative-allocate-derived-warning.f90
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index acaef6554dfc9..1fc382d217db9 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2792,6 +2792,18 @@ static void genWsloopClauses(
// Code generation functions for leaf constructs
//===----------------------------------------------------------------------===//
+static bool
+allocateRequiresInitOrFinalization(const semantics::Symbol &ultimate) {
+ const semantics::DeclTypeSpec *declTypeSpec = ultimate.GetType();
+ if (!declTypeSpec)
+ return false;
+ const semantics::DerivedTypeSpec *derivedTypeSpec = declTypeSpec->AsDerived();
+ if (!derivedTypeSpec)
+ return false;
+ return derivedTypeSpec->HasDefaultInitialization(false, false) ||
+ semantics::MayRequireFinalization(*derivedTypeSpec);
+}
+
static void genAllocateDirOp(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
lower::StatementContext &stmtCtx,
@@ -2814,6 +2826,14 @@ static void genAllocateDirOp(lower::AbstractConverter &converter,
sym->name().ToString() + "'");
continue;
}
+ if (allocateRequiresInitOrFinalization(ultimate)) {
+ mlir::emitWarning(
+ loc, "TODO : OpenMP declarative ALLOCATE on derived-type "
+ "variables with initialization or finalization is not yet "
+ "supported, ignoring the ALLOCATE directive for '" +
+ sym->name().ToString() + "'");
+ continue;
+ }
supportedObjects.push_back(object);
}
diff --git a/flang/test/Lower/OpenMP/omp-declarative-allocate-derived-warning.f90 b/flang/test/Lower/OpenMP/omp-declarative-allocate-derived-warning.f90
new file mode 100644
index 0000000000000..ed1d6db6cbfa1
--- /dev/null
+++ b/flang/test/Lower/OpenMP/omp-declarative-allocate-derived-warning.f90
@@ -0,0 +1,46 @@
+! Verify that declarative ALLOCATE on derived-type variables that require
+! default initialization or finalization emits a lowering warning and does
+! not generate omp.allocate_dir / omp.allocate_free for those variables.
+
+! RUN: %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 %s -o - 2>&1 | FileCheck %s
+
+module derived_allocate_warning
+ type :: init_type
+ integer :: k = 42
+ end type
+
+ type :: final_type
+ integer :: a
+ contains
+ final :: final_type_cleanup
+ end type
+
+contains
+ subroutine final_type_cleanup(this)
+ type(final_type) :: this
+ end subroutine
+
+ subroutine init_allocate_warning
+ type(init_type) :: obj
+
+ !$omp allocate(obj) allocator(1)
+ end subroutine init_allocate_warning
+
+ subroutine final_allocate_warning
+ type(final_type) :: obj
+
+ !$omp allocate(obj) allocator(1)
+ end subroutine final_allocate_warning
+end module derived_allocate_warning
+
+! Warnings are emitted during lowering before HLFIR is printed.
+! CHECK: warning: {{.*}}TODO : OpenMP declarative ALLOCATE on derived-type variables with initialization or finalization is not yet supported, ignoring the ALLOCATE directive for 'obj'
+! CHECK: warning: {{.*}}TODO : OpenMP declarative ALLOCATE on derived-type variables with initialization or finalization is not yet supported, ignoring the ALLOCATE directive for 'obj'
+
+! CHECK-LABEL: func.func @_QMderived_allocate_warningPinit_allocate_warning
+! CHECK-NOT: omp.allocate_dir
+! CHECK-NOT: omp.allocate_free
+
+! CHECK-LABEL: func.func @_QMderived_allocate_warningPfinal_allocate_warning
+! CHECK-NOT: omp.allocate_dir
+! CHECK-NOT: omp.allocate_free
More information about the flang-commits
mailing list