Skip to content

Commit 71f7e34

Browse files
committed
support constant initializers for global struct/array variables
1 parent dd96578 commit 71f7e34

4 files changed

Lines changed: 158 additions & 9 deletions

File tree

src/codegen.ts

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6476,16 +6476,60 @@ export class Codegen {
64766476

64776477
private usedSatIntrinsics?: Set<string>;
64786478

6479+
private tryConstantExpr(expr: import("./hir").HIRExpr): string | null {
6480+
switch (expr.kind) {
6481+
case "IntLit": return expr.value.toString();
6482+
case "FloatLit": {
6483+
const buf = new ArrayBuffer(8);
6484+
new Float64Array(buf)[0] = expr.value;
6485+
const bits = new BigUint64Array(buf)[0];
6486+
return `0x${bits.toString(16).toUpperCase().padStart(16, "0")}`;
6487+
}
6488+
case "BoolLit": return expr.value ? "1" : "0";
6489+
case "Cast":
6490+
if (expr.type.tag === "ptr") return "null";
6491+
return null;
6492+
case "StructLit": {
6493+
const layout = this.structLayouts.get(expr.name);
6494+
if (!layout) return null;
6495+
const fieldVals: string[] = [];
6496+
for (const lf of layout.fields) {
6497+
const ef = expr.fields.find(f => f.name === lf.name);
6498+
if (!ef) return null;
6499+
const val = this.tryConstantExpr(ef.value);
6500+
if (val === null) return null;
6501+
fieldVals.push(`${lf.type} ${val}`);
6502+
}
6503+
return `{ ${fieldVals.join(", ")} }`;
6504+
}
6505+
case "ArrayLit": {
6506+
if (expr.type.tag !== "array" || expr.type.size === null) return null;
6507+
const elemTy = this.llvmType(expr.type.element);
6508+
const elemVals: string[] = [];
6509+
for (const elem of expr.elements) {
6510+
const val = this.tryConstantExpr(elem);
6511+
if (val === null) return null;
6512+
elemVals.push(`${elemTy} ${val}`);
6513+
}
6514+
return `[${elemVals.join(", ")}]`;
6515+
}
6516+
case "ArrayRepeat": {
6517+
const elemKind = expr.type.tag === "array" ? expr.type.element : { tag: "int" as const, bits: 32, signed: true };
6518+
const elemTy = this.llvmType(elemKind);
6519+
const val = this.tryConstantExpr(expr.value);
6520+
if (val === null) return null;
6521+
if (val === "0" || val === "zeroinitializer") return "zeroinitializer";
6522+
const elems = Array(expr.count).fill(`${elemTy} ${val}`);
6523+
return `[${elems.join(", ")}]`;
6524+
}
6525+
default:
6526+
return null;
6527+
}
6528+
}
6529+
64796530
private getConstantInitializer(g: import("./hir").HIRGlobal): string {
6480-
if (g.value.kind === "IntLit") return g.value.value.toString();
6481-
if (g.value.kind === "FloatLit") {
6482-
const buf = new ArrayBuffer(8);
6483-
new Float64Array(buf)[0] = g.value.value;
6484-
const bits = new BigUint64Array(buf)[0];
6485-
return `0x${bits.toString(16).toUpperCase().padStart(16, "0")}`;
6486-
}
6487-
if (g.value.kind === "BoolLit") return g.value.value ? "1" : "0";
6488-
if (g.value.kind === "Cast" && g.type.tag === "ptr") return "null";
6531+
const constVal = this.tryConstantExpr(g.value);
6532+
if (constVal !== null) return constVal;
64896533
if (g.type.tag === "ptr") return "null";
64906534
const tag = g.type.tag;
64916535
if (tag === "struct" || tag === "array" || tag === "enum" || tag === "string" || tag === "vec" || tag === "hashmap" || tag === "tuple") {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
var scores: [i32; 5] = [10, 20, 30, 40, 50]
2+
var flags: [bool; 3] = [true, false, true]
3+
let repeatedF64: [f64; 3] = [3.14; 3]
4+
5+
fn main(): i32 {
6+
print(scores[0])
7+
print(scores[2])
8+
print(scores[4])
9+
10+
scores[2] = 999
11+
print(scores[2])
12+
13+
print(flags[0])
14+
print(flags[1])
15+
print(flags[2])
16+
17+
print(repeatedF64[0])
18+
print(repeatedF64[2])
19+
20+
return 0
21+
}
22+
23+
// @expect: 10
24+
// @expect: 30
25+
// @expect: 50
26+
// @expect: 999
27+
// @expect: true
28+
// @expect: false
29+
// @expect: true
30+
// @expect: 3.14
31+
// @expect: 3.14
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
struct Timer {
2+
id: i32,
3+
active: bool,
4+
delayMs: i32,
5+
}
6+
7+
var timers: [Timer; 4] = [Timer { id: 0, active: false, delayMs: 0 }; 4]
8+
9+
fn main(): i32 {
10+
// verify zero-init values
11+
print(timers[0].id)
12+
print(timers[0].active)
13+
print(timers[0].delayMs)
14+
15+
// mutate one element
16+
timers[1].id = 42
17+
timers[1].active = true
18+
timers[1].delayMs = 1000
19+
20+
print(timers[1].id)
21+
print(timers[1].active)
22+
print(timers[1].delayMs)
23+
24+
// confirm others unchanged
25+
print(timers[2].id)
26+
print(timers[3].active)
27+
28+
return 0
29+
}
30+
31+
// @expect: 0
32+
// @expect: false
33+
// @expect: 0
34+
// @expect: 42
35+
// @expect: true
36+
// @expect: 1000
37+
// @expect: 0
38+
// @expect: false
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
struct Point {
2+
x: i32,
3+
y: i32,
4+
}
5+
6+
struct Config {
7+
width: i32,
8+
height: i32,
9+
scale: f64,
10+
enabled: bool,
11+
}
12+
13+
var origin: Point = Point { x: 10, y: 20 }
14+
let config: Config = Config { width: 1920, height: 1080, scale: 2.5, enabled: true }
15+
16+
fn main(): i32 {
17+
print(origin.x)
18+
print(origin.y)
19+
print(config.width)
20+
print(config.height)
21+
print(config.scale)
22+
print(config.enabled)
23+
24+
origin.x = 99
25+
print(origin.x)
26+
27+
return 0
28+
}
29+
30+
// @expect: 10
31+
// @expect: 20
32+
// @expect: 1920
33+
// @expect: 1080
34+
// @expect: 2.5
35+
// @expect: true
36+
// @expect: 99

0 commit comments

Comments
 (0)