[clang] [CIR] Add offload container attribute (PR #206576)
@@ -115,6 +115,50 @@ def CIR_SourceLanguageAttr :
CIR_EnumAttr {
}];
}
+//===--===//
+// OffloadKindAttr
+//===--===//
+
+def CIR_OffloadKind : CIR_I32Enum<"OffloadKind", "offload kind", [
+ I32EnumAttrCase<"Host", 0, "host">,
+ I32EnumAttrCase<"Device", 1, "device">
xlauko wrote:
```suggestion
I32EnumCase<"Host", 0, "host">,
I32EnumCase<"Device", 1, "device">
```
https://github.com/llvm/llvm-project/pull/206576
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
@@ -110,6 +111,87 @@ Operation
*cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder,
mlir::cast(value));
}
+//===--===//
+// Dialect attribute verification
+//===--===//
+
+static LogicalResult verifyOffloadKind(mlir::ModuleOp module,
+ cir::OffloadKind expected) {
+ auto attr = module->getAttrOfType(
+ cir::CIRDialect::getOffloadKindAttrName());
+ if (!attr)
+return module.emitOpError()
+ << "expects '" << cir::CIRDialect::getOffloadKindAttrName()
+ << "' offload kind attribute";
+ if (attr.getValue() != expected)
+return module.emitOpError()
+ << "expects '" << cir::CIRDialect::getOffloadKindAttrName()
+ << "' value '" << cir::stringifyOffloadKind(expected) << "'";
+ return success();
+}
+
+// A module marked with `cir.offload.container` holds the host module followed
+// by one or more device modules, each tagged with `cir.offload.kind`. Keeping
+// the host module first gives later offload passes a simple convention for
+// finding the host side while iterating the remaining device modules.
+static LogicalResult verifyOffloadContainer(mlir::Operation *op) {
+ auto container = mlir::dyn_cast(op);
+ if (!container)
+return op->emitError() << "expects '"
+ << cir::CIRDialect::getOffloadContainerAttrName()
+ << "' attribute to be attached to '"
+ << mlir::ModuleOp::getOperationName() << "'";
+
+ mlir::Block &body = *container.getBody();
+ if (body.empty())
+return container.emitOpError()
+ << "expects host module as the first nested op";
+
+ auto host = mlir::dyn_cast(body.front());
+ if (!host)
+return container.emitOpError()
+ << "expects host module as the first nested op";
+ if (failed(verifyOffloadKind(host, cir::OffloadKind::Host)))
+return failure();
+
+ auto it = body.begin();
+ ++it;
xlauko wrote:
use `llvm::drop_begin(body)`
https://github.com/llvm/llvm-project/pull/206576
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
@@ -115,6 +115,50 @@ def CIR_SourceLanguageAttr :
CIR_EnumAttr {
}];
}
+//===--===//
+// OffloadKindAttr
+//===--===//
+
+def CIR_OffloadKind : CIR_I32Enum<"OffloadKind", "offload kind", [
+ I32EnumAttrCase<"Host", 0, "host">,
+ I32EnumAttrCase<"Device", 1, "device">
+]>;
+
+def CIR_OffloadKindAttr : CIR_EnumAttr {
xlauko wrote:
```suggestion
def CIR_OffloadKindAttr : CIR_EnumAttr {
```
https://github.com/llvm/llvm-project/pull/206576
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
xlauko wrote: Use CHECK-LABEL in between modules here https://github.com/llvm/llvm-project/pull/206576 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
@@ -110,6 +111,87 @@ Operation
*cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder,
mlir::cast(value));
}
+//===--===//
+// Dialect attribute verification
+//===--===//
+
+static LogicalResult verifyOffloadKind(mlir::ModuleOp module,
+ cir::OffloadKind expected) {
+ auto attr = module->getAttrOfType(
+ cir::CIRDialect::getOffloadKindAttrName());
+ if (!attr)
+return module.emitOpError()
+ << "expects '" << cir::CIRDialect::getOffloadKindAttrName()
+ << "' offload kind attribute";
+ if (attr.getValue() != expected)
+return module.emitOpError()
+ << "expects '" << cir::CIRDialect::getOffloadKindAttrName()
+ << "' value '" << cir::stringifyOffloadKind(expected) << "'";
+ return success();
+}
+
+// A module marked with `cir.offload.container` holds the host module followed
+// by one or more device modules, each tagged with `cir.offload.kind`. Keeping
+// the host module first gives later offload passes a simple convention for
+// finding the host side while iterating the remaining device modules.
+static LogicalResult verifyOffloadContainer(mlir::Operation *op) {
+ auto container = mlir::dyn_cast(op);
+ if (!container)
+return op->emitError() << "expects '"
xlauko wrote:
nit: emitOpError as everywhere else?
https://github.com/llvm/llvm-project/pull/206576
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
@@ -115,6 +115,50 @@ def CIR_SourceLanguageAttr :
CIR_EnumAttr {
}];
}
+//===--===//
+// OffloadKindAttr
+//===--===//
+
+def CIR_OffloadKind : CIR_I32Enum<"OffloadKind", "offload kind", [
+ I32EnumAttrCase<"Host", 0, "host">,
+ I32EnumAttrCase<"Device", 1, "device">
+]>;
+
+def CIR_OffloadKindAttr : CIR_EnumAttr {
xlauko wrote:
I recently moved all enum attributes to not spell `_kind`.
Can you fix this also in test expectaions.
https://github.com/llvm/llvm-project/pull/206576
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
https://github.com/RiverDave updated
https://github.com/llvm/llvm-project/pull/206576
>From be1086b6453cc16402913c60f145a39abe7b3630 Mon Sep 17 00:00:00 2001
From: David Rivera
Date: Mon, 29 Jun 2026 15:46:11 -0400
Subject: [PATCH 1/5] [CIR] Add offload container operation
Introduce cir.offload.container, a CIR dialect operation that groups one host
CIR module with one or more device CIR modules in a single IR unit.
Nested modules are tagged with the new cir.offload.kind enum attribute using
#cir.offload_kind and #cir.offload_kind. The verifier enforces
the structural contract expected by follow-up offload merge/split pipeline
patches: host module first, device modules after it, only nested builtin.module
ops, and at least one device module.
This patch only adds the IR representation and verifier tests; the passes that
create, consume, or split the container are left to later patches.
---
.../clang/CIR/Dialect/IR/CIRDialect.td| 1 +
clang/include/clang/CIR/Dialect/IR/CIROps.td | 59 ++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 61 +++
.../test/CIR/IR/invalid-offload-container.cir | 54
clang/test/CIR/IR/offload-container.cir | 32 ++
5 files changed, 207 insertions(+)
create mode 100644 clang/test/CIR/IR/invalid-offload-container.cir
create mode 100644 clang/test/CIR/IR/offload-container.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 9ea186489ac65..00c8cfe008408 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -53,6 +53,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getModuleLevelAsmAttrName() { return
"cir.module_asm"; }
static llvm::StringRef getGlobalCtorsAttrName() { return
"cir.global_ctors"; }
static llvm::StringRef getGlobalDtorsAttrName() { return
"cir.global_dtors"; }
+static llvm::StringRef getOffloadKindAttrName() { return
"cir.offload.kind"; }
static llvm::StringRef getOperandSegmentSizesAttrName() { return
"operandSegmentSizes"; }
static llvm::StringRef getNoCallerSavedRegsAttrName() { return
"no_caller_saved_registers"; }
static llvm::StringRef getNoCallbackAttrName() { return "nocallback"; }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6d149e6b1ccaa..158b97adfbe4e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -6141,6 +6141,65 @@ def CIR_VecSplatOp : CIR_Op<"vec.splat", [
}];
}
+//===--===//
+// OffloadKind
+//===--===//
+
+def CIR_OffloadKind : CIR_I32EnumAttr<"OffloadKind", "offload kind", [
+ I32EnumAttrCase<"Host", 0, "host">,
+ I32EnumAttrCase<"Device", 1, "device">
+]> {
+ let genSpecializedAttr = 0;
+}
+
+def CIR_OffloadKindAttr : CIR_EnumAttr {
+ let summary = "Offload kind (host or device)";
+}
+
+//===--===//
+// OffloadContainerOp
+//===--===//
+
+def CIR_OffloadContainerOp : CIR_Op<"offload.container", [
+NoRegionArguments, NoTerminator, SingleBlock, SymbolTable]> {
+ let summary = "Container for host and device CIR modules";
+ let description = [{
+`cir.offload.container` groups one host CIR module with one or more device
+CIR modules for offload-aware analysis and transformation.
+
+The body holds nested `builtin.module` operations. The first nested
+module is the host module and must carry
+`cir.offload.kind = #cir.offload_kind`. All remaining nested
+modules are device modules and must carry
+`cir.offload.kind = #cir.offload_kind`. There must be at least
+one device module.
+
+Example:
+
+```mlir
+cir.offload.container {
+ builtin.module @host attributes {cir.offload.kind =
#cir.offload_kind} {
+ }
+ builtin.module @device_0 attributes {cir.offload.kind =
#cir.offload_kind} {
+ }
+}
+```
+ }];
+
+ let regions = (region SizedRegion<1>:$body);
+
+ let assemblyFormat = "$body attr-dict";
+
+ let hasVerifier = 1;
+ let hasLLVMLowering = false;
+
+ let extraClassDeclaration = [{
+mlir::ModuleOp getHostModule();
+llvm::iterator_range>
+getDeviceModules();
+ }];
+}
+
//===--===//
// BaseClassAddrOp
//===--===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 606b4fd9d3fa6..b36424aa31ded 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -18,6 +18,7
[clang] [CIR] Add offload container attribute (PR #206576)
github-actions[bot] wrote: # :penguin: Linux x64 Test Results The build failed before running any tests. Click on a failure below to see the details. tools/clang/include/clang/CIR/Dialect/IR/CIROps.cpp.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.cpp.inc ``` FAILED: tools/clang/include/clang/CIR/Dialect/IR/CIROps.cpp.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.cpp.inc cd /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR && /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/mlir-tblgen -gen-op-defs -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/../mlir/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/mlir/include /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIROps.td --write-if-changed -o CIROps.cpp.inc -d CIROps.cpp.inc.d && /usr/bin/cmake -E cmake_transform_depfile Ninja gccdepfile /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR /home/gha/actions-runner/_work/llvm-project/llvm-project/build /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.cpp.inc.d /home/gha/actions-runner/_work/llvm-project/llvm-project/build/CMakeFiles/d/297aa97d4942a28141fed5d98d7a7b47ed99f97ad95009e6f242827f56aab6e8.d Included from /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIROps.td:19: /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td:122:23: error: Couldn't find class 'CIR_I32EnumAttr' def CIR_OffloadKind : CIR_I32EnumAttr<"OffloadKind", "offload kind", [ ^ ``` tools/clang/include/clang/CIR/Dialect/IR/CIROps.h.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.h.inc ``` FAILED: tools/clang/include/clang/CIR/Dialect/IR/CIROps.h.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.h.inc cd /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR && /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/mlir-tblgen -gen-op-decls -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/../mlir/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/mlir/include /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIROps.td --write-if-changed -o CIROps.h.inc -d CIROps.h.inc.d && /usr/bin/cmake -E cmake_transform_depfile Ninja gccdepfile /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR /home/gha/actions-runner/_work/llvm-project/llvm-project/build /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROps.h.inc.d /home/gha/actions-runner/_work/llvm-project/llvm-project/build/CMakeFiles/d/d02f6e2d322101f4177025222c3d0ddebc6b552e28b76e179488dc79b0bd40d6.d Included from /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIROps.td:19: /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td:122:23: error: Couldn't find class 'CIR_I32EnumAttr' def CIR_OffloadKind : CIR_I32EnumAttr<"OffloadKind", "offload kind", [ ^ ``` tools/clang/include/clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc ``` FAILED:
[clang] [CIR] Add offload container attribute (PR #206576)
https://github.com/RiverDave edited https://github.com/llvm/llvm-project/pull/206576 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
RiverDave wrote: gentle ping @andykaylor :) https://github.com/llvm/llvm-project/pull/206576 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add offload container attribute (PR #206576)
RiverDave wrote: > Desing looks good. I can see you have some deviations from gpu dialect: > > 1. GPU keeps `verifyOperationAttribute` trivial, just checks the `attr` sits > on ModuleOp, and defers structural checks to reference sites. This PR front > loads the verification. It is stricter and potentially more costly. > 2. You introduce a strict ordering, host is first, gpu dialect does not > impose this. Our passes rely on `front() = host`. No strong feelings about > this, I would add a comment about it though to document the behavior. > 3. gpu.dialect uses a dedicated `gpu.module`; In your PR code lives in nested > builtin.module. This is the design you propose. I am ok with this, but before > merging I would expect to add a note confirming your design choice. > > The PR title says "Op", now it is an attribute. > > Some NITS: > > The functions `isOffloadContainer` / `getOffloadHostModule` / > `getOffloadDeviceModules` have no coverage, and currently are not being > called. It is worthwhile to add some unit tests to lock their behavior, since > next optimizations will rely on these. I've Dropped the three helpers from this patch instead of adding tests for them. They have no callers yet, so a test could only re-assert what the verifier already guarantees (host module first, device modules after), which `offload-container.cir` and `invalid-offload-container.cir` cover. They'll come back with their first consumer in the merge/split pass work, where FileCheck over the pass exercises them directly -- think it'll make it easier to review for all of us. https://github.com/llvm/llvm-project/pull/206576 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
