# brintOS LLVM (the `wasm32-hwjs` toolchain)

This is the brintOS pin of [llvm-project](https://github.com/llvm/llvm-project).
It provides the `clang` / `wasm-ld` / `opt` / `libLLVM` that the brintOS
WebAssembly toolchain is built on:

- **[`hwjs-cc`](../hwjs-cc)** builds its `HwjsCoroutinize` pass as an out-of-tree
  LLVM plugin and loads it into *this* clang via `-fpass-plugin`. clang has no
  stable plugin ABI across versions, so the pass must be built against the exact
  LLVM below.
- The brintOS **Linux kernel** and **userland packages** (musl/glibc, bash,
  coreutils) compile through this clang targeting `wasm32`.

## Pin

This is a **fork**, not a stock rebuild: an upstream LLVM base **plus the brintOS
`wasm32-hwjs` patches** that the coroutine pass, the kernel, and the glibc port
require. It is therefore **not** behaviour-neutral vs stock/emsdk LLVM — you
cannot substitute an off-the-shelf clang.

| Field | Value |
|-------|-------|
| Upstream base | ~`60513b8d` (clang / LLVM / LLD `22.0.0git`) |
| Fork HEAD | this submodule's `HEAD` — the base + the patches below (`git log --oneline`) |
| Projects | `clang;lld` |
| Targets | `X86;WebAssembly` (X86 host tools + the wasm backend) |
| Build type | `Release`, assertions OFF |

### brintOS patches on top of the base

Compiling the kernel + musl/glibc through `HwjsCoroutinize` exercises code paths
stock LLVM mishandles, so the fork carries fixes not yet upstream:

- **CoroSplit** — split `indirectbr` critical edges before `rewritePHIs`,
  relocate `blockaddress` jump tables across a split, and don't frame an
  escaped-but-not-suspend-crossing dynamic `alloca` (the `printf`/locale/glibc
  crashes).
- **`wasm-ld` (lld)** — apply non-PIC absolute TLS relocations in
  `__wasm_apply_tls_relocs` (glibc `__thread` init), plus symbol-type/reloc fixes
  glibc surfaced.
- **MC / assembler** — accept glibc's assembler idioms (idempotent
  absolute-constant symbol assignment, `.symver`, section/type directives).

`git log --oneline` in this submodule is the authoritative patch list. The base
tracks the LLVM emsdk shipped at ~`60513b8d` (the swap *was* behaviour-neutral
before these patches landed); see
[`../hwjs-cc/toolchain/llvm-from-source.md`](../hwjs-cc/toolchain/llvm-from-source.md)
for the finding trail.

## Cloning (git transports)

The brintOS forge is **SSH-only on its own host**: `https://git.brintos.io/...`
does not serve git at all (connections hang/time out). Use one of:

```bash
git clone git@git.brintos.io:brintos/llvm-project.git          # SSH (read/write)
git clone https://brintos.io/brintos/llvm-project.git          # HTTPS (read), via the main site
```

Both verified empirically; the same pattern (`git@git.brintos.io:<owner>/<repo>.git`
/ `https://brintos.io/<owner>/<repo>.git`) applies to every `brintos/*` repo.

## Build

One command (configures + builds only what the toolchain needs):

```bash
./build-brintos.sh              # -> build/bin/{clang,clang++,wasm-ld,opt,llvm-config,...}
./build-brintos.sh -j 8         # cap parallelism
BUILD_DIR=/tmp/llvm ./build-brintos.sh
```

Besides clang/lld/opt/llvm-config, the script also builds the LLVM binutils the
downstream builds invoke — `llvm-ar`, `llvm-nm`, `llvm-ranlib`, `llvm-link`,
`llvm-objcopy`, `llvm-strip`, `llvm-objdump`, `llvm-readelf`. The wasm32 kernel
build (Kbuild `LLVM=1`) and hwjs-cc's `wasmld` bitcode merge require them; a
stock `ninja clang lld` build does not produce them, and a from-clean
`make kernel` would otherwise stop at its first `OBJCOPY` step.

From the super-repo root this is also wired as **`make llvm`** (`make llvm JOBS=8`
to cap parallelism).

This is the same configuration `hwjs-cc` and the distros expect at
`toolchains/llvm-project/build`. `hwjs-cc/toolchain/find-llvm.sh` discovers this
build automatically.

### Why these flags

`-fpass-plugin` `dlopen`s the pass `.so`, which must resolve LLVM symbols against
the *compiling clang*. So the build **must** enable:

- `LLVM_BUILD_LLVM_DYLIB=ON` + `LLVM_LINK_LLVM_DYLIB=ON` — clang and the plugin
  bind to one `libLLVM.so`, so the new-PM pass registration is found.
- `LLVM_ENABLE_PLUGINS=ON` + `CLANG_PLUGIN_SUPPORT=ON` — keep the loader paths in.
- `opt` + `llvm-config` — the pass CMake needs `llvm-config`; the drivers use
  `opt` for the glibc DCE pre-pass.

A clang built without these silently cannot host the pass — the exact wall the
old docs hit (finding **F10** in `hwjs-cc`).
