Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[OpenACC][CIR] Implement Loop lowering of seq/auto/independent #138164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 1, 2025

Conversation

erichkeane
Copy link
Collaborator

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.

erichkeane added 2 commits May 1, 2025 08:46
These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.
@llvmbot llvmbot added clang Clang issues not falling into any other category mlir mlir:openacc openacc ClangIR Anything related to the ClangIR project labels May 1, 2025
@llvmbot
Copy link
Member

llvmbot commented May 1, 2025

@llvm/pr-subscribers-mlir
@llvm/pr-subscribers-openacc

@llvm/pr-subscribers-clangir

Author: Erich Keane (erichkeane)

Changes

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.


Full diff: https://github.com/llvm/llvm-project/pull/138164.diff

4 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h (+32-2)
  • (modified) clang/test/CIR/CodeGenOpenACC/loop.cpp (+79)
  • (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+8)
  • (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+18)
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
index b54682402d961..ff0bf6e7f55dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
@@ -147,13 +147,13 @@ class OpenACCClauseCIREmitter final
             decodeDeviceType(clause.getArchitectures()[0].getIdentifierInfo()));
     } else if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp,
                                       mlir::acc::SerialOp, mlir::acc::KernelsOp,
-                                      mlir::acc::DataOp>) {
+                                      mlir::acc::DataOp, mlir::acc::LoopOp>) {
       // Nothing to do here, these constructs don't have any IR for these, as
       // they just modify the other clauses IR.  So setting of
       // `lastDeviceTypeValues` (done above) is all we need.
     } else {
       // TODO: When we've implemented this for everything, switch this to an
-      // unreachable. update, data, loop, routine, combined constructs remain.
+      // unreachable. update, data, routine, combined constructs remain.
       return clauseNotImplemented(clause);
     }
   }
@@ -306,6 +306,36 @@ class OpenACCClauseCIREmitter final
       llvm_unreachable("set, is only valid device_num constructs");
     }
   }
+
+  void VisitSeqClause(const OpenACCSeqClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addSeq(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitAutoClause(const OpenACCAutoClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addAuto(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitIndependentClause(const OpenACCIndependentClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addIndependent(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
 };
 
 template <typename OpTy>
diff --git a/clang/test/CIR/CodeGenOpenACC/loop.cpp b/clang/test/CIR/CodeGenOpenACC/loop.cpp
index 792edfedaacc6..2757d935e1f76 100644
--- a/clang/test/CIR/CodeGenOpenACC/loop.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/loop.cpp
@@ -30,4 +30,83 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) {
   // CHECK-NEXT: } loc
   // CHECK-NEXT: acc.yield
   // CHECK-NEXT: } loc
+
+
+#pragma acc loop seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<radeon>]} loc
+#pragma acc loop seq device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop seq device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+
+#pragma acc loop independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<radeon>]} loc
+#pragma acc loop independent device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop independent device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+
+#pragma acc loop auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<radeon>]} loc
+#pragma acc loop auto device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop auto device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
 }
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 3ad8e4f9ccbeb..c3df064cf0ead 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -2198,6 +2198,14 @@ def OpenACC_LoopOp : OpenACC_Op<"loop",
     /// Return the value of the worker clause for the given device_type 
     /// if present.
     mlir::Value getGangValue(mlir::acc::GangArgType gangArgType, mlir::acc::DeviceType deviceType);
+
+    // Add an entry to the 'seq' attribute for each additional device types.
+    void addSeq(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'independent' attribute for each additional device
+    // types.
+    void addIndependent(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'auto' attribute for each additional device types.
+    void addAuto(MLIRContext *, llvm::ArrayRef<DeviceType>);
   }];
 
   let hasCustomAssemblyFormat = 1;
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index d23563f1f0fb0..39dbb0c92a309 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -2651,6 +2651,24 @@ void printLoopControl(OpAsmPrinter &p, Operation *op, Region &region,
   p.printRegion(region, /*printEntryBlockArgs=*/false);
 }
 
+void acc::LoopOp::addSeq(MLIRContext *context,
+                         llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
+                                                effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addIndependent(
+    MLIRContext *context, llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setIndependentAttr(addDeviceTypeAffectedOperandHelper(
+      context, getIndependentAttr(), effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addAuto(MLIRContext *context,
+                          llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
+                                                  effectiveDeviceTypes));
+}
+
 //===----------------------------------------------------------------------===//
 // DataOp
 //===----------------------------------------------------------------------===//

@llvmbot
Copy link
Member

llvmbot commented May 1, 2025

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

Changes

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.


Full diff: https://github.com/llvm/llvm-project/pull/138164.diff

4 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h (+32-2)
  • (modified) clang/test/CIR/CodeGenOpenACC/loop.cpp (+79)
  • (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+8)
  • (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+18)
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
index b54682402d961..ff0bf6e7f55dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
@@ -147,13 +147,13 @@ class OpenACCClauseCIREmitter final
             decodeDeviceType(clause.getArchitectures()[0].getIdentifierInfo()));
     } else if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp,
                                       mlir::acc::SerialOp, mlir::acc::KernelsOp,
-                                      mlir::acc::DataOp>) {
+                                      mlir::acc::DataOp, mlir::acc::LoopOp>) {
       // Nothing to do here, these constructs don't have any IR for these, as
       // they just modify the other clauses IR.  So setting of
       // `lastDeviceTypeValues` (done above) is all we need.
     } else {
       // TODO: When we've implemented this for everything, switch this to an
-      // unreachable. update, data, loop, routine, combined constructs remain.
+      // unreachable. update, data, routine, combined constructs remain.
       return clauseNotImplemented(clause);
     }
   }
@@ -306,6 +306,36 @@ class OpenACCClauseCIREmitter final
       llvm_unreachable("set, is only valid device_num constructs");
     }
   }
+
+  void VisitSeqClause(const OpenACCSeqClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addSeq(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitAutoClause(const OpenACCAutoClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addAuto(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitIndependentClause(const OpenACCIndependentClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addIndependent(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
 };
 
 template <typename OpTy>
diff --git a/clang/test/CIR/CodeGenOpenACC/loop.cpp b/clang/test/CIR/CodeGenOpenACC/loop.cpp
index 792edfedaacc6..2757d935e1f76 100644
--- a/clang/test/CIR/CodeGenOpenACC/loop.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/loop.cpp
@@ -30,4 +30,83 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) {
   // CHECK-NEXT: } loc
   // CHECK-NEXT: acc.yield
   // CHECK-NEXT: } loc
+
+
+#pragma acc loop seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<radeon>]} loc
+#pragma acc loop seq device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop seq device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+
+#pragma acc loop independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<radeon>]} loc
+#pragma acc loop independent device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop independent device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+
+#pragma acc loop auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<radeon>]} loc
+#pragma acc loop auto device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop auto device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
 }
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 3ad8e4f9ccbeb..c3df064cf0ead 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -2198,6 +2198,14 @@ def OpenACC_LoopOp : OpenACC_Op<"loop",
     /// Return the value of the worker clause for the given device_type 
     /// if present.
     mlir::Value getGangValue(mlir::acc::GangArgType gangArgType, mlir::acc::DeviceType deviceType);
+
+    // Add an entry to the 'seq' attribute for each additional device types.
+    void addSeq(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'independent' attribute for each additional device
+    // types.
+    void addIndependent(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'auto' attribute for each additional device types.
+    void addAuto(MLIRContext *, llvm::ArrayRef<DeviceType>);
   }];
 
   let hasCustomAssemblyFormat = 1;
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index d23563f1f0fb0..39dbb0c92a309 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -2651,6 +2651,24 @@ void printLoopControl(OpAsmPrinter &p, Operation *op, Region &region,
   p.printRegion(region, /*printEntryBlockArgs=*/false);
 }
 
+void acc::LoopOp::addSeq(MLIRContext *context,
+                         llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
+                                                effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addIndependent(
+    MLIRContext *context, llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setIndependentAttr(addDeviceTypeAffectedOperandHelper(
+      context, getIndependentAttr(), effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addAuto(MLIRContext *context,
+                          llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
+                                                  effectiveDeviceTypes));
+}
+
 //===----------------------------------------------------------------------===//
 // DataOp
 //===----------------------------------------------------------------------===//

@llvmbot
Copy link
Member

llvmbot commented May 1, 2025

@llvm/pr-subscribers-mlir-openacc

Author: Erich Keane (erichkeane)

Changes

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.


Full diff: https://github.com/llvm/llvm-project/pull/138164.diff

4 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h (+32-2)
  • (modified) clang/test/CIR/CodeGenOpenACC/loop.cpp (+79)
  • (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+8)
  • (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+18)
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
index b54682402d961..ff0bf6e7f55dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.h
@@ -147,13 +147,13 @@ class OpenACCClauseCIREmitter final
             decodeDeviceType(clause.getArchitectures()[0].getIdentifierInfo()));
     } else if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp,
                                       mlir::acc::SerialOp, mlir::acc::KernelsOp,
-                                      mlir::acc::DataOp>) {
+                                      mlir::acc::DataOp, mlir::acc::LoopOp>) {
       // Nothing to do here, these constructs don't have any IR for these, as
       // they just modify the other clauses IR.  So setting of
       // `lastDeviceTypeValues` (done above) is all we need.
     } else {
       // TODO: When we've implemented this for everything, switch this to an
-      // unreachable. update, data, loop, routine, combined constructs remain.
+      // unreachable. update, data, routine, combined constructs remain.
       return clauseNotImplemented(clause);
     }
   }
@@ -306,6 +306,36 @@ class OpenACCClauseCIREmitter final
       llvm_unreachable("set, is only valid device_num constructs");
     }
   }
+
+  void VisitSeqClause(const OpenACCSeqClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addSeq(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitAutoClause(const OpenACCAutoClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addAuto(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
+
+  void VisitIndependentClause(const OpenACCIndependentClause &clause) {
+    if constexpr (isOneOfTypes<OpTy, mlir::acc::LoopOp>) {
+      operation.addIndependent(builder.getContext(), lastDeviceTypeValues);
+    } else {
+      // TODO: When we've implemented this for everything, switch this to an
+      // unreachable. Routine, Combined constructs remain.
+      return clauseNotImplemented(clause);
+    }
+  }
 };
 
 template <typename OpTy>
diff --git a/clang/test/CIR/CodeGenOpenACC/loop.cpp b/clang/test/CIR/CodeGenOpenACC/loop.cpp
index 792edfedaacc6..2757d935e1f76 100644
--- a/clang/test/CIR/CodeGenOpenACC/loop.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/loop.cpp
@@ -30,4 +30,83 @@ extern "C" void acc_loop(int *A, int *B, int *C, int N) {
   // CHECK-NEXT: } loc
   // CHECK-NEXT: acc.yield
   // CHECK-NEXT: } loc
+
+
+#pragma acc loop seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) seq
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<radeon>]} loc
+#pragma acc loop seq device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+#pragma acc loop seq device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {seq = [#acc.device_type<none>]} loc
+
+#pragma acc loop independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) independent
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<radeon>]} loc
+#pragma acc loop independent device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+#pragma acc loop independent device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {independent = [#acc.device_type<none>]} loc
+
+#pragma acc loop auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop device_type(nvidia, radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<nvidia>, #acc.device_type<radeon>]} loc
+#pragma acc loop device_type(radeon) auto
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<radeon>]} loc
+#pragma acc loop auto device_type(nvidia, radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
+#pragma acc loop auto device_type(radeon)
+  for(unsigned I = 0; I < N; ++I);
+  // CHECK: acc.loop {
+  // CHECK: acc.yield
+  // CHECK-NEXT: } attributes {auto_ = [#acc.device_type<none>]} loc
 }
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 3ad8e4f9ccbeb..c3df064cf0ead 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -2198,6 +2198,14 @@ def OpenACC_LoopOp : OpenACC_Op<"loop",
     /// Return the value of the worker clause for the given device_type 
     /// if present.
     mlir::Value getGangValue(mlir::acc::GangArgType gangArgType, mlir::acc::DeviceType deviceType);
+
+    // Add an entry to the 'seq' attribute for each additional device types.
+    void addSeq(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'independent' attribute for each additional device
+    // types.
+    void addIndependent(MLIRContext *, llvm::ArrayRef<DeviceType>);
+    // Add an entry to the 'auto' attribute for each additional device types.
+    void addAuto(MLIRContext *, llvm::ArrayRef<DeviceType>);
   }];
 
   let hasCustomAssemblyFormat = 1;
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index d23563f1f0fb0..39dbb0c92a309 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -2651,6 +2651,24 @@ void printLoopControl(OpAsmPrinter &p, Operation *op, Region &region,
   p.printRegion(region, /*printEntryBlockArgs=*/false);
 }
 
+void acc::LoopOp::addSeq(MLIRContext *context,
+                         llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
+                                                effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addIndependent(
+    MLIRContext *context, llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setIndependentAttr(addDeviceTypeAffectedOperandHelper(
+      context, getIndependentAttr(), effectiveDeviceTypes));
+}
+
+void acc::LoopOp::addAuto(MLIRContext *context,
+                          llvm::ArrayRef<DeviceType> effectiveDeviceTypes) {
+  setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
+                                                  effectiveDeviceTypes));
+}
+
 //===----------------------------------------------------------------------===//
 // DataOp
 //===----------------------------------------------------------------------===//

Copy link
Contributor

@razvanlupusoru razvanlupusoru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thank you for continuing to contribute the builders to the dialect.

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@erichkeane erichkeane merged commit 4efcc52 into llvm:main May 1, 2025
17 checks passed
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…138164)

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…138164)

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…138164)

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…138164)

These just add a standard 'device_type' flag to the acc.loop, so
implement that lowering. This also modifies the dialect to add helpers
for these as well, to be consistent with the previous ones.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project mlir:openacc mlir openacc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants