# Contributing to rocjitsu ## General principles - **Extend existing libraries** rather than adding new ones. Check `lib/util/`, `lib/simdojo/`, and `lib/rocjitsu/` before introducing a dependency or writing something from scratch. - **Follow the existing architecture.** See [docs/architecture.md](docs/architecture.md) for the component overview and where things live. - **Never manually edit autogenerated files.** ISA decoders, execute bodies, legalization tables, and encoding translators are generated by the `amdisa` codegen pipeline. Edit the generator (`lib/python/amdisa/codegen/_generator.py`), regenerate, and commit all generated output. See [docs/codegen.md](docs/codegen.md). ## Where things live | What you're adding | Where it goes | |---|---| | GPU hardware component (cache, queue, CU logic) | `lib/rocjitsu/src/rocjitsu/vm/amdgpu/` | | ISA instruction semantics | `lib/python/amdisa/codegen/_generator.py` (regenerate) | | Hand-written ISA support (address calc, matrix math) | `lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu//` | | KFD ioctl or interposer hook | `lib/rocjitsu/src/rocjitsu/kmd/linux/` | | Binary translation rule or expansion | `lib/rocjitsu/src/rocjitsu/code/dbt/` | | Binary instrumentation pass | `lib/rocjitsu/src/rocjitsu/code/patch/` | | Code object loading or ELF mutation | `lib/rocjitsu/src/rocjitsu/code/` | | Register liveness or def-use analysis | `lib/rocjitsu/src/rocjitsu/analysis/` | | Simulation engine (events, topology, PDES) | `lib/simdojo/` | | Shared utility (bit ops, logging, SIMD, allocators) | `lib/util/` | | JSON config schema change | `schemas/` + `lib/rocjitsu/src/rocjitsu/config/` | | CLI changes | `tools/rocjitsu/` | | New GPU topology config | `configs/` | | Tests | `tests/` (mirror the source structure: `tests/dbt/`, `tests/analysis/`, `tests/patch/`, etc.) | ## Libraries to use Before writing new infrastructure, check these existing libraries: - **Logging** — Use `util/log.h` (`Logger::print<>()`), never `fprintf` or `std::cerr`. Build with or without tracing via the logger's compile-time group filters. - **Bit manipulation** — `util/bit.h` and `util/bitfield.h` cover masks, extraction, insertion, and typed bitfield access. - **Data types** — `util/data_types.h` provides FP16/BF16/FP8/BF8/FP4/FP6 conversions. Extend it rather than adding ad-hoc converters. - **SIMD** — `util/simd.h` wraps `` with scalar fallback. Add new SIMD primitives here, not inline in ISA execute bodies. - **Intrusive list** — `util/intrusive_list.h` for linked data structures that need O(1) insert/erase without heap allocation per node. - **Arena allocator** — `util/arena_alloc.h` for fixed-size block pools. - **Exceptions** — `util/except.h` for `InvalidInst`, `UnimplementedInst`, `ConfigError`. - **Register sets** — `isa/register_set.h` for ISA-independent register file modeling (SGPR/VGPR/AccVGPR bitsets). - **Spill manager** — `code/patch/spill_manager.h` for scratch layout planning (DBI spill/fill slots). - **Instruction builder** — `code/patch/instruction_builder.h` for encoding common instructions (`s_branch`, `s_nop`, etc.). ## Code style - **C++20.** Use standard library features (concepts, ranges, `std::format`). - **Formatting.** The repo uses pre-commit hooks (clang-format for C++, black for Python, gersemi for CMake). Install once and run before every commit: ```bash pip install pre-commit pre-commit install pre-commit run --all-files ``` The config lives at the repo root (`rocm-systems/.pre-commit-config.yaml`). - **Naming.** Use clear, descriptive names. No single-letter variables. Non-trivial types with methods must be `class` (not `struct`). Maintain `public:` / `protected:` / `private:` ordering. - **Comments.** Use `@brief` / `@details` doxygen style when documenting public APIs. Avoid decorative comment lines (`---`, `===`). Default to writing no comments; only comment when the *why* is non-obvious. - **No `fprintf`.** Always use `Logger` from `util/log.h`. - **Exceptions.** Exceptions are used only for unrecoverable errors during initialization and configuration (`ConfigError`) or when encountering invalid/unimplemented instructions during code object parsing (`InvalidInst`, `UnimplementedInst`). All exception types live in `util/except.h`. Do not throw exceptions in simulation hot paths (event handlers, instruction execution, cache lookups). Do not add `try`/`catch` blocks unless you are at a boundary that must translate an error (e.g., the C API layer). There is no general exception safety guarantee — assume code is not exception-safe unless explicitly documented. ## ISA codegen workflow When modifying instruction semantics or adding instruction support: 1. Edit `lib/python/amdisa/codegen/_generator.py` (never the generated C++ files) 2. Regenerate with `--multi` mode (see [docs/codegen.md](docs/codegen.md)) 3. Format the generated files with `clang-format` 4. Stage ALL generated files before committing ## Testing - Add tests for new functionality. Place them in `tests/` mirroring the source directory structure. - Run the test suite: `ctest --test-dir build` - Run Python tests: `cd lib/python && python -m pytest amdisa/tests/ -x` - Ensure zero compiler warnings before submitting. ## Proposing architectural changes Large changes that affect the component structure, add new subsystems, change public APIs, or modify the translation/instrumentation pipeline must be proposed before implementation. Open a GitHub issue with: - A clear title describing the proposed change - A markdown document (attached or inline) covering: - **Motivation** — What problem does this solve and why now? - **Design** — Proposed architecture, component interactions, data flow - **Alternatives considered** — What else was evaluated and why it was rejected - **Migration / compatibility** — Impact on existing code, tests, and users - **Scope** — What is and is not included in the change Wait for maintainer review and approval before starting implementation. This avoids wasted effort on changes that conflict with the project direction or duplicate ongoing work. Examples of changes that require a proposal: - Adding a new translation pair or instrumentation pass - Changing the KFD ioctl interface or RPC protocol - Restructuring the simulation engine or cache hierarchy - Introducing new external dependencies Bug fixes, test additions, and localized improvements do not need a proposal — open a PR directly. ## Commit hygiene - Never commit buggy or untested code. Verify end-to-end first. - Write concise commit messages focused on the *why*, not the *what*. - When regenerating ISA files, include all generated output in the same commit as the generator change.