Files
TheRock/compiler/amd-llvm/amd/comgr/AGENT_CONVENTIONS.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

189 lines
8.6 KiB
Markdown

# Comgr Project Conventions
Conventions for working in `amd/comgr/`. Apply these to all changes
under this directory.
This file is the single source of truth for general Comgr project
conventions. The agent-tool wrappers (`amd/comgr/CLAUDE.md`,
`.cursor/rules/comgr.mdc`) point here so updates only need to be made
once.
For hotswap-subsystem-specific conventions (patch-pass authoring,
B0/A0 rewrite invariants, hotswap test driver), see
[`src/hotswap/HOTSWAP_CONVENTIONS.md`](src/hotswap/HOTSWAP_CONVENTIONS.md).
## 1. Code reuse — Comgr first, LLVM second, custom never
**Reuse existing Comgr APIs before writing new ones.** Notable hits:
- `parseTargetIdentifier()` (`src/comgr.cpp:231`) — parses an ISA string
(`amdgcn-amd-amdhsa--gfx1250:sramecc+`) into arch / vendor / OS /
environ / processor / features. Don't re-implement string parsing
for ISA names.
- `ensureLLVMInitialized()` (`src/comgr.cpp:275`) — initializes the
AMDGPU target stack with thread-safety. Don't roll your own
`std::call_once` over `LLVMInitializeAMDGPU*` calls; reuse this.
- `DisassemblyInfo::create()` (`src/comgr-disassembly.cpp:25`) — sets
up the full MC stack (Target, MRI, MAI, MCII, STI, MCContext,
MCDisassembler, MCInstPrinter). If a new feature needs a similar
bundle, refactor `DisassemblyInfo` to share, don't duplicate.
- Small refactors of existing Comgr APIs are **preferred over parallel
implementations**. If extracting a shared helper enables your reuse
story, do that.
**Reuse existing LLVM APIs second**, especially the MC layer:
- `MCCodeEmitter::encodeInstruction` for instruction encoding.
- `MCRegisterInfo::regsOverlap` for register overlap checks.
- `llvm::AMDGPU::*` from `llvm/TargetParser/TargetParser.h` for AMDGPU
target queries (`parseArchAMDGCN`, `getArchNameAMDGCN`, etc.).
- `llvm::object::ELFFile<>` for ELF parsing — don't hand-roll section
or symbol iteration.
- `llvm/Support/Compiler.h` macros for portable attributes.
**For upstream LLVM APIs that need small reworks** to be usable here:
add a `TODO` comment in the Comgr code **and** file a GitHub issue to
fix upstream. Do not implement a parallel version inside Comgr.
## 2. Code quality
- Follow LLVM coding guidelines (`BasedOnStyle: LLVM` in `.clang-format`).
Run `clang-format` on changed files before submitting.
- Apply upstream LLVM code review standards (small focused commits,
meaningful commit messages, no unrelated changes).
- **Avoid Windows-hostile code**:
- Use `LLVM_ATTRIBUTE_WEAK` (from `llvm/Support/Compiler.h`), not
`__attribute__((weak))`. MSVC does not understand the GCC syntax
and will fail to build.
- No GCC/Clang-only attributes without an LLVM-portable wrapper.
- All assembly / disassembly goes through the MC layer (e.g.,
`assembleSingleInst`, `assembleInstructions`, `parseAsmToMCInsts`). **No
hardcoded instruction opcodes or encoded byte sequences** — let the asm parser
resolve them, and round-trip through `MCCodeEmitter::encodeInstruction`
for any modification.
- When invoking the asm parser, register the SourceMgr with `MCContext`
via `MCContext::initInlineSourceManager()` so error diagnostics on
bad input don't crash with `Either SourceMgr should be available`.
- **Mnemonic identity is asm-level, not tablegen-level.**
`MCInstrInfo::getName(Opcode)` returns the tablegen pseudo name —
on gfx1250 the assembled `v_nop` has opcode name `V_NOP_e32_gfx12`,
not `V_NOP_e32`. Resolve opcodes once at init via the asm parser,
cache the resolved opcode / `MCInst`, and compare against the
cached value. Verify any new mnemonic comparison with
`llvm-mc -show-inst` against the target you care about.
**Style.** Comgr follows the canonical LLVM coding conventions; for
the full reference Read these source files (in this monorepo):
- [`llvm/docs/CodingStandards.rst`](../../llvm/docs/CodingStandards.rst)
- [`llvm/docs/AMDGPU/DeveloperGuideline.rst`](../../llvm/docs/AMDGPU/DeveloperGuideline.rst)
Comgr-specific deviations and items recurring in code review that
aren't covered upstream:
- Avoid `auto`. Comgr leans stricter than upstream LLVM here — spell
types out, including iterator types.
- ASCII only in source comments — no box-drawing dividers, no smart
quotes, no em-dashes.
- Pass `MCRegister` (not `unsigned`) until you need the encoded id.
**Error-return policy.** Don't mix signaling styles within one PR.
- Public C API: `amd_comgr_status_t`.
- Internal helpers: `bool` only when there is one meaningful failure
mode; otherwise `std::optional<T>` or `llvm::Expected<T>`.
- **No silent returns on failure.** Every failure path emits a specific
`log()` message naming what was attempted and why it failed.
- Don't return a count where 0 conflates "no candidates" with "found
candidates but couldn't process them" — that distinction matters to
downstream callers.
## 3. Testing
Comgr has three test suites:
- `test/` — legacy CTest C-based tests.
- `test-lit/` — LIT integration tests with `comgr-sources/` tool binaries.
- `test-unit/` — newer gtest-based unit tests.
**Prefer LIT tests** over gtests where the public API is reachable.
Compile a kernel with `%clang`, pipe through a LIT tool driver, verify
with `%llvm-objdump` / `%llvm-readelf` / `%FileCheck`.
- LIT inputs should be compiled with **`%clang` directly**, not through
Comgr actions (`AMD_COMGR_ACTION_ASSEMBLE_SOURCE_TO_RELOCATABLE` etc.).
Going through Comgr actions implicitly tests the Comgr compiler
pipeline alongside whatever the test is checking, which makes
failures harder to attribute.
- **Reuse existing tools in `test-lit/comgr-sources/`** rather than
adding parallel drivers. Extend an existing tool if needed (e.g.,
adding a new flag). Add a new tool only when an existing one is
genuinely a bad fit.
- When extending a shared driver, **unknown-flag handling rejects with
an error**. Silent pass-through turns typoed RUN lines into false
negatives.
- gtests in `test-unit/` are appropriate for:
- Pure functions with bit-level edge cases (e.g., encoding limits).
- Internal helpers not reachable through any public API path.
`make check-comgr` runs all three suites; the per-suite targets
(`make test`, `make test-lit`, `make test-unit`) run them individually.
**Verify under AddressSanitizer before submitting.** Comgr builds with
`-DADDRESS_SANITIZER=On` (see `CMakeLists.txt`). Re-run `make
check-comgr` against the ASAN build to catch use-after-free, leaks,
and other memory bugs that won't surface in a normal release build.
## 4. PR workflow
**One feature per PR.** Split by file-of-truth — one new
`comgr-*-X.cpp` per PR. Refactors of pre-existing Comgr code go in
their own PR; don't bundle a refactor (e.g. of `DisassemblyInfo`) into
a feature PR.
**Tests required.** Each PR is accompanied by tests aiming for 100%
code coverage of the change being added.
**Keep the branch rebased.** Resolve conflicts before requesting
review.
**Deferral protocol.** When a reviewer asks for a structural change
that would require touching code outside the PR scope:
1. Acknowledge the direction.
2. File a tracking issue and link it inline in the comment thread.
3. State the trigger condition for picking it up.
Deferring without a tracker is the failure mode — the concern gets
silently lost.
## 5. Working as an agent
These items address fingerprints that have surfaced in code review.
Self-audit your diff before pushing.
**Cite, don't claim.** Don't make "verified empirically" or "I
confirmed" claims about LLVM internals (parser behavior, codegen
choices, ABI specifics) without a citation — a link to an MC test, a
TableGen `.td`, or actual `llvm-mc` output. If you can't produce one,
downgrade the claim to "would need to verify" and verify before
letting it become an architectural justification.
**Self-audit for over-decomposition.** Grep your diff for one-line
helpers that wrap a single call (a 4-byte `memcpy` wrapped as a named
function; a `printInst` with one caller). If the helper has one caller
and is one operation, inline it.
**Self-audit for defensive checks against impossible conditions.**
"Defensive against tablegen / decoder corruption" is not a justifiable
guard — if the disassembler is producing garbage, the patch can't
recover. `REQUIRES:` LIT gates that can never fail are dead code.
Delete checks that can't fire.
**Self-audit for duplicated `llvm/` content.** Before adding a
constant, table, X-macro, or helper, grep
`llvm/include/llvm/{Object,BinaryFormat,Support,MC}/` and
`llvm/lib/Target/AMDGPU/Utils/` for the same content. If it exists
and is reachable, use it; if it exists but is target-internal, file a
tracking issue and add a `TODO` linking it.