Skip to content

Commit 2d657f4

Browse files
committed
[v2] perf: o3+aggressive codegen; narrow-globals: extend to mul/rem and any-int-pure rhs
1 parent 668521f commit 2d657f4

3 files changed

Lines changed: 82 additions & 73 deletions

File tree

src/codegen/llvm-bridge.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export const LLVMInternalLinkage = 8;
133133
export const LLVMPrivateLinkage = 9;
134134
export const LLVMCodeGenLevelNone = 0;
135135
export const LLVMCodeGenLevelDefault = 2;
136+
export const LLVMCodeGenLevelAggressive = 3;
136137
export const LLVMRelocPIC = 1;
137138
export const LLVMCodeModelDefault = 0;
138139
export const LLVMObjectFileType = 1;
@@ -432,12 +433,12 @@ export class LLVMModule {
432433
const target = chad2_LLVMGetTargetFromTriple(triple);
433434
if (target === "") throw new Error("Failed to get target from triple");
434435

435-
const tm = LLVMCreateTargetMachine(target, triple, "generic", "",
436-
LLVMCodeGenLevelDefault, LLVMRelocPIC, LLVMCodeModelDefault);
436+
const tm = LLVMCreateTargetMachine(target, triple, "", "",
437+
LLVMCodeGenLevelAggressive, LLVMRelocPIC, LLVMCodeModelDefault);
437438
const dl = LLVMCreateTargetDataLayout(tm);
438439
LLVMSetModuleDataLayout(this.mod, dl);
439440

440-
if (chad2_LLVMRunPasses(this.mod, "default<O2>", tm) !== 0) {
441+
if (chad2_LLVMRunPasses(this.mod, "default<O3>", tm) !== 0) {
441442
throw new Error("LLVM optimization passes failed");
442443
}
443444

src/codegen/llvm.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ const LLVMPrintModuleToFile = lib.func("LLVMPrintModuleToFile", Bool, [
132132
const LLVMDisposeMessage = lib.func("LLVMDisposeMessage", "void", [Ref]);
133133

134134
const LLVMGetDefaultTargetTriple = lib.func("LLVMGetDefaultTargetTriple", "char *", []);
135+
const LLVMGetHostCPUName = lib.func("LLVMGetHostCPUName", "char *", []);
136+
const LLVMGetHostCPUFeatures = lib.func("LLVMGetHostCPUFeatures", "char *", []);
135137
const LLVMGetTargetFromTriple = lib.func("LLVMGetTargetFromTriple", Bool, [
136138
"str",
137139
koffi.out(koffi.pointer(Ref)),
@@ -261,6 +263,7 @@ export const LLVMRealUNO = 8;
261263
export const LLVMInternalLinkage = 8;
262264
export const LLVMPrivateLinkage = 9;
263265
export const LLVMCodeGenLevelDefault = 2;
266+
export const LLVMCodeGenLevelAggressive = 3;
264267
export const LLVMRelocPIC = 1;
265268
export const LLVMCodeModelDefault = 0;
266269
export const LLVMObjectFileType = 1;
@@ -682,9 +685,9 @@ export class LLVMModule {
682685
const tm = LLVMCreateTargetMachine(
683686
target,
684687
triple,
685-
"generic",
686688
"",
687-
LLVMCodeGenLevelDefault,
689+
"",
690+
LLVMCodeGenLevelAggressive,
688691
LLVMRelocPIC,
689692
LLVMCodeModelDefault,
690693
);
@@ -693,7 +696,7 @@ export class LLVMModule {
693696
LLVMSetModuleDataLayout(this.mod, dl);
694697

695698
const passOpts = LLVMCreatePassBuilderOptions();
696-
const passErr = LLVMRunPasses(this.mod, "default<O2>", tm, passOpts);
699+
const passErr = LLVMRunPasses(this.mod, "default<O3>", tm, passOpts);
697700
LLVMDisposePassBuilderOptions(passOpts);
698701
if (passErr !== null) {
699702
const msg = LLVMGetErrorMessage(passErr);

src/transforms/narrow-globals.ts

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { HIRModule, HIRExpr, HIRStmt, HIRFunction } from "../hir/types.js";
22
import { I64, F64 } from "../hir/types.js";
33

4-
const SAFE_OPS = new Set(["add", "sub"]);
4+
const SAFE_OPS = new Set(["add", "sub", "mul", "rem"]);
55
const CMP_OPS = new Set(["eq", "ne", "lt", "le", "gt", "ge"]);
66
const ARITH_OPS = new Set(["add", "sub", "mul", "rem"]);
77

@@ -19,116 +19,120 @@ function isIntLiteralInit(e: HIRExpr | undefined): boolean {
1919
return false;
2020
}
2121

22-
function isSafeIntPureExpr(expr: HIRExpr, name: string): boolean {
22+
function isSafeIntPureExpr(expr: HIRExpr, name: string, eligible: Set<string>): boolean {
2323
switch (expr.kind) {
2424
case "literal_i64":
2525
return true;
2626
case "literal_f64":
2727
return Number.isInteger(expr.value) && Math.abs(expr.value) <= Number.MAX_SAFE_INTEGER;
2828
case "global_get":
29-
return expr.name === name;
29+
if (expr.name === name) return true;
30+
if (eligible.has(expr.name)) return true;
31+
return expr.type.kind === "i64";
32+
case "local_get":
33+
return expr.type.kind === "i64";
3034
case "binary":
3135
if (!SAFE_OPS.has(expr.op)) return false;
32-
return isSafeIntPureExpr(expr.left, name) && isSafeIntPureExpr(expr.right, name);
36+
return isSafeIntPureExpr(expr.left, name, eligible) && isSafeIntPureExpr(expr.right, name, eligible);
3337
case "widen_f64":
3438
case "narrow_i64":
35-
return isSafeIntPureExpr(expr.value, name);
39+
return isSafeIntPureExpr(expr.value, name, eligible);
3640
default:
3741
return false;
3842
}
3943
}
4044

41-
function visitExpr(expr: HIRExpr, info: Map<string, GlobalState>): void {
45+
function visitExpr(expr: HIRExpr, info: Map<string, GlobalState>, candidates: Set<string>): void {
4246
if (expr.kind === "global_set") {
4347
const cur = info.get(expr.name);
44-
if (cur && !isSafeIntPureExpr(expr.value, expr.name)) cur.hasIncompatibleWrite = true;
45-
visitExpr(expr.value, info);
48+
if (cur && !isSafeIntPureExpr(expr.value, expr.name, candidates)) cur.hasIncompatibleWrite = true;
49+
visitExpr(expr.value, info, candidates);
4650
return;
4751
}
4852
switch (expr.kind) {
4953
case "binary":
50-
visitExpr(expr.left, info);
51-
visitExpr(expr.right, info);
54+
visitExpr(expr.left, info, candidates);
55+
visitExpr(expr.right, info, candidates);
5256
return;
5357
case "unary":
54-
visitExpr(expr.operand, info);
58+
visitExpr(expr.operand, info, candidates);
5559
return;
5660
case "call":
5761
case "runtime_call":
58-
for (const a of expr.args) visitExpr(a, info);
62+
for (const a of expr.args) visitExpr(a, info, candidates);
5963
return;
6064
case "vtable_call":
61-
visitExpr(expr.object, info);
62-
for (const a of expr.args) visitExpr(a, info);
65+
visitExpr(expr.object, info, candidates);
66+
for (const a of expr.args) visitExpr(a, info, candidates);
6367
return;
6468
case "call_closure":
65-
visitExpr(expr.callee, info);
66-
for (const a of expr.args) visitExpr(a, info);
69+
visitExpr(expr.callee, info, candidates);
70+
for (const a of expr.args) visitExpr(a, info, candidates);
6771
return;
6872
case "conditional":
69-
visitExpr(expr.condition, info);
70-
visitExpr(expr.then, info);
71-
visitExpr(expr.else, info);
73+
visitExpr(expr.condition, info, candidates);
74+
visitExpr(expr.then, info, candidates);
75+
visitExpr(expr.else, info, candidates);
7276
return;
7377
case "field_get":
74-
visitExpr(expr.object, info);
78+
visitExpr(expr.object, info, candidates);
7579
return;
7680
case "field_set":
77-
visitExpr(expr.object, info);
78-
visitExpr(expr.value, info);
81+
visitExpr(expr.object, info, candidates);
82+
visitExpr(expr.value, info, candidates);
7983
return;
8084
case "index_get":
81-
visitExpr(expr.array, info);
82-
visitExpr(expr.index, info);
85+
visitExpr(expr.array, info, candidates);
86+
visitExpr(expr.index, info, candidates);
8387
return;
8488
case "index_set":
85-
visitExpr(expr.array, info);
86-
visitExpr(expr.index, info);
87-
visitExpr(expr.value, info);
89+
visitExpr(expr.array, info, candidates);
90+
visitExpr(expr.index, info, candidates);
91+
visitExpr(expr.value, info, candidates);
8892
return;
8993
case "local_set":
90-
visitExpr(expr.value, info);
94+
visitExpr(expr.value, info, candidates);
9195
return;
9296
case "narrow_i64":
9397
case "widen_f64":
9498
case "box":
9599
case "unbox":
96100
case "await":
97101
case "wrap_interface":
98-
visitExpr(expr.value, info);
102+
visitExpr(expr.value, info, candidates);
99103
return;
100104
case "alloc_array":
101-
for (const v of expr.initialValues) visitExpr(v, info);
105+
for (const v of expr.initialValues) visitExpr(v, info, candidates);
102106
return;
103107
case "alloc_struct":
104-
for (const v of expr.fields) visitExpr(v, info);
108+
for (const v of expr.fields) visitExpr(v, info, candidates);
105109
return;
106110
case "alloc_dynobj":
107-
for (const p of expr.props as any[]) visitExpr(p.value, info);
108-
if (expr.spreadSource) visitExpr(expr.spreadSource, info);
111+
for (const p of expr.props as any[]) visitExpr(p.value, info, candidates);
112+
if (expr.spreadSource) visitExpr(expr.spreadSource, info, candidates);
109113
return;
110114
case "alloc_dynarray":
111-
for (const v of expr.elements as any[]) visitExpr(v, info);
115+
for (const v of expr.elements as any[]) visitExpr(v, info, candidates);
112116
return;
113117
case "alloc_array_spread":
114-
for (const e of expr.elements as any[]) visitExpr(e.value, info);
118+
for (const e of expr.elements as any[]) visitExpr(e.value, info, candidates);
115119
return;
116120
case "alloc_map":
117121
for (const e of expr.entries as any[]) {
118-
visitExpr(e.key, info);
119-
visitExpr(e.value, info);
122+
visitExpr(e.key, info, candidates);
123+
visitExpr(e.value, info, candidates);
120124
}
121125
return;
122126
case "alloc_set":
123-
for (const v of expr.elements as any[]) visitExpr(v, info);
127+
for (const v of expr.elements as any[]) visitExpr(v, info, candidates);
124128
return;
125129
case "nullish_coalesce":
126-
visitExpr(expr.left, info);
127-
visitExpr(expr.right, info);
130+
visitExpr(expr.left, info, candidates);
131+
visitExpr(expr.right, info, candidates);
128132
return;
129133
case "array_hof":
130-
visitExpr(expr.array, info);
131-
visitExpr(expr.callback, info);
134+
visitExpr(expr.array, info, candidates);
135+
visitExpr(expr.callback, info, candidates);
132136
return;
133137
case "make_closure":
134138
return;
@@ -137,45 +141,45 @@ function visitExpr(expr: HIRExpr, info: Map<string, GlobalState>): void {
137141
}
138142
}
139143

140-
function visitStmt(stmt: HIRStmt, info: Map<string, GlobalState>): void {
144+
function visitStmt(stmt: HIRStmt, info: Map<string, GlobalState>, candidates: Set<string>): void {
141145
switch (stmt.kind) {
142146
case "let":
143-
if (stmt.init) visitExpr(stmt.init, info);
147+
if (stmt.init) visitExpr(stmt.init, info, candidates);
144148
return;
145149
case "expr":
146-
visitExpr(stmt.expr, info);
150+
visitExpr(stmt.expr, info, candidates);
147151
return;
148152
case "return":
149-
if (stmt.value) visitExpr(stmt.value, info);
153+
if (stmt.value) visitExpr(stmt.value, info, candidates);
150154
return;
151155
case "if":
152-
visitExpr(stmt.condition, info);
153-
stmt.then.forEach((s) => visitStmt(s, info));
154-
stmt.else?.forEach((s) => visitStmt(s, info));
156+
visitExpr(stmt.condition, info, candidates);
157+
stmt.then.forEach((s) => visitStmt(s, info, candidates));
158+
stmt.else?.forEach((s) => visitStmt(s, info, candidates));
155159
return;
156160
case "while":
157-
visitExpr(stmt.condition, info);
158-
stmt.body.forEach((s) => visitStmt(s, info));
161+
visitExpr(stmt.condition, info, candidates);
162+
stmt.body.forEach((s) => visitStmt(s, info, candidates));
159163
return;
160164
case "for":
161-
if (stmt.init) visitStmt(stmt.init, info);
162-
if (stmt.condition) visitExpr(stmt.condition, info);
163-
if (stmt.update) visitExpr(stmt.update, info);
164-
stmt.body.forEach((s) => visitStmt(s, info));
165+
if (stmt.init) visitStmt(stmt.init, info, candidates);
166+
if (stmt.condition) visitExpr(stmt.condition, info, candidates);
167+
if (stmt.update) visitExpr(stmt.update, info, candidates);
168+
stmt.body.forEach((s) => visitStmt(s, info, candidates));
165169
return;
166170
case "throw":
167-
visitExpr(stmt.value, info);
171+
visitExpr(stmt.value, info, candidates);
168172
return;
169173
case "try":
170-
stmt.body.forEach((s) => visitStmt(s, info));
171-
stmt.catch?.body.forEach((s) => visitStmt(s, info));
172-
stmt.finally?.forEach((s) => visitStmt(s, info));
174+
stmt.body.forEach((s) => visitStmt(s, info, candidates));
175+
stmt.catch?.body.forEach((s) => visitStmt(s, info, candidates));
176+
stmt.finally?.forEach((s) => visitStmt(s, info, candidates));
173177
return;
174178
case "switch":
175-
visitExpr(stmt.discriminant, info);
179+
visitExpr(stmt.discriminant, info, candidates);
176180
for (const c of stmt.cases) {
177-
if (c.test) visitExpr(c.test, info);
178-
c.body.forEach((s) => visitStmt(s, info));
181+
if (c.test) visitExpr(c.test, info, candidates);
182+
c.body.forEach((s) => visitStmt(s, info, candidates));
179183
}
180184
return;
181185
default:
@@ -392,8 +396,8 @@ function rewriteStmt(stmt: HIRStmt, eligible: Set<string>): HIRStmt {
392396
}
393397
}
394398

395-
function visitFn(fn: HIRFunction, info: Map<string, GlobalState>): void {
396-
for (const s of fn.body) visitStmt(s, info);
399+
function visitFn(fn: HIRFunction, info: Map<string, GlobalState>, candidates: Set<string>): void {
400+
for (const s of fn.body) visitStmt(s, info, candidates);
397401
}
398402

399403
function rewriteFn(fn: HIRFunction, eligible: Set<string>): void {
@@ -408,9 +412,10 @@ export function narrowGlobalsPass(mod: HIRModule): void {
408412
}
409413
if (info.size === 0) return;
410414

411-
for (const s of mod.init) visitStmt(s, info);
412-
for (const fn of mod.functions) visitFn(fn, info);
413-
for (const cls of mod.classes) for (const m of cls.methods) visitFn(m, info);
415+
const candidates = new Set(info.keys());
416+
for (const s of mod.init) visitStmt(s, info, candidates);
417+
for (const fn of mod.functions) visitFn(fn, info, candidates);
418+
for (const cls of mod.classes) for (const m of cls.methods) visitFn(m, info, candidates);
414419

415420
const eligible = new Set<string>();
416421
for (const gi of info.values()) {

0 commit comments

Comments
 (0)