mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Mark typed-array header loads invariant (#2016)
This commit is contained in:
@@ -7,9 +7,15 @@ import type { LlvmEmitterContext } from "./expr-context.js";
|
||||
* buffer. Neither overlaps the other, a native field, array storage or a
|
||||
* module global's slot, so element stores leave header loads and global
|
||||
* receiver slots loop-invariant. Untagged accesses and calls still alias
|
||||
* every category. */
|
||||
* every category.
|
||||
*
|
||||
* Header loads are also `!invariant.load`: no store or call between the
|
||||
* construction of a view and its release changes them. Without it, a data
|
||||
* pointer load ahead of a bounds branch is sunk into the in-bounds block,
|
||||
* and LICM keeps a conditionally executed load inside the loop. */
|
||||
export function bytesHeaderAlias(host: LlvmEmitterContext): string {
|
||||
return host.memoryAliasAttachment("bytes:header");
|
||||
const tag = host.memoryAliasAttachment("bytes:header");
|
||||
return tag === "" ? "" : `${tag}, !invariant.load !{}`;
|
||||
}
|
||||
|
||||
export function bytesElementAlias(host: LlvmEmitterContext): string {
|
||||
|
||||
@@ -249,6 +249,11 @@ test("emitted loops version the body and tag typed-array memory", () => {
|
||||
const elements = /store double [^\n]*!tbaa !(\d+)/.exec(body)![1];
|
||||
const header = /load ptr, ptr [^\n]*!tbaa !(\d+)/.exec(body)![1];
|
||||
expect(elements).not.toBe(header);
|
||||
// Header loads are invariant for the view's lifetime; element accesses
|
||||
// are not.
|
||||
expect(body).toMatch(/load ptr, ptr [^\n]*, !tbaa !\d+, !invariant\.load !\{\}$/m);
|
||||
expect(body).toMatch(/load i64, ptr [^\n]*, !tbaa !\d+, !invariant\.load !\{\}$/m);
|
||||
expect(body).not.toMatch(/(load double|store double)[^\n]*invariant\.load/);
|
||||
});
|
||||
|
||||
test("loops to a typed array's length version the other typed arrays they index", () => {
|
||||
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
emitPairedLoopSafety,
|
||||
} from "./counted-loops.js";
|
||||
import { emitBytesLoopVersionGuard, type BytesLoopVersion } from "./bytes-loop-versions.js";
|
||||
import { bytesHeaderAlias } from "./bytes-alias.js";
|
||||
import { mangleLocal } from "../mangle.js";
|
||||
import { LlvmUnsupportedError } from "./unsupported.js";
|
||||
import type { LlValue } from "./expr-context.js";
|
||||
@@ -1229,10 +1230,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void {
|
||||
}
|
||||
B.line(`${inBounds} = icmp ult i32 ${narrow}, ${len}`);
|
||||
} else {
|
||||
emitter.markMemoryPointer(lenPtr, "bytes:header");
|
||||
B.line(
|
||||
`${len} = load ${emitter.sizeType}, ptr ${lenPtr}${emitter.fieldAliasAttachment(lenPtr)}`,
|
||||
);
|
||||
B.line(`${len} = load ${emitter.sizeType}, ptr ${lenPtr}${bytesHeaderAlias(emitter)}`);
|
||||
B.line(`${inBounds} = icmp ult ${emitter.sizeType} ${index}, ${len}`);
|
||||
}
|
||||
B.condBr(inBounds, lb, exit);
|
||||
|
||||
Reference in New Issue
Block a user