mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
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.
97 lines
4.0 KiB
JavaScript
97 lines
4.0 KiB
JavaScript
/* The LLVM distribution the Linux helpers link in releases: LLVM built from
|
|
* the release sources with ThinLTO and with a profile of the helper's own
|
|
* code generation (llvm.profdata.gz). scripts/build-llvm-dist.mjs builds it,
|
|
* the llvm-dist workflow attaches it to the LLVM_DIST_TAG release of this
|
|
* repository, and scripts/refresh-llvm-profile.mjs collects the profile. */
|
|
import { execFileSync } from "node:child_process";
|
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { gunzipSync } from "node:zlib";
|
|
|
|
export const LLVM_VERSION = "22.1.8";
|
|
/** The release of this repository that holds the distribution archives. A
|
|
* new profile or LLVM version gets a new tag. */
|
|
export const LLVM_DIST_TAG = "llvm-22.1.8-pgo.1";
|
|
export const llvmProfile = fileURLToPath(new URL("./llvm.profdata.gz", import.meta.url));
|
|
|
|
/** The archive name for a Linux architecture (`x64` or `arm64`). */
|
|
export function llvmDistAsset(arch) {
|
|
return `scriptc-llvm-${LLVM_VERSION}-linux-${arch}.tar.xz`;
|
|
}
|
|
|
|
/** Writes the uncompressed profile into `dir` and returns its path. */
|
|
export function writeLlvmProfile(dir, profile = llvmProfile) {
|
|
mkdirSync(dir, { recursive: true });
|
|
const path = join(dir, "llvm.profdata");
|
|
writeFileSync(path, gunzipSync(readFileSync(profile)));
|
|
return path;
|
|
}
|
|
|
|
/** CMake arguments for an LLVM build with the helper's targets, static,
|
|
* without tools or tests. `profile` builds with that indexed profile and
|
|
* ThinLTO; `instrumented` builds the IR-instrumented libraries the profile
|
|
* is collected with. clang and lld come from PATH and must be LLVM_VERSION,
|
|
* since the profile's format and hashes follow the compiler. */
|
|
export function llvmCmakeArgs({ source, build, prefix, profile, instrumented }) {
|
|
const version = execFileSync("clang", ["--version"], { encoding: "utf8" });
|
|
if (!version.includes(`clang version ${LLVM_VERSION}`))
|
|
throw new Error(`the LLVM distribution is built with clang ${LLVM_VERSION}; found ${version}`);
|
|
return [
|
|
"-S",
|
|
join(source, "llvm"),
|
|
"-B",
|
|
build,
|
|
"-G",
|
|
"Ninja",
|
|
"-DCMAKE_BUILD_TYPE=Release",
|
|
`-DCMAKE_INSTALL_PREFIX=${prefix}`,
|
|
"-DCMAKE_C_COMPILER=clang",
|
|
"-DCMAKE_CXX_COMPILER=clang++",
|
|
"-DLLVM_USE_LINKER=lld",
|
|
"-DLLVM_TARGETS_TO_BUILD=X86;AArch64;WebAssembly",
|
|
"-DLLVM_ENABLE_PROJECTS=",
|
|
"-DLLVM_ENABLE_ASSERTIONS=OFF",
|
|
"-DLLVM_ENABLE_ZLIB=FORCE_ON",
|
|
"-DLLVM_ENABLE_ZSTD=FORCE_ON",
|
|
"-DLLVM_USE_STATIC_ZSTD=ON",
|
|
"-DLLVM_ENABLE_TERMINFO=OFF",
|
|
"-DLLVM_ENABLE_LIBXML2=OFF",
|
|
"-DLLVM_ENABLE_LIBEDIT=OFF",
|
|
"-DLLVM_ENABLE_LIBPFM=OFF",
|
|
"-DLLVM_INCLUDE_TESTS=OFF",
|
|
"-DLLVM_INCLUDE_EXAMPLES=OFF",
|
|
"-DLLVM_INCLUDE_BENCHMARKS=OFF",
|
|
"-DLLVM_INCLUDE_DOCS=OFF",
|
|
"-DLLVM_BUILD_TOOLS=OFF",
|
|
...(instrumented ? ["-DLLVM_BUILD_INSTRUMENTED=IR", "-DLLVM_BUILD_RUNTIME=OFF"] : []),
|
|
...(profile ? ["-DLLVM_ENABLE_LTO=Thin", `-DLLVM_PROFDATA_FILE=${profile}`] : []),
|
|
];
|
|
}
|
|
|
|
/** Extra CMake arguments for a Linux helper package build. With
|
|
* SCRIPTC_LLVM_THINLTO=1, LLVM_DIR names a distribution from
|
|
* scripts/build-llvm-dist.mjs: its archives hold ThinLTO bitcode, so the
|
|
* helper compiles and links with clang, lld and ThinLTO, and its own sources
|
|
* use the same profile. SCRIPTC_LLVM_PROFILE_GENERATE=1 instruments the
|
|
* helper's sources against an instrumented LLVM. */
|
|
export function helperLlvmDistArgs(build) {
|
|
const args = [];
|
|
if (process.env.SCRIPTC_LLVM_THINLTO === "1")
|
|
args.push(
|
|
"-DCMAKE_C_COMPILER=clang",
|
|
"-DCMAKE_CXX_COMPILER=clang++",
|
|
"-DSCRIPTC_LLVM_THINLTO=ON",
|
|
`-DSCRIPTC_LLVM_PROFILE_USE=${writeLlvmProfile(build)}`,
|
|
);
|
|
else args.push("-DSCRIPTC_LLVM_THINLTO=OFF", "-DSCRIPTC_LLVM_PROFILE_USE=");
|
|
if (process.env.SCRIPTC_LLVM_PROFILE_GENERATE === "1")
|
|
args.push(
|
|
"-DCMAKE_C_COMPILER=clang",
|
|
"-DCMAKE_CXX_COMPILER=clang++",
|
|
"-DSCRIPTC_LLVM_PROFILE_GENERATE=ON",
|
|
);
|
|
else args.push("-DSCRIPTC_LLVM_PROFILE_GENERATE=OFF");
|
|
return args;
|
|
}
|