mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-06 08:23:19 +08:00
Count comparator calls in AArch64 and Mach-O assembly
The string comparison emission test matched only x86-64 `call` instructions to unprefixed symbols, so on AArch64 and macOS hosts it counted no calls and failed its positive-count check. It now also matches AArch64 `bl` and Mach-O's leading underscore, and it runs for the host and for aarch64-linux-gnu and x86_64-macos assembly, so every host checks all three spellings.
This commit is contained in:
@@ -11,17 +11,23 @@ import { compile } from "@scriptc/compiler";
|
||||
const repoRoot = join(import.meta.dirname, "../..");
|
||||
const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests");
|
||||
|
||||
async function emittedAsm(name: string, source: string): Promise<string> {
|
||||
const key = createHash("sha256").update(source).digest("hex").slice(0, 16);
|
||||
async function emittedAsm(name: string, source: string, target: string): Promise<string> {
|
||||
const key = createHash("sha256").update(target).update(source).digest("hex").slice(0, 16);
|
||||
const outDir = join(cacheDir, `string-compare-${key}`);
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
const file = join(outDir, `${name}.ts`);
|
||||
writeFileSync(file, source);
|
||||
const saved = process.env["SCRIPTC_TARGET"];
|
||||
if (target === "host") delete process.env["SCRIPTC_TARGET"];
|
||||
else process.env["SCRIPTC_TARGET"] = target;
|
||||
const result = await compile(file, {
|
||||
outPath: join(outDir, name),
|
||||
outDir,
|
||||
backend: "llvm",
|
||||
outputKind: "asm",
|
||||
}).finally(() => {
|
||||
if (saved === undefined) delete process.env["SCRIPTC_TARGET"];
|
||||
else process.env["SCRIPTC_TARGET"] = saved;
|
||||
});
|
||||
if (!result.ok)
|
||||
throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n"));
|
||||
@@ -36,12 +42,23 @@ words.sort(order);
|
||||
console.log(words.join(","));
|
||||
`;
|
||||
|
||||
// Calls to the comparison runtime: `call`/`callq` on x86-64 and `bl` on
|
||||
// AArch64, with Mach-O's leading underscore on macOS.
|
||||
const compareCalls = (asm: string): number =>
|
||||
asm.match(/\bcall[a-z]*\s+(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g)?.length ?? 0;
|
||||
asm.match(
|
||||
/\b(?:call[a-z]*|bl)\s+_?(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g,
|
||||
)?.length ?? 0;
|
||||
|
||||
test("a three-way string comparator compares its pair once", async () => {
|
||||
const once = compareCalls(await emittedAsm("once", program("a < b ? -1 : 1")));
|
||||
const both = compareCalls(await emittedAsm("both", program("a < b ? -1 : a > b ? 1 : 0")));
|
||||
expect(once).toBeGreaterThan(0);
|
||||
expect(both).toBe(once);
|
||||
});
|
||||
// The host's assembly, and two other targets' so that every host checks the
|
||||
// x86-64, AArch64 and Mach-O spellings.
|
||||
test.each(["host", "aarch64-linux-gnu", "x86_64-macos"])(
|
||||
"a three-way string comparator compares its pair once (%s)",
|
||||
async (target) => {
|
||||
const once = compareCalls(await emittedAsm("once", program("a < b ? -1 : 1"), target));
|
||||
const both = compareCalls(
|
||||
await emittedAsm("both", program("a < b ? -1 : a > b ? 1 : 0"), target),
|
||||
);
|
||||
expect(once).toBeGreaterThan(0);
|
||||
expect(both).toBe(once);
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user