Skip to content

[WIP][Fix] Fix lld invocation failed when ROCm is not at the baked-in path - #987

Open
jli-melchior wants to merge 2 commits into
mainfrom
jli/fix-lld-issue
Open

[WIP][Fix] Fix lld invocation failed when ROCm is not at the baked-in path#987
jli-melchior wants to merge 2 commits into
mainfrom
jli/fix-lld-issue

Conversation

@jli-melchior

Copy link
Copy Markdown
Collaborator

Motivation

Technical Details

Test Plan

Test Result

Submission Checklist

@jli-melchior jli-melchior changed the title [Fix] Fix lld invocation failed when ROCm is not at the baked-in path [WIP][Fix] Fix lld invocation failed when ROCm is not at the baked-in path Aug 8, 2026
`gpu-module-to-binary` spawns `<toolkit>/llvm/bin/ld.lld`, where `<toolkit>`
comes from ROCM_PATH/ROCM_ROOT/ROCM_HOME or from `__DEFAULT_ROCM_PATH__`, a
path baked into the LLVM build. Any container that installs ROCm somewhere
else fails, and upstream reports only `lld invocation failed` without naming
the path it tried. Our own LLVM bakes in the build machine's ROCm wheel path,
so an image switch is enough to break it.

Add `fly-emit-gpu-binary`, a wrapper that runs upstream only as far as
`format=isa` -- which returns before the toolkit is consulted -- then finishes
in process: `mlir::ROCDL::assembleIsa` for the AMDGPU MC assembler and the LLD
ELF driver for the link. That removes the lookup entirely and pins the linker
to the LLVM revision that produced the ISA.

LLD is resolved from the same install that provides MLIR, with NO_DEFAULT_PATH
so a mismatched system LLD can never be picked up, and is linked statically
into the shared library. An LLVM built without the lld project keeps the
upstream behavior via FLYDSL_HAS_LLD_LIBRARY.

Two details are carried over from Triton's equivalent change (#7548):
`--threads=1`, because LLD's use of the LLVM thread pool deadlocks in
`~TaskGroup()` inside a forked child, and checking `canRunAgain`, because a
JIT links thousands of times per process and must not continue on corrupted
linker state.

The FLYDSL_COMPILE_LLVM_DIR path still uses `gpu-module-to-binary`: it drives
an upstream mlir-opt that does not know FlyDSL passes.

Verified on the same IR with ROCM_PATH pointing at a nonexistent directory:
upstream reports `lld invocation failed`, the new pass emits a valid
ET_DYN/EM_AMDGPU `gpu.binary`. Full tests/unit + tests/system swept per file
against the upstream pass: identical results.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ntainer

Linking in process removed the ld.lld lookup, but `appendStandardLibs()` still
reads `<toolkit>/amdgcn/bitcode` whenever a module references `__ocml_*` or
`__ockl_*`, and errors out if that directory is absent. FlyDSL reaches it:
`convert-gpu-to-rocdl` pulls in MathToROCDL, so scalar math ops with no LLVM
intrinsic lower to ocml calls -- `fx.erfc` becomes `__ocml_erfc_f32`. So the
per-image path problem survived in the device-library half.

Bundle the bitcode the way Triton does. CMake locates ocml/ockl/hip/opencl at
configure time (ROCM_PATH/ROCM_ROOT/ROCM_HOME or /opt/rocm, overridable with
-DFLYDSL_ROCM_BITCODE_DIR) and copies them into the package; those four are the
complete set appendStandardLibs() can request, since the oclc_* control
variables are synthesized in-module rather than read from disk. They land under
`_mlir/`, which is already the packaged build-output subtree, so the editable
symlink and the wheel's package_dir mapping carry them with no new plumbing.

`rocm_toolkit_path()` then resolves FLYDSL_COMPILE_ROCM_PATH, the bundled tree,
and ROCM_PATH/ROCM_ROOT/ROCM_HOME in that order and passes the winner as
`toolkit=`. Finding nothing passes no option at all, leaving upstream's lookup
untouched rather than forcing a known-bad path on it.

`RocmBackend.hash()` folds the bitcode digest into the JIT cache key: swapping
ocml.bc changes generated code without changing any FlyDSL shared library, so
the native-library hashes alone would serve stale artifacts.

Verified with ROCM_PATH/ROCM_ROOT/ROCM_HOME all unset: a kernel calling
fx.erfc compiles and runs. Hiding the bundled ocml.bc makes that same
compilation fail on the bundled path, confirming which copy is consumed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant