Files
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

8.6 KiB

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.

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):

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.