fix(0124): large stack arrays lower to in-place access, not first-class values
Two lowering sites materialized a local array as a whole LLVM value;
the legalizer scalarizes each such op into one SelectionDAG node per
element, and at ~64K elements the DAG combiner segfaults
(DAGCombiner::visitMERGE_VALUES → ReplaceAllUsesWith).
- lowerVarDecl: an array-typed `---` initializer emits NO store — the
slot stays uninitialized instead of receiving a whole-array undef
store. The tuple zero-init carve-out stays; non-array `---` keeps
the undef store. The interp is unchanged either way (slots start
.undef).
- lowerIndexExpr: element reads on an array with addressable storage
GEP the storage and load one element — the general-expression
sibling of 0110's lowerFor fix — without value-lowering the object
(a dead whole-array load would still reach the DAG). Storage-less
arrays keep the index_get fallback.
Sibling shape filed as 0125: any_to_string's per-array-type arms still
pass the array by value, so a 64K+ array type + any {} print crashes.
Regression: examples/0055-basic-large-stack-array.sx (sx build
segfaulted pre-fix). 22 .ir snapshots re-pinned: removed undef stores
and ig.tmp spills, in-place gep+load (instruction-shape-only churn,
reviewed).
This commit is contained in:
@@ -1275,10 +1275,25 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
|
||||
}
|
||||
}
|
||||
}
|
||||
const obj = self.lowerExpr(ie.object);
|
||||
const idx = self.lowerExpr(ie.index);
|
||||
// Infer element type from the object's slice/array type
|
||||
const obj_ty = self.inferExprType(ie.object);
|
||||
// Array with addressable storage: GEP the element in place + load,
|
||||
// never `index_get` on the loaded array VALUE — that realizes as
|
||||
// copy-whole-array-to-temp per read (the general-expression sibling
|
||||
// of 0110's `lowerFor` fix), and on a 64K+ array the whole-aggregate
|
||||
// load/store ops segfault LLVM's SelectionDAG (issue 0124). The
|
||||
// object must not be lowered as a value on this path or the dead
|
||||
// whole-array load still reaches the DAG.
|
||||
if (!obj_ty.isBuiltin() and self.module.types.get(obj_ty) == .array) {
|
||||
if (self.getExprAlloca(ie.object)) |storage| {
|
||||
const idx = self.lowerExpr(ie.index);
|
||||
const elem_ty = self.getElementType(obj_ty);
|
||||
const gep = self.builder.emit(.{ .index_gep = .{ .lhs = storage, .rhs = idx } }, self.module.types.ptrTo(elem_ty));
|
||||
return self.builder.load(gep, elem_ty);
|
||||
}
|
||||
}
|
||||
const obj = self.lowerExpr(ie.object);
|
||||
const idx = self.lowerExpr(ie.index);
|
||||
// `*[N]T` receiver auto-derefs (issue 0117): `obj` IS the pointer
|
||||
// value — GEP the pointee array and load the element.
|
||||
if (self.ptrToArrayElem(obj_ty)) |elem| {
|
||||
|
||||
@@ -260,9 +260,9 @@ pub fn lowerVarDecl(self: *Lowering, vd: *const ast.VarDecl) void {
|
||||
const ty = self.resolveType(ta);
|
||||
const slot = self.builder.alloca(ty);
|
||||
if (vd.value) |val| {
|
||||
// = --- (undef_literal) on tuple types: zero-initialize
|
||||
if (val.data == .undef_literal and !ty.isBuiltin()) {
|
||||
const ti = self.module.types.get(ty);
|
||||
// = --- (undef_literal) on tuple types: zero-initialize
|
||||
if (ti == .tuple) {
|
||||
var field_vals = std.ArrayList(Ref).empty;
|
||||
defer field_vals.deinit(self.alloc);
|
||||
@@ -278,6 +278,16 @@ pub fn lowerVarDecl(self: *Lowering, vd: *const ast.VarDecl) void {
|
||||
}
|
||||
return;
|
||||
}
|
||||
// `---` on an array: explicitly uninitialized — no store.
|
||||
// A whole-array undef store is a store of nothing that
|
||||
// LLVM's legalizer scalarizes into one DAG node per
|
||||
// element (issue 0124: SelectionDAG segfault at ~64K).
|
||||
if (ti == .array) {
|
||||
if (self.scope) |scope| {
|
||||
scope.put(vd.name, .{ .ref = slot, .ty = ty, .is_alloca = true });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// A compile-time float initializer narrowing into an integer
|
||||
// local follows the unified rule (integral folds, non-integral
|
||||
|
||||
Reference in New Issue
Block a user