Files
scriptc/native/llvm-codegen/linux-helper.mjs
T
Chris Tate 4c3a1d9c98 Link the Linux release helpers against LLVM built with ThinLTO and a helper profile
The Linux helpers linked LLVM 22.1.8's release archive. The helper's code
generation is LLVM's code, so building that LLVM from its release sources
with ThinLTO and with a profile of the helper's own work makes code
generation 5-9% faster than the helper as released, with identical objects.

- native/llvm-codegen/llvm.profdata.gz is the profile, collected by
  scripts/refresh-llvm-profile.mjs: it builds LLVM with IR instrumentation
  and an instrumented helper, and runs that helper on tsc-ts, five Effect
  fixtures, the runtime benchmark workloads and every 50th corpus program
  (scripts/llvm-helper-inputs.mjs). It follows LLVM's sources, so it needs
  a refresh when LLVM is bumped.
- scripts/build-llvm-dist.mjs builds LLVM with that profile and ThinLTO,
  and packs it with a checksum. The llvm-dist workflow, run by hand, builds
  it for x64 and arm64, requires a helper linked against it to give the
  same objects as one linked against the release archive
  (scripts/check-llvm-dist.mjs), prints both helpers' times and the
  profile's mismatch count, and attaches the archive to the LLVM_DIST_TAG
  release of this repository.
- The release workflow's Linux jobs, and the wasm32-wasi job, which also
  uploads the x64 GNU helper, download that archive and build the helper
  with SCRIPTC_LLVM_THINLTO=1: clang, lld and ThinLTO, and the profile for
  the helper's own sources. Without the archive, or if that build fails,
  the helper links the release archive as before.
- The four Linux helper packages share their build in
  native/llvm-codegen/linux-helper.mjs. Without SCRIPTC_LLVM_THINLTO it
  builds the same executable as before.
2026-10-25 18:53:25 -05:00

80 lines
2.9 KiB
JavaScript

/* The static Linux helper build shared by the four Linux helper packages,
* scripts/refresh-llvm-profile.mjs and scripts/check-llvm-dist.mjs. */
import { execFileSync } from "node:child_process";
import {
chmodSync,
copyFileSync,
existsSync,
mkdirSync,
readFileSync,
rmSync,
writeFileSync,
} from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { helperLlvmDistArgs } from "./llvm-dist.mjs";
import { nativeTargetCmakeArgs } from "./targets.mjs";
const DATA_LAYOUTS = {
x64: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
arm64:
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
};
/** Configures and builds the helper for `arch` (`x64` or `arm64`) and `libc`
* (`gnu` or `musl`) in `build` against LLVM_DIR, and writes the stripped
* executable to `output`. musl builds take the compilers from CC and CXX. */
export function buildLinuxHelper({ arch, libc, version, build, output }) {
const triple = `${arch === "x64" ? "x86_64" : "aarch64"}-unknown-linux-${libc}`;
// CMake drops the other definitions when a reconfigure changes the
// compiler, so a build directory configured for another LLVM or build
// kind starts over.
const kind = JSON.stringify({
llvm: process.env.LLVM_DIR ?? null,
thinLTO: process.env.SCRIPTC_LLVM_THINLTO === "1",
profileGenerate: process.env.SCRIPTC_LLVM_PROFILE_GENERATE === "1",
cc: process.env.CC ?? null,
cxx: process.env.CXX ?? null,
});
const stamp = join(build, "scriptc-helper-build.json");
if (existsSync(build) && (!existsSync(stamp) || readFileSync(stamp, "utf8") !== kind))
rmSync(build, { recursive: true, force: true });
mkdirSync(build, { recursive: true });
writeFileSync(stamp, kind);
execFileSync(
"cmake",
[
"-S",
fileURLToPath(new URL(".", import.meta.url)),
"-B",
build,
"-G",
"Ninja",
...(libc === "musl"
? [
`-DCMAKE_C_COMPILER=${process.env.CC ?? "cc"}`,
`-DCMAKE_CXX_COMPILER=${process.env.CXX ?? "c++"}`,
]
: []),
`-DLLVM_DIR=${process.env.LLVM_DIR ?? "/usr/lib/llvm-22/lib/cmake/llvm"}`,
`-DSCRIPTC_PACKAGE_VERSION=${version}`,
`-DSCRIPTC_DEFAULT_TARGET=${triple}`,
`-DSCRIPTC_DEFAULT_DATA_LAYOUT=${DATA_LAYOUTS[arch]}`,
...nativeTargetCmakeArgs,
"-DSCRIPTC_STATIC_LINUX_BUILD=ON",
"-DCMAKE_EXE_LINKER_FLAGS=-static",
"-DCMAKE_BUILD_TYPE=Release",
// Later definitions win, so these can select clang for musl builds.
...helperLlvmDistArgs(build),
],
{ stdio: "inherit" },
);
execFileSync("cmake", ["--build", build, "--target", "scriptc-llvm-codegen"], {
stdio: "inherit",
});
mkdirSync(dirname(output), { recursive: true });
copyFileSync(join(build, "scriptc-llvm-codegen"), output);
execFileSync("strip", [output], { stdio: "inherit" });
chmodSync(output, 0o755);
}