Skip to content

Commit 7242a10

Browse files
committed
fix(ssa): apply @reference heap-layout rule for Type::Unresolved too
`convert_type` already wraps `@reference` user types in `Ptr(Struct(...))` when the typed AST hands us `Type::Named(id)`, but the parallel `Type::Unresolved(name)` arm — which fires for type references inside `impl` method bodies (`Vec3R { ... }` inside `impl Add<Vec3R> for Vec3R`) — returned a bare `Struct(...)`, missing the `is_reference` check. The constructor lowering then took the value-type path (chained `InsertValue` producing a struct SSA value rather than a malloc + per-field store + pointer return) and downstream field-access GEPs took a struct value as their `ptr` operand, panicking at `into_pointer_value()` (llvm_backend.rs:1363). The fix mirrors the `is_reference` check from the `Named` arm into the `Unresolved` arm. Bench impact: `bench_op_overload_ref` (1M iter × 2 calls = 2M heap-Vec3R `+` ops) now runs cleanly through the LLVM tier — was falling back to Cranelift silently because the BG-thread compile panicked. ~30 ms exec, returning `Int(21000000)`. CI gate: `bench_op_overload_ref` is now in the value-asserted KERNELS list so any future regression that re-introduces this shape gets caught loudly instead of falling back to Cranelift in the background.
1 parent 2cbfd84 commit 7242a10

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

crates/compiler/src/ssa.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7542,6 +7542,25 @@ impl SsaBuilder {
75427542
.map(|field| self.convert_type(&field.ty))
75437543
.collect();
75447544

7545+
// Same `@reference` heap-layout check the `Type::Named`
7546+
// arm above performs — Unresolved arrived here because
7547+
// an earlier resolution stage produced `Unresolved(name)`
7548+
// instead of `Named(id)`, which happens for type
7549+
// references inside `impl` method bodies (`Vec3R { ... }`
7550+
// inside `impl Add<Vec3R> for Vec3R`). Without this
7551+
// mirror, the constructor lowering builds a value-type
7552+
// struct via `insertvalue` chains, the field-access
7553+
// path then issues a GEP whose `ptr` operand is the
7554+
// struct value, and the LLVM backend panics at
7555+
// `into_pointer_value()` (llvm_backend.rs:1363).
7556+
if type_def.metadata.is_reference {
7557+
return HirType::Ptr(Box::new(HirType::Struct(HirStructType {
7558+
name: Some(type_def.name),
7559+
fields: hir_fields,
7560+
packed: false,
7561+
})));
7562+
}
7563+
75457564
HirType::Struct(HirStructType {
75467565
name: Some(type_def.name),
75477566
fields: hir_fields,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import prelude
2+
3+
@reference
4+
struct Vec3R {
5+
x: f64, y: f64, z: f64
6+
}
7+
8+
impl Add<Vec3R> for Vec3R {
9+
def add(self, other: Vec3R): Vec3R {
10+
return Vec3R { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
11+
}
12+
}
13+
14+
def main(): i64 {
15+
let mut acc = Vec3R { x: 0.0, y: 0.0, z: 0.0 }
16+
let a = Vec3R { x: 1.0, y: 2.0, z: 3.0 }
17+
let b = Vec3R { x: 4.0, y: 5.0, z: 6.0 }
18+
let mut i: i64 = 0
19+
while i < 1000000 {
20+
acc = acc + a
21+
acc = acc + b
22+
i = i + 1
23+
}
24+
return (acc.x + acc.y + acc.z) as i64
25+
}

crates/zynml/examples/bench_runner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ const KERNELS: &[(&str, &str)] = &[
195195
// a=(1,2,3), b=(4,5,6) → acc = (50000000, 70000000, 90000000)
196196
// → sum 210000000.
197197
("bench_op_overload", "Int(210000000)"),
198+
("bench_op_overload_ref", "Int(21000000)"),
198199
];
199200

200201
/// Each target produces one [`TargetResult`] per kernel.

0 commit comments

Comments
 (0)