[flang-commits] [flang] [mlir] [flang][OpenMP] Lower align modifiers on allocate clauses (PR #211624)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Tue Aug 4 03:38:20 PDT 2026


https://github.com/Saieiei updated https://github.com/llvm/llvm-project/pull/211624

>From 7ee61c6a3fa0707fd6acba501fde9d4ed60558af Mon Sep 17 00:00:00 2001
From: Sairudra More <sairudra60 at gmail.com>
Date: Thu, 23 Jul 2026 09:15:41 -0500
Subject: [PATCH] [flang][OpenMP] Lower allocate align modifier on parallel

Lower the align modifier on OpenMP allocate clauses for parallel constructs.
Carry per-item alignments through the OpenMP dialect and select
__kmpc_aligned_alloc for aligned private storage while retaining the existing
allocation and cleanup behavior for unaligned items.

Add source, verifier, preservation, LLVM IR, i386 ABI, and overflow coverage.
Keep unsupported construct kinds and device lowering unchanged.

Assisted-by: GitHub Copilot
---
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |  29 ++--
 flang/lib/Lower/OpenMP/ClauseProcessor.h      |   3 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |   2 +-
 .../Optimizer/OpenMP/LowerWorkdistribute.cpp  |  36 ++---
 flang/lib/Semantics/check-omp-structure.cpp   |   3 +
 .../OpenMP/Todo/allocate-clause-align.f90     |  13 --
 .../Todo/allocate-clause-unsupported.f90      |  12 +-
 .../OpenMP/allocate-clause-allocator.f90      |  19 +++
 .../Semantics/OpenMP/allocate-clause01.f90    |  25 ++++
 .../lower-workdistribute-fission-target.mlir  |   3 +-
 .../mlir/Dialect/OpenMP/OpenMPClauses.td      |   8 +-
 .../Conversion/SCFToOpenMP/SCFToOpenMP.cpp    |   1 +
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  | 130 +++++++++++-------
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      |  24 +++-
 .../Dialect/OpenMP/host-op-filtering.mlir     |   4 +-
 mlir/test/Dialect/OpenMP/invalid.mlir         |  52 +++++++
 mlir/test/Dialect/OpenMP/ops.mlir             |   4 +-
 .../Target/LLVMIR/openmp-allocate-clause.mlir | 125 +++++++++++++++--
 18 files changed, 383 insertions(+), 110 deletions(-)
 delete mode 100644 flang/test/Lower/OpenMP/Todo/allocate-clause-align.f90

diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index f912c2af15d67..2f45b70db8fe6 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -94,11 +94,11 @@ getSimdModifier(const omp::clause::Schedule &clause) {
   return mlir::omp::ScheduleModifier::none;
 }
 
-static void
-genAllocateClause(lower::AbstractConverter &converter,
-                  const omp::clause::Allocate &clause,
-                  llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
-                  llvm::SmallVectorImpl<mlir::Value> &allocateOperands) {
+static void genAllocateClause(
+    lower::AbstractConverter &converter, const omp::clause::Allocate &clause,
+    llvm::SmallVectorImpl<mlir::Value> &allocatorOperands,
+    llvm::SmallVectorImpl<mlir::Value> &allocateOperands,
+    llvm::SmallVectorImpl<int64_t> &alignments, bool supportAlignment) {
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
   mlir::Location currentLocation = converter.getCurrentLocation();
   lower::StatementContext stmtCtx;
@@ -106,10 +106,18 @@ genAllocateClause(lower::AbstractConverter &converter,
   auto &objects = std::get<omp::ObjectList>(clause.t);
 
   using Allocate = omp::clause::Allocate;
-  // ALIGN in this context is unimplemented
-  if (std::get<std::optional<Allocate::AlignModifier>>(clause.t))
+  auto &align = std::get<std::optional<Allocate::AlignModifier>>(clause.t);
+  if (align && !supportAlignment)
     TODO(currentLocation, "OmpAllocateClause ALIGN modifier");
 
+  if (align) {
+    if (alignments.empty())
+      alignments.resize(allocateOperands.size(), 0);
+    alignments.append(objects.size(), evaluate::ToInt64(align->v).value());
+  } else if (!alignments.empty()) {
+    alignments.append(objects.size(), 0);
+  }
+
   // Use a null handle to select the binding task's default allocator.
   using ComplexModifier = Allocate::AllocatorComplexModifier;
   if (auto &mod = std::get<std::optional<ComplexModifier>>(clause.t)) {
@@ -1136,12 +1144,13 @@ bool ClauseProcessor::processAligned(
       });
 }
 
-bool ClauseProcessor::processAllocate(
-    mlir::omp::AllocateClauseOps &result) const {
+bool ClauseProcessor::processAllocate(mlir::omp::AllocateClauseOps &result,
+                                      bool supportAlignment) const {
   return findRepeatableClause<omp::clause::Allocate>(
       [&](const omp::clause::Allocate &clause, const parser::CharBlock &) {
         genAllocateClause(converter, clause, result.allocatorVars,
-                          result.allocateVars);
+                          result.allocateVars, result.allocateAlignments,
+                          supportAlignment);
       });
 }
 
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index cb42b6524e2e7..2a78cd52ee633 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -129,7 +129,8 @@ class ClauseProcessor {
   // 'Repeatable' clauses: They can appear multiple times in the clause list.
   bool processAffinity(mlir::omp::AffinityClauseOps &result) const;
   bool processAligned(mlir::omp::AlignedClauseOps &result) const;
-  bool processAllocate(mlir::omp::AllocateClauseOps &result) const;
+  bool processAllocate(mlir::omp::AllocateClauseOps &result,
+                       bool supportAlignment = false) const;
   bool processCopyin() const;
   bool processCopyprivate(mlir::Location currentLocation,
                           mlir::omp::CopyprivateClauseOps &result) const;
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 1ac2d254d14e9..3876799b3a081 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2544,7 +2544,7 @@ static void genParallelClauses(
     mlir::Location loc, mlir::omp::ParallelOperands &clauseOps,
     llvm::SmallVectorImpl<Object> &reductionObjects) {
   ClauseProcessor cp(converter, semaCtx, clauses);
-  cp.processAllocate(clauseOps);
+  cp.processAllocate(clauseOps, /*supportAlignment=*/true);
   cp.processIf(llvm::omp::Directive::OMPD_parallel, clauseOps);
 
   HostEvalInfo *hostEvalInfo = getHostEvalInfoStackTop(converter);
diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
index 5c42632d0c5fb..68e997e3abde4 100644
--- a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
+++ b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
@@ -757,10 +757,11 @@ FailureOr<omp::TargetOp> splitTargetData(omp::TargetOp targetOp,
   // Create the inner target op
   auto newTargetOp = omp::TargetOp::create(
       rewriter, targetOp.getLoc(), targetOp.getAllocateVars(),
-      targetOp.getAllocatorVars(), targetOp.getAllocatePrivateIndicesAttr(),
-      targetOp.getDependKindsAttr(), targetOp.getDependVars(),
-      targetOp.getDependIteratedKindsAttr(), targetOp.getDependIterated(),
-      targetOp.getDevice(), targetOp.getDynGroupprivateAccessGroupAttr(),
+      targetOp.getAllocatorVars(), targetOp.getAllocateAlignmentsAttr(),
+      targetOp.getAllocatePrivateIndicesAttr(), targetOp.getDependKindsAttr(),
+      targetOp.getDependVars(), targetOp.getDependIteratedKindsAttr(),
+      targetOp.getDependIterated(), targetOp.getDevice(),
+      targetOp.getDynGroupprivateAccessGroupAttr(),
       targetOp.getDynGroupprivateFallbackAttr(),
       targetOp.getDynGroupprivateSize(), targetOp.getHasDeviceAddrVars(),
       targetOp.getHostEvalVars(), targetOp.getIfExpr(),
@@ -1482,10 +1483,11 @@ genPreTargetOp(omp::TargetOp targetOp, SmallVector<Value> &preMapOperands,
   // update the hostEvalVars of preTargetOp
   omp::TargetOp preTargetOp = omp::TargetOp::create(
       rewriter, targetOp.getLoc(), targetOp.getAllocateVars(),
-      targetOp.getAllocatorVars(), targetOp.getAllocatePrivateIndicesAttr(),
-      targetOp.getDependKindsAttr(), targetOp.getDependVars(),
-      targetOp.getDependIteratedKindsAttr(), targetOp.getDependIterated(),
-      targetOp.getDevice(), targetOp.getDynGroupprivateAccessGroupAttr(),
+      targetOp.getAllocatorVars(), targetOp.getAllocateAlignmentsAttr(),
+      targetOp.getAllocatePrivateIndicesAttr(), targetOp.getDependKindsAttr(),
+      targetOp.getDependVars(), targetOp.getDependIteratedKindsAttr(),
+      targetOp.getDependIterated(), targetOp.getDevice(),
+      targetOp.getDynGroupprivateAccessGroupAttr(),
       targetOp.getDynGroupprivateFallbackAttr(),
       targetOp.getDynGroupprivateSize(), targetOp.getHasDeviceAddrVars(),
       preHostEvalVars, targetOp.getIfExpr(), targetOp.getInReductionVars(),
@@ -1576,10 +1578,11 @@ genIsolatedTargetOp(omp::TargetOp targetOp, SmallVector<Value> &postMapOperands,
   // Create the isolated target op
   omp::TargetOp isolatedTargetOp = omp::TargetOp::create(
       rewriter, targetOp.getLoc(), targetOp.getAllocateVars(),
-      targetOp.getAllocatorVars(), targetOp.getAllocatePrivateIndicesAttr(),
-      targetOp.getDependKindsAttr(), targetOp.getDependVars(),
-      targetOp.getDependIteratedKindsAttr(), targetOp.getDependIterated(),
-      targetOp.getDevice(), targetOp.getDynGroupprivateAccessGroupAttr(),
+      targetOp.getAllocatorVars(), targetOp.getAllocateAlignmentsAttr(),
+      targetOp.getAllocatePrivateIndicesAttr(), targetOp.getDependKindsAttr(),
+      targetOp.getDependVars(), targetOp.getDependIteratedKindsAttr(),
+      targetOp.getDependIterated(), targetOp.getDevice(),
+      targetOp.getDynGroupprivateAccessGroupAttr(),
       targetOp.getDynGroupprivateFallbackAttr(),
       targetOp.getDynGroupprivateSize(), targetOp.getHasDeviceAddrVars(),
       isolatedHostEvalVars, targetOp.getIfExpr(), targetOp.getInReductionVars(),
@@ -1662,10 +1665,11 @@ static omp::TargetOp genPostTargetOp(omp::TargetOp targetOp,
   // Create the post target op
   omp::TargetOp postTargetOp = omp::TargetOp::create(
       rewriter, targetOp.getLoc(), targetOp.getAllocateVars(),
-      targetOp.getAllocatorVars(), targetOp.getAllocatePrivateIndicesAttr(),
-      targetOp.getDependKindsAttr(), targetOp.getDependVars(),
-      targetOp.getDependIteratedKindsAttr(), targetOp.getDependIterated(),
-      targetOp.getDevice(), targetOp.getDynGroupprivateAccessGroupAttr(),
+      targetOp.getAllocatorVars(), targetOp.getAllocateAlignmentsAttr(),
+      targetOp.getAllocatePrivateIndicesAttr(), targetOp.getDependKindsAttr(),
+      targetOp.getDependVars(), targetOp.getDependIteratedKindsAttr(),
+      targetOp.getDependIterated(), targetOp.getDevice(),
+      targetOp.getDynGroupprivateAccessGroupAttr(),
       targetOp.getDynGroupprivateFallbackAttr(),
       targetOp.getDynGroupprivateSize(), targetOp.getHasDeviceAddrVars(),
       postHostEvalVars, targetOp.getIfExpr(), targetOp.getInReductionVars(),
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 8e845fbf5993b..7bd5f1720fb3c 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2488,6 +2488,9 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) {
       if (const auto &v{GetIntValue(align->v)}; !v || *v <= 0) {
         context_.Say(OmpGetModifierSource(modifiers, align),
             "The alignment value should be a constant positive integer"_err_en_US);
+      } else if (!llvm::isPowerOf2_64(*v)) {
+        context_.Say(OmpGetModifierSource(modifiers, align),
+            "The alignment value should be a power of 2"_err_en_US);
       }
     }
   }
diff --git a/flang/test/Lower/OpenMP/Todo/allocate-clause-align.f90 b/flang/test/Lower/OpenMP/Todo/allocate-clause-align.f90
deleted file mode 100644
index b272d2e76d70c..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/allocate-clause-align.f90
+++ /dev/null
@@ -1,13 +0,0 @@
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: OmpAllocateClause ALIGN modifier
-program p
-  integer :: x
-  integer :: a
-  integer :: i
-  !$omp parallel private(x) allocate(align(4): x)
-  do i=1,10
-     a = a + i
-  end do
-  !$omp end parallel
-end program p
diff --git a/flang/test/Lower/OpenMP/Todo/allocate-clause-unsupported.f90 b/flang/test/Lower/OpenMP/Todo/allocate-clause-unsupported.f90
index 82b82fa6c33f1..72e83c6967642 100644
--- a/flang/test/Lower/OpenMP/Todo/allocate-clause-unsupported.f90
+++ b/flang/test/Lower/OpenMP/Todo/allocate-clause-unsupported.f90
@@ -5,6 +5,7 @@
 ! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 -o - %t/pointer.f90 2>&1 | FileCheck %s --check-prefix=POINTER
 ! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 -o - %t/allocatable.f90 2>&1 | FileCheck %s --check-prefix=ALLOCATABLE
 ! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 -o - %t/assumed-length.f90 2>&1 | FileCheck %s --check-prefix=ASSUMED-LENGTH
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir %openmp_flags -fopenmp-version=51 -o - %t/non-parallel.f90 2>&1 | FileCheck %s --check-prefix=NON-PARALLEL
 
 ! DUPLICATE: not yet implemented: ALLOCATE clause item appears more than once
 ! ARRAY: not yet implemented: ALLOCATE clause currently supports only fixed-size intrinsic scalar PRIVATE or FIRSTPRIVATE items
@@ -12,6 +13,7 @@
 ! POINTER: not yet implemented: ALLOCATE clause currently supports only fixed-size intrinsic scalar PRIVATE or FIRSTPRIVATE items
 ! ALLOCATABLE: not yet implemented: ALLOCATE clause currently supports only fixed-size intrinsic scalar PRIVATE or FIRSTPRIVATE items
 ! ASSUMED-LENGTH: not yet implemented: ALLOCATE clause currently supports only fixed-size intrinsic scalar PRIVATE or FIRSTPRIVATE items
+! NON-PARALLEL: not yet implemented: OmpAllocateClause ALIGN modifier
 
 !--- duplicate.f90
 subroutine duplicate(x)
@@ -29,6 +31,14 @@ subroutine pointer(x)
   !$omp end parallel
 end subroutine
 
+!--- non-parallel.f90
+subroutine non_parallel(x)
+  integer :: x
+  !$omp task private(x) allocate(align(64): x)
+    x = 1
+  !$omp end task
+end subroutine
+
 !--- allocatable.f90
 subroutine allocatable(x)
   integer, allocatable :: x
@@ -48,7 +58,7 @@ subroutine assumed_length(x)
 !--- array.f90
 subroutine array(x)
   integer :: x(4)
-  !$omp parallel private(x) allocate(x)
+  !$omp parallel private(x) allocate(align(64): x)
     x = 1
   !$omp end parallel
 end subroutine
diff --git a/flang/test/Lower/OpenMP/allocate-clause-allocator.f90 b/flang/test/Lower/OpenMP/allocate-clause-allocator.f90
index 79f8554dbdbda..09ac3993f5cec 100644
--- a/flang/test/Lower/OpenMP/allocate-clause-allocator.f90
+++ b/flang/test/Lower/OpenMP/allocate-clause-allocator.f90
@@ -135,3 +135,22 @@ subroutine allocator_common_block(y)
 ! HLFIR-SAME: private({{.*}} -> %{{.*}}, {{.*}} -> %{{.*}}, {{.*}} %[[Y]]#0 -> %{{.*}} :
 ! HLFIR-SAME: !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>) {
 ! HLFIR: } {allocate_private_indices = array<i64: 2>}
+
+subroutine allocator_alignment(x, y, z, w)
+  use omp_lib
+  integer :: x, y, z, w
+  !$omp parallel private(x, y, z) firstprivate(w) &
+  !$omp& allocate(x) &
+  !$omp& allocate(align(64): y, z) &
+  !$omp& allocate(allocator(omp_default_mem_alloc), align(128): w)
+    x = 1
+    y = 2
+    z = 3
+    w = w + 1
+  !$omp end parallel
+end subroutine
+
+! HLFIR-LABEL: func.func @_QPallocator_alignment
+! HLFIR: omp.parallel allocate(
+! HLFIR-SAME: private(
+! HLFIR: } {allocate_alignments = array<i64: 0, 64, 64, 128>, allocate_private_indices = array<i64: 0, 1, 2, 3>}
diff --git a/flang/test/Semantics/OpenMP/allocate-clause01.f90 b/flang/test/Semantics/OpenMP/allocate-clause01.f90
index b84b13df5aab0..d5e22871943fb 100644
--- a/flang/test/Semantics/OpenMP/allocate-clause01.f90
+++ b/flang/test/Semantics/OpenMP/allocate-clause01.f90
@@ -34,3 +34,28 @@ subroutine parallel_allocate(x, y)
         x = y
     !$omp end parallel
 end subroutine
+
+subroutine parallel_allocate_align(x, alignment)
+    integer, parameter :: cache_line = 64
+    integer :: x, alignment
+
+    !$omp parallel private(x) allocate(align(cache_line): x)
+        x = 1
+    !$omp end parallel
+
+    !ERROR: The alignment value should be a constant positive integer
+    !$omp parallel private(x) allocate(align(0): x)
+    !$omp end parallel
+
+    !ERROR: The alignment value should be a constant positive integer
+    !$omp parallel private(x) allocate(align(-4): x)
+    !$omp end parallel
+
+    !ERROR: The alignment value should be a constant positive integer
+    !$omp parallel private(x) allocate(align(alignment): x)
+    !$omp end parallel
+
+    !ERROR: The alignment value should be a power of 2
+    !$omp parallel private(x) allocate(align(24): x)
+    !$omp end parallel
+end subroutine
diff --git a/flang/test/Transforms/OpenMP/lower-workdistribute-fission-target.mlir b/flang/test/Transforms/OpenMP/lower-workdistribute-fission-target.mlir
index 4efc02e07c6d0..7354c89dfa321 100644
--- a/flang/test/Transforms/OpenMP/lower-workdistribute-fission-target.mlir
+++ b/flang/test/Transforms/OpenMP/lower-workdistribute-fission-target.mlir
@@ -62,7 +62,7 @@
 // CHECK:                 omp.terminator
 // CHECK:               } {omp.combined}
 // CHECK:               omp.terminator
-// CHECK:             } {allocate_private_indices = array<i64: 0>, omp.combined}
+// CHECK:             } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>, omp.combined}
 // CHECK:             %[[VAL_45:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:             %[[VAL_46:.*]] = fir.load %[[VAL_11]] : !fir.ref<index>
 // CHECK:             %[[VAL_47:.*]] = fir.load %[[VAL_14]] : !fir.ref<index>
@@ -96,6 +96,7 @@ func.func @x(%lb : index, %ub : index, %step : index, %addr : !fir.ref<index>) {
 
   "omp.target"(%addr, %allocator, %lb_map, %ub_map, %step_map, %addr_map, %addr) <{
       allocate_private_indices = array<i64: 0>,
+      allocate_alignments = array<i64: 64>,
       kernel_type = #omp<kernel_type(generic)>,
       operandSegmentSizes = array<i32: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0>,
       private_syms = [@addr_private]
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
index b6637d6df90e5..22296338b7915 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
@@ -114,6 +114,7 @@ class OpenMP_AllocateClauseSkip<
   let arguments = (ins
     Variadic<AnyType>:$allocate_vars,
     Variadic<AnyType>:$allocator_vars,
+    OptionalAttr<DenseI64ArrayAttr>:$allocate_alignments,
     OptionalAttr<DenseI64ArrayAttr>:$allocate_private_indices
   );
 
@@ -131,8 +132,11 @@ class OpenMP_AllocateClauseSkip<
   let description = [{
     The `allocate_vars` and `allocator_vars` parameters are parallel lists that
     pair each allocated private value with the allocator used to obtain its
-    storage. When present, `allocate_private_indices` maps each allocate variable
-    to the corresponding position in the operation's private variables.
+    storage. When present, `allocate_alignments` has one entry per allocate
+    variable; zero means omitted alignment, and nonzero entries must be powers
+    of two.
+    `allocate_private_indices` maps each allocate variable to the corresponding
+    position in the operation's private variables.
   }];
 }
 
diff --git a/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp b/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
index bdc428fc289f4..37a2b5046096a 100644
--- a/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
+++ b/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
@@ -503,6 +503,7 @@ struct ParallelOpLowering : public OpRewritePattern<scf::ParallelOp> {
         rewriter, loc,
         /* allocate_vars = */ llvm::SmallVector<Value>{},
         /* allocator_vars = */ llvm::SmallVector<Value>{},
+        /* allocate_alignments = */ nullptr,
         /* allocate_private_indices = */ nullptr,
         /* if_expr = */ Value{},
         /* num_threads_vars = */ numThreadsVars,
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 190014f2bab89..d941b62d13414 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -622,6 +622,7 @@ static void printAlignedClause(OpAsmPrinter &p, Operation *op,
 
 static LogicalResult verifyAllocateClause(
     Operation *op, ValueRange allocateVars, ValueRange allocatorVars,
+    DenseI64ArrayAttr allocateAlignments,
     DenseI64ArrayAttr allocatePrivateIndices, ValueRange privateVars = {},
     ArrayAttr privateSyms = nullptr, bool requirePrivateIndices = false) {
   if (allocateVars.size() != allocatorVars.size())
@@ -629,12 +630,29 @@ static LogicalResult verifyAllocateClause(
         "expected equal sizes for allocate and allocator variables");
 
   if (allocateVars.empty()) {
+    if (allocateAlignments)
+      return op->emitError(
+          "unexpected allocate alignments without allocate variables");
     if (allocatePrivateIndices)
       return op->emitError(
           "unexpected allocate private indices without allocate variables");
     return success();
   }
 
+  if (allocateAlignments) {
+    ArrayRef<int64_t> alignments = allocateAlignments.asArrayRef();
+    if (alignments.size() != allocateVars.size())
+      return op->emitError(
+          "expected as many allocate alignments as allocate variables");
+    for (int64_t alignment : alignments) {
+      if (alignment < 0)
+        return op->emitError("expected non-negative allocate alignments");
+      if (alignment != 0 && (alignment & (alignment - 1)) != 0)
+        return op->emitError(
+            "expected positive allocate alignments to be powers of two");
+    }
+  }
+
   if (!allocatePrivateIndices) {
     if (requirePrivateIndices)
       return op->emitError(
@@ -2718,6 +2736,7 @@ void TargetOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   TargetOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
       makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
       makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
       makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
@@ -2783,10 +2802,10 @@ static bool targetInReductionCapturedBy(Value inReductionVar, Value mapVarPtr) {
 }
 
 LogicalResult TargetOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (getKernelType() == TargetExecMode::bare && !isCombined())
@@ -2935,6 +2954,7 @@ void ParallelOp::build(OpBuilder &builder, OperationState &state,
                        ArrayRef<NamedAttribute> attributes) {
   ParallelOp::build(builder, state, /*allocate_vars=*/ValueRange(),
                     /*allocator_vars=*/ValueRange(),
+                    /*allocate_alignments=*/nullptr,
                     /*allocate_private_indices=*/nullptr, /*if_expr=*/nullptr,
                     /*num_threads_vars=*/ValueRange(),
                     /*private_vars=*/ValueRange(),
@@ -2949,6 +2969,7 @@ void ParallelOp::build(OpBuilder &builder, OperationState &state,
                        const ParallelOperands &clauses) {
   MLIRContext *ctx = builder.getContext();
   ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
+                    makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
                     makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
                     clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
                     makeArrayAttr(ctx, clauses.privateSyms),
@@ -3006,8 +3027,9 @@ LogicalResult ParallelOp::verify() {
     return failure();
   if (failed(verifyAllocateClause(
           getOperation(), getAllocateVars(), getAllocatorVars(),
-          getAllocatePrivateIndicesAttr(), getPrivateVars(),
-          getPrivateSymsAttr(), /*requirePrivateIndices=*/true)))
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr(),
+          /*requirePrivateIndices=*/true)))
     return failure();
 
   return verifyReductionVarList(*this, getReductionSyms(), getReductionVars(),
@@ -3061,6 +3083,7 @@ void TeamsOp::build(OpBuilder &builder, OperationState &state,
   // TODO Store clauses in op: privateVars, privateSyms, privateNeedsBarrier
   TeamsOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
       makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
       clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
       clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
@@ -3111,10 +3134,10 @@ LogicalResult TeamsOp::verify() {
       (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
     return emitOpError() << "'num_teams' not allowed in SPMD-no-loop kernels";
 
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (failed(verifyDynGroupprivateClause(
@@ -3150,6 +3173,7 @@ void SectionsOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   // TODO Store clauses in op: privateVars, privateSyms, privateNeedsBarrier
   SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
+                    makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
                     makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
                     clauses.nowait, /*private_vars=*/{},
                     /*private_syms=*/nullptr, /*private_needs_barrier=*/nullptr,
@@ -3162,10 +3186,10 @@ LogicalResult SectionsOp::verify() {
   if (isCombined())
     return emitOpError() << "cannot be a non-innermost combined construct leaf";
 
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   return verifyReductionVarList(*this, getReductionSyms(), getReductionVars(),
@@ -3191,6 +3215,7 @@ void ScopeOp::build(OpBuilder &builder, OperationState &state,
                     const ScopeOperands &clauses) {
   MLIRContext *ctx = builder.getContext();
   ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
+                 makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
                  makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
                  clauses.nowait, clauses.privateVars,
                  makeArrayAttr(ctx, clauses.privateSyms),
@@ -3201,10 +3226,10 @@ void ScopeOp::build(OpBuilder &builder, OperationState &state,
 }
 
 LogicalResult ScopeOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (failed(verifyPrivateVarList(*this)))
@@ -3223,6 +3248,7 @@ void SingleOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   // TODO Store clauses in op: privateVars, privateSyms, privateNeedsBarrier
   SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
+                  makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
                   makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
                   clauses.copyprivateVars,
                   makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
@@ -3231,10 +3257,10 @@ void SingleOp::build(OpBuilder &builder, OperationState &state,
 }
 
 LogicalResult SingleOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   return verifyCopyprivateVarList(*this, getCopyprivateVars(),
@@ -3427,6 +3453,7 @@ LogicalResult LoopOp::verifyRegions() {
 void WsloopOp::build(OpBuilder &builder, OperationState &state,
                      ArrayRef<NamedAttribute> attributes) {
   build(builder, state, /*allocate_vars=*/{}, /*allocator_vars=*/{},
+        /*allocate_alignments=*/nullptr,
         /*allocate_private_indices=*/nullptr,
         /*linear_vars=*/ValueRange(), /*linear_step_vars=*/ValueRange(),
         /*linear_var_types*/ nullptr, /*linear_modifiers=*/nullptr,
@@ -3446,6 +3473,7 @@ void WsloopOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   WsloopOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
       makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
       clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
       clauses.linearModifiers, clauses.nowait, clauses.order, clauses.orderMod,
@@ -3458,10 +3486,10 @@ void WsloopOp::build(OpBuilder &builder, OperationState &state,
 }
 
 LogicalResult WsloopOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (failed(
@@ -3600,14 +3628,15 @@ LogicalResult SimdOp::verifyRegions() {
 
 void DistributeOp::build(OpBuilder &builder, OperationState &state,
                          const DistributeOperands &clauses) {
-  DistributeOp::build(builder, state, clauses.allocateVars,
-                      clauses.allocatorVars,
-                      makeDenseI64ArrayAttr(builder.getContext(),
-                                            clauses.allocatePrivateIndices),
-                      clauses.distScheduleStatic, clauses.distScheduleChunkSize,
-                      clauses.order, clauses.orderMod, clauses.privateVars,
-                      makeArrayAttr(builder.getContext(), clauses.privateSyms),
-                      clauses.privateNeedsBarrier);
+  DistributeOp::build(
+      builder, state, clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(builder.getContext(), clauses.allocateAlignments),
+      makeDenseI64ArrayAttr(builder.getContext(),
+                            clauses.allocatePrivateIndices),
+      clauses.distScheduleStatic, clauses.distScheduleChunkSize, clauses.order,
+      clauses.orderMod, clauses.privateVars,
+      makeArrayAttr(builder.getContext(), clauses.privateSyms),
+      clauses.privateNeedsBarrier);
 }
 
 LogicalResult DistributeOp::verify() {
@@ -3615,10 +3644,10 @@ LogicalResult DistributeOp::verify() {
     return emitOpError() << "chunk size set without "
                             "dist_schedule_static being present";
 
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (failed(verifyPrivateVarList(*this)))
@@ -3770,6 +3799,7 @@ void TaskOp::build(OpBuilder &builder, OperationState &state,
   TaskOp::build(
       builder, state, clauses.iterated, clauses.affinityVars,
       clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
       makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
       makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
       makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
@@ -3782,10 +3812,10 @@ void TaskOp::build(OpBuilder &builder, OperationState &state,
 }
 
 LogicalResult TaskOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   LogicalResult verifyDependVars =
@@ -3810,6 +3840,7 @@ void TaskgroupOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   TaskgroupOp::build(builder, state, clauses.allocateVars,
                      clauses.allocatorVars,
+                     makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
                      makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices),
                      clauses.taskReductionVars,
                      makeDenseBoolArrayAttr(ctx, clauses.taskReductionByref),
@@ -3817,9 +3848,9 @@ void TaskgroupOp::build(OpBuilder &builder, OperationState &state,
 }
 
 LogicalResult TaskgroupOp::verify() {
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr())))
     return failure();
 
   return verifyReductionVarList(*this, getTaskReductionSyms(),
@@ -3836,6 +3867,7 @@ void TaskloopContextOp::build(OpBuilder &builder, OperationState &state,
   MLIRContext *ctx = builder.getContext();
   TaskloopContextOp::build(
       builder, state, clauses.allocateVars, clauses.allocatorVars,
+      makeDenseI64ArrayAttr(ctx, clauses.allocateAlignments),
       makeDenseI64ArrayAttr(ctx, clauses.allocatePrivateIndices), clauses.final,
       clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
       clauses.inReductionVars,
@@ -3860,10 +3892,10 @@ TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
 LogicalResult TaskloopContextOp::verify() {
   if (failed(verifyPrivateVarList(*this)))
     return failure();
-  if (failed(verifyAllocateClause(getOperation(), getAllocateVars(),
-                                  getAllocatorVars(),
-                                  getAllocatePrivateIndicesAttr(),
-                                  getPrivateVars(), getPrivateSymsAttr())))
+  if (failed(verifyAllocateClause(
+          getOperation(), getAllocateVars(), getAllocatorVars(),
+          getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
+          getPrivateVars(), getPrivateSymsAttr())))
     return failure();
 
   if (failed(verifyReductionVarList(*this, getReductionSyms(),
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index a1c0f5dcfbd72..e09bb720ced2d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -1971,8 +1971,10 @@ allocatePrivateVars(T op, llvm::IRBuilderBase &builder,
   SmallVector<int64_t> allocateItemForPrivate(privateVarsInfo.blockArgs.size(),
                                               -1);
   ValueRange allocatorVars;
+  DenseI64ArrayAttr allocateAlignments;
   if constexpr (std::is_same_v<T, omp::ParallelOp>) {
     allocatorVars = op.getAllocatorVars();
+    allocateAlignments = op.getAllocateAlignmentsAttr();
     if (auto privateIndices = op.getAllocatePrivateIndicesAttr())
       for (auto [allocateIndex, privateIndex] :
            llvm::enumerate(privateIndices.asArrayRef()))
@@ -2016,8 +2018,26 @@ allocatePrivateVars(T op, llvm::IRBuilderBase &builder,
         return llvm::createStringError(
             "failed to find converted OpenMP allocator operand");
       llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
-      llvmPrivateVar = ompBuilder->createOMPAlloc(
-          ompLoc, sizeValue, allocator->second, "omp.private.alloc");
+      int64_t alignment =
+          allocateAlignments ? allocateAlignments[allocateIndex] : 0;
+      if (alignment != 0) {
+        // The allocation must be aligned to at least the maximum of the
+        // requested alignment and the alignment the base language requires
+        // for the type being allocated.
+        uint64_t alignmentValue = std::max<uint64_t>(
+            static_cast<uint64_t>(alignment),
+            dataLayout.getABITypeAlign(llvmAllocType).value());
+        if (!llvm::isUIntN(sizeTy->getBitWidth(), alignmentValue))
+          return llvm::createStringError(
+              "OpenMP allocation alignment cannot be represented by the "
+              "target size type");
+        llvmPrivateVar = ompBuilder->createOMPAlignedAlloc(
+            ompLoc, llvm::ConstantInt::get(sizeTy, alignmentValue), sizeValue,
+            allocator->second, "omp.private.alloc");
+      } else {
+        llvmPrivateVar = ompBuilder->createOMPAlloc(
+            ompLoc, sizeValue, allocator->second, "omp.private.alloc");
+      }
       if (!llvmPrivateVar)
         return llvm::createStringError(
             "failed to create OpenMP private allocation");
diff --git a/mlir/test/Dialect/OpenMP/host-op-filtering.mlir b/mlir/test/Dialect/OpenMP/host-op-filtering.mlir
index e11ef390c2147..d4dde0cdef178 100644
--- a/mlir/test/Dialect/OpenMP/host-op-filtering.mlir
+++ b/mlir/test/Dialect/OpenMP/host-op-filtering.mlir
@@ -353,10 +353,10 @@ module attributes {omp.is_target_device = true} {
     // CHECK-NEXT: %[[MAP:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
     %1 = omp.map.info var_ptr(%arg0 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
     // CHECK-NEXT: omp.target kernel_type(generic) allocate(%[[ARG0]] : !llvm.ptr -> %[[ARG0]] : !llvm.ptr) thread_limit(%[[ARG1]] : i32) map_entries(%[[MAP]] -> %{{.*}} : !llvm.ptr) private(@privatizer %[[ARG0]] -> %{{.*}} : !llvm.ptr)
-    // CHECK: } {allocate_private_indices = array<i64: 0>}
+    // CHECK: } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
     omp.target kernel_type(generic) allocate(%arg0 : !llvm.ptr -> %arg0 : !llvm.ptr) depend(taskdependin -> %arg0 : !llvm.ptr) device(%arg1 : i32) if(%arg2) thread_limit(%arg1 : i32) in_reduction(@reduction %arg0 : !llvm.ptr) map_entries(%1 -> %arg3 : !llvm.ptr) private(@privatizer %arg0 -> %arg4 : !llvm.ptr) {
       omp.terminator
-    } {allocate_private_indices = array<i64: 0>}
+    } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
 
     // CHECK-NOT: omp.target_enter_data
     // CHECK-NOT: omp.target_exit_data
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 41f2b705d31fe..56dae56f2fb8c 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -3374,6 +3374,58 @@ func.func @omp_parallel_allocate_empty_map() {
 
 // -----
 
+func.func @omp_parallel_allocate_empty_alignments() {
+  // expected-error @below {{unexpected allocate alignments without allocate variables}}
+  omp.parallel {
+    omp.terminator
+  } {allocate_alignments = array<i64>}
+  return
+}
+
+// -----
+
+omp.private {type = private} @allocate_private : i32
+
+func.func @omp_parallel_allocate_alignment_size(
+    %allocator : i64, %var : !llvm.ptr) {
+  // expected-error @below {{expected as many allocate alignments as allocate variables}}
+  omp.parallel allocate(%allocator : i64 -> %var : !llvm.ptr)
+      private(@allocate_private %var -> %private : !llvm.ptr) {
+    omp.terminator
+  } {allocate_alignments = array<i64: 64, 128>, allocate_private_indices = array<i64: 0>}
+  return
+}
+
+// -----
+
+omp.private {type = private} @allocate_private : i32
+
+func.func @omp_parallel_allocate_negative_alignment(
+    %allocator : i64, %var : !llvm.ptr) {
+  // expected-error @below {{expected non-negative allocate alignments}}
+  omp.parallel allocate(%allocator : i64 -> %var : !llvm.ptr)
+      private(@allocate_private %var -> %private : !llvm.ptr) {
+    omp.terminator
+  } {allocate_alignments = array<i64: -64>, allocate_private_indices = array<i64: 0>}
+  return
+}
+
+// -----
+
+omp.private {type = private} @allocate_private : i32
+
+func.func @omp_parallel_allocate_non_power_of_two_alignment(
+    %allocator : i64, %var : !llvm.ptr) {
+  // expected-error @below {{expected positive allocate alignments to be powers of two}}
+  omp.parallel allocate(%allocator : i64 -> %var : !llvm.ptr)
+      private(@allocate_private %var -> %private : !llvm.ptr) {
+    omp.terminator
+  } {allocate_alignments = array<i64: 24>, allocate_private_indices = array<i64: 0>}
+  return
+}
+
+// -----
+
 omp.private {type = private} @allocate_private : i32
 
 func.func @omp_parallel_allocate_missing_map(%allocator : i64, %var : !llvm.ptr) {
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index b2fe5effd2de6..00b975c371d1b 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -195,11 +195,11 @@ func.func @omp_parallel_pretty(%data_var : memref<i32>, %if_cond : i1, %num_thre
 
  // CHECK: omp.parallel allocate(
  // CHECK-SAME: private(
- // CHECK: } {allocate_private_indices = array<i64: 0>}
+ // CHECK: } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
  omp.parallel allocate(%allocator : si32 -> %data_var : memref<i32>)
      private(@parallel_allocate_private %data_var -> %private : memref<i32>) {
    omp.terminator
- } {allocate_private_indices = array<i64: 0>}
+ } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
 
  // CHECK: omp.parallel
  // CHECK-NEXT: omp.parallel if(%{{.*}})
diff --git a/mlir/test/Target/LLVMIR/openmp-allocate-clause.mlir b/mlir/test/Target/LLVMIR/openmp-allocate-clause.mlir
index dc2515e3f1358..d6e0587ce5095 100644
--- a/mlir/test/Target/LLVMIR/openmp-allocate-clause.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-allocate-clause.mlir
@@ -1,7 +1,10 @@
 // RUN: split-file %s %t
 // RUN: mlir-translate -mlir-to-llvmir -split-input-file %t/valid.mlir | FileCheck %s
 // RUN: mlir-translate -mlir-to-llvmir %t/i386.mlir | FileCheck %s --check-prefix=I386
+// RUN: mlir-translate -mlir-to-llvmir %t/i386-aligned.mlir | FileCheck %s --check-prefix=I386-ALIGNED
+// RUN: mlir-translate -mlir-to-llvmir %t/natural-alignment.mlir | FileCheck %s --check-prefix=NATURAL
 // RUN: not mlir-translate -mlir-to-llvmir %t/i386-overflow.mlir 2>&1 | FileCheck %s --check-prefix=I386-OVERFLOW
+// RUN: not mlir-translate -mlir-to-llvmir %t/i386-alignment-overflow.mlir 2>&1 | FileCheck %s --check-prefix=I386-ALIGNMENT-OVERFLOW
 // RUN: not mlir-translate -mlir-to-llvmir %t/device.mlir 2>&1 | FileCheck %s --check-prefix=DEVICE
 
 //--- valid.mlir
@@ -15,6 +18,19 @@ omp.private {type = firstprivate} @x.firstprivate : i32 copy {
 
 omp.private {type = private} @y.private : i32
 
+llvm.func @allocator_unaligned(%x: !llvm.ptr) {
+  %null = llvm.mlir.constant(0 : i64) : i64
+  omp.parallel allocate(%null : i64 -> %x : !llvm.ptr)
+      private(@y.private %x -> %x.private : !llvm.ptr) {
+    omp.terminator
+  } {allocate_private_indices = array<i64: 0>}
+  llvm.return
+}
+
+// CHECK-LABEL: define internal void @allocator_unaligned..omp_par
+// CHECK: %[[UNALIGNED:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr null)
+// CHECK: call void @__kmpc_free({{.*}}, ptr %[[UNALIGNED]], ptr null)
+
 llvm.func @allocator_dynamic(%x: !llvm.ptr, %y: !llvm.ptr, %allocator: i64) {
   omp.parallel allocate(%allocator : i64 -> %x : !llvm.ptr)
       private(@x.firstprivate %x -> %x.private,
@@ -25,7 +41,7 @@ llvm.func @allocator_dynamic(%x: !llvm.ptr, %y: !llvm.ptr, %allocator: i64) {
     llvm.store %next, %x.private : i32, !llvm.ptr
     llvm.store %one, %y.private : i32, !llvm.ptr
     omp.terminator
-  } {allocate_private_indices = array<i64: 0>}
+  } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
   llvm.return
 }
 
@@ -35,7 +51,7 @@ llvm.func @allocator_dynamic(%x: !llvm.ptr, %y: !llvm.ptr, %allocator: i64) {
 // CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call
 // CHECK-LABEL: define internal void @allocator_dynamic..omp_par
 // CHECK: %[[CAPTURED_ALLOCATOR:.*]] = load ptr, ptr %{{.*}}, align 8
-// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr %[[CAPTURED_ALLOCATOR]])
+// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 64, i64 4, ptr %[[CAPTURED_ALLOCATOR]])
 // CHECK: %[[Y_ALLOCA:.*]] = alloca i32, align 4
 // CHECK: %[[ORIGINAL:.*]] = load i32, ptr %{{.*}}, align 4
 // CHECK: store i32 %[[ORIGINAL]], ptr %[[ALLOC]], align 4
@@ -67,8 +83,11 @@ llvm.func @allocator_reverse_free(%x: !llvm.ptr, %y: !llvm.ptr,
                         %allocator.x : i64 -> %x : !llvm.ptr)
       private(@x.private %x -> %x.private,
               @y.private %y -> %y.private : !llvm.ptr, !llvm.ptr) {
+    %one = llvm.mlir.constant(1 : i32) : i32
+    llvm.store %one, %x.private : i32, !llvm.ptr
+    llvm.store %one, %y.private : i32, !llvm.ptr
     omp.terminator
-  } {allocate_private_indices = array<i64: 1, 0>}
+  } {allocate_alignments = array<i64: 128, 64>, allocate_private_indices = array<i64: 1, 0>}
   llvm.return
 }
 
@@ -78,8 +97,10 @@ llvm.func @allocator_reverse_free(%x: !llvm.ptr, %y: !llvm.ptr,
 // CHECK-LABEL: define internal void @allocator_reverse_free..omp_par
 // CHECK: %[[CAPTURED_X:.*]] = load ptr, ptr %{{.*}}, align 8
 // CHECK: %[[CAPTURED_Y:.*]] = load ptr, ptr %{{.*}}, align 8
-// CHECK: %[[X_ALLOC:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr %[[CAPTURED_X]])
-// CHECK: %[[Y_ALLOC:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr %[[CAPTURED_Y]])
+// CHECK: %[[X_ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 64, i64 4, ptr %[[CAPTURED_X]])
+// CHECK: %[[Y_ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 128, i64 4, ptr %[[CAPTURED_Y]])
+// CHECK: store i32 1, ptr %[[X_ALLOC]], align 4
+// CHECK: store i32 1, ptr %[[Y_ALLOC]], align 4
 // CHECK: call void @private_dealloc(ptr %[[X_ALLOC]])
 // CHECK: call void @__kmpc_free({{.*}}, ptr %[[Y_ALLOC]], ptr %[[CAPTURED_Y]])
 // CHECK: call void @__kmpc_free({{.*}}, ptr %[[X_ALLOC]], ptr %[[CAPTURED_X]])
@@ -95,12 +116,12 @@ llvm.func @allocator_cancel(%x: !llvm.ptr) {
       private(@x.private %x -> %x.private : !llvm.ptr) {
     omp.cancel cancellation_construct_type(parallel)
     omp.terminator
-  } {allocate_private_indices = array<i64: 0>}
+  } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
   llvm.return
 }
 
 // CHECK-LABEL: define internal void @allocator_cancel..omp_par
-// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr null)
+// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 64, i64 4, ptr null)
 // CHECK: {{.*}}.cncl:
 // CHECK: br label %[[FINI:.*]]
 // CHECK: .fini:
@@ -119,12 +140,12 @@ llvm.func @allocator_cancellation_point(%x: !llvm.ptr) {
       private(@x.private %x -> %x.private : !llvm.ptr) {
     omp.cancellation_point cancellation_construct_type(parallel)
     omp.terminator
-  } {allocate_private_indices = array<i64: 0>}
+  } {allocate_alignments = array<i64: 128>, allocate_private_indices = array<i64: 0>}
   llvm.return
 }
 
 // CHECK-LABEL: define internal void @allocator_cancellation_point..omp_par
-// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_alloc({{.*}}, i64 4, ptr null)
+// CHECK: %[[ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 128, i64 4, ptr null)
 // CHECK: {{.*}}.cncl:
 // CHECK: br label %[[FINI:.*]]
 // CHECK: .fini:
@@ -158,6 +179,66 @@ module attributes {
 // I386: ret void
 // I386-LABEL: declare noalias ptr @__kmpc_alloc(i32, i32, ptr)
 
+//--- i386-aligned.mlir
+
+module attributes {
+  llvm.data_layout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-S128",
+  llvm.target_triple = "i386-unknown-linux-gnu"
+} {
+  omp.private {type = private} @x.private : i32
+
+  llvm.func @allocator_i386_aligned(%x: !llvm.ptr) {
+    %null = llvm.mlir.constant(0 : i64) : i64
+    omp.parallel allocate(%null : i64 -> %x : !llvm.ptr)
+        private(@x.private %x -> %x.private : !llvm.ptr) {
+      %one = llvm.mlir.constant(1 : i32) : i32
+      llvm.store %one, %x.private : i32, !llvm.ptr
+      omp.terminator
+    } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
+    llvm.return
+  }
+}
+
+// I386-ALIGNED: target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-S128"
+// I386-ALIGNED-LABEL: define internal void @allocator_i386_aligned..omp_par
+// I386-ALIGNED: %[[ALLOC:.*]] = call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i32 64, i32 4, ptr null)
+// I386-ALIGNED: store i32 1, ptr %[[ALLOC]], align 4
+// I386-ALIGNED: call void @__kmpc_free(i32 %{{.*}}, ptr %[[ALLOC]], ptr null)
+// I386-ALIGNED: ret void
+// I386-ALIGNED-LABEL: declare noalias ptr @__kmpc_aligned_alloc(i32, i32, i32, ptr)
+
+//--- natural-alignment.mlir
+
+module attributes {
+  llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
+  llvm.target_triple = "x86_64-unknown-linux-gnu"
+} {
+  omp.private {type = private} @i64.private : i64
+
+  llvm.func @allocator_below_natural_alignment(%x: !llvm.ptr) {
+    %null = llvm.mlir.constant(0 : i64) : i64
+    omp.parallel allocate(%null : i64 -> %x : !llvm.ptr)
+        private(@i64.private %x -> %x.private : !llvm.ptr) {
+      omp.terminator
+    } {allocate_alignments = array<i64: 2>, allocate_private_indices = array<i64: 0>}
+    llvm.return
+  }
+
+  llvm.func @allocator_above_natural_alignment(%x: !llvm.ptr) {
+    %null = llvm.mlir.constant(0 : i64) : i64
+    omp.parallel allocate(%null : i64 -> %x : !llvm.ptr)
+        private(@i64.private %x -> %x.private : !llvm.ptr) {
+      omp.terminator
+    } {allocate_alignments = array<i64: 32>, allocate_private_indices = array<i64: 0>}
+    llvm.return
+  }
+}
+
+// NATURAL-LABEL: define internal void @allocator_below_natural_alignment..omp_par
+// NATURAL: call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 8, i64 8, ptr null)
+// NATURAL-LABEL: define internal void @allocator_above_natural_alignment..omp_par
+// NATURAL: call ptr @__kmpc_aligned_alloc(i32 %{{.*}}, i64 32, i64 8, ptr null)
+
 //--- i386-overflow.mlir
 
 module attributes {
@@ -182,6 +263,30 @@ module attributes {
 // I386-OVERFLOW: LLVM Translation failed for operation: omp.parallel
 // I386-OVERFLOW-NOT: __kmpc_alloc
 
+//--- i386-alignment-overflow.mlir
+
+module attributes {
+  llvm.data_layout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-S128",
+  llvm.target_triple = "i386-unknown-linux-gnu"
+} {
+  omp.private {type = private} @x.private : i32
+
+  llvm.func @allocator_i386_alignment_overflow(%x: !llvm.ptr) {
+    %null = llvm.mlir.constant(0 : i64) : i64
+    omp.parallel allocate(%null : i64 -> %x : !llvm.ptr)
+        private(@x.private %x -> %x.private : !llvm.ptr) {
+      omp.terminator
+    } {allocate_alignments = array<i64: 4294967296>, allocate_private_indices = array<i64: 0>}
+    llvm.return
+  }
+}
+
+// I386-ALIGNMENT-OVERFLOW-NOT: __kmpc_aligned_alloc
+// I386-ALIGNMENT-OVERFLOW: OpenMP allocation alignment cannot be represented by the target size type
+// I386-ALIGNMENT-OVERFLOW-NOT: __kmpc_aligned_alloc
+// I386-ALIGNMENT-OVERFLOW: LLVM Translation failed for operation: omp.parallel
+// I386-ALIGNMENT-OVERFLOW-NOT: __kmpc_aligned_alloc
+
 //--- device.mlir
 
 omp.private {type = private} @device.private : i32
@@ -193,7 +298,7 @@ llvm.func @allocator_device() {
     omp.parallel allocate(%allocator : i64 -> %x : !llvm.ptr)
         private(@device.private %x -> %private : !llvm.ptr) {
       omp.terminator
-    } {allocate_private_indices = array<i64: 0>}
+    } {allocate_alignments = array<i64: 64>, allocate_private_indices = array<i64: 0>}
     omp.terminator
   }
   llvm.return



More information about the flang-commits mailing list