Skip to content

Commit 5d65277

Browse files
committed
Fix nested array slice lowering
Track runtime representation separately from solved expression types so fixed array rows are wrapped correctly when passed or stored as slices. This fixes nested array row slicing and arrays of slice fat pointers. Fixes #16
1 parent 2516f57 commit 5d65277

7 files changed

Lines changed: 269 additions & 14 deletions

File tree

src/jit.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::defs::*;
77
use crate::expr::*;
88
use crate::DeclTable;
99
use crate::Instance;
10+
use crate::TypeID;
1011
extern crate cranelift_codegen;
1112
use core::panic;
1213
use cranelift::codegen::{self, settings};
@@ -382,15 +383,20 @@ impl JIT {
382383
.load(I64, MemFlags::new(), closure_ptr_val, (i * 8) as i32);
383384
let var = trans.declare_variable(&cv.name.to_string(), I64);
384385
trans.builder.def_var(var, var_ptr);
386+
trans.variable_types.insert(cv.name.to_string(), cv.ty);
385387
// NOT added to let_bindings → acts as a var binding (accessed through the pointer).
386388
}
387389
}
388390

389391
// Add variables for the function parameters and define them with block param values.
390392
for (i, param) in decl.params.iter().enumerate() {
391-
let ty = param.ty.expect("expected type").cranelift_type();
393+
let param_ty = param.ty.expect("expected type");
394+
let ty = param_ty.cranelift_type();
392395
let var = trans.declare_variable(&param.name, ty);
393396
trans.builder.def_var(var, block_params[i + param_idx]);
397+
trans
398+
.variable_types
399+
.insert(param.name.to_string(), param_ty);
394400
// Function parameters are like let bindings - they hold values directly.
395401
trans.let_bindings.insert(param.name.to_string());
396402
}
@@ -510,6 +516,7 @@ fn fn_sig(module: &JITModule, from: crate::TypeID, to: crate::TypeID) -> Signatu
510516
struct FunctionTranslator<'a> {
511517
builder: FunctionBuilder<'a>,
512518
variables: HashMap<String, Variable>,
519+
variable_types: HashMap<String, TypeID>,
513520
module: &'a mut JITModule,
514521

515522
/// Next variable index.
@@ -559,6 +566,7 @@ impl<'a> FunctionTranslator<'a> {
559566
Self {
560567
builder,
561568
variables: HashMap::new(),
569+
variable_types: HashMap::new(),
562570
module,
563571
next_index: 0,
564572
current_instance: Instance::new(),
@@ -968,7 +976,7 @@ impl<'a> FunctionTranslator<'a> {
968976
let arg_val = self.translate_expr(*arg_id, decl, decls);
969977
let param_ty = callee_decl.params[i].ty.unwrap();
970978
if matches!(&*param_ty, crate::Type::Slice(_)) {
971-
let actual_ty = decl.types[*arg_id];
979+
let actual_ty = self.representation_type(*arg_id, decl, decls);
972980
match &*actual_ty {
973981
crate::Type::Slice(_) => {
974982
// Already a fat pointer: load data_ptr and len.
@@ -1054,7 +1062,7 @@ impl<'a> FunctionTranslator<'a> {
10541062
if is_slice(param_types[i]) {
10551063
args.push(self.wrap_as_slice(
10561064
arg_val,
1057-
decl.types[*arg_id],
1065+
self.representation_type(*arg_id, decl, decls),
10581066
decls,
10591067
));
10601068
continue;
@@ -1086,8 +1094,10 @@ impl<'a> FunctionTranslator<'a> {
10861094
Expr::Let(name, init, _) => {
10871095
let ty = &decl.types[expr];
10881096
let init_val = self.translate_expr(*init, decl, decls);
1097+
let init_val = self.wrap_for_expected_slice(init_val, *ty, *init, decl, decls);
10891098
let var = self.declare_variable(name, ty.cranelift_type());
10901099
self.builder.def_var(var, init_val);
1100+
self.variable_types.insert(name.to_string(), *ty);
10911101
self.let_bindings.insert(name.to_string());
10921102
init_val
10931103
}
@@ -1108,11 +1118,13 @@ impl<'a> FunctionTranslator<'a> {
11081118
self.builder.ins().splat(F32X4, zero)
11091119
};
11101120
self.builder.def_var(var, init_val);
1121+
self.variable_types.insert(name.to_string(), *ty);
11111122
self.let_bindings.insert(name.to_string());
11121123
return init_val;
11131124
}
11141125

11151126
let var = self.declare_variable(name, I64);
1127+
self.variable_types.insert(name.to_string(), *ty);
11161128

11171129
let sz = ty.size(decls) as u32;
11181130
if sz == 0 {
@@ -1136,6 +1148,8 @@ impl<'a> FunctionTranslator<'a> {
11361148

11371149
if let Some(init_id) = init {
11381150
let init_value = self.translate_expr(*init_id, decl, decls);
1151+
let init_value =
1152+
self.wrap_for_expected_slice(init_value, *ty, *init_id, decl, decls);
11391153
self.gen_copy(*ty, addr, init_value, decls);
11401154
} else {
11411155
self.gen_zero(*ty, addr, decls);
@@ -1393,6 +1407,7 @@ impl<'a> FunctionTranslator<'a> {
13931407
// Save variable scope — variables declared inside this block
13941408
// shadow outer names only for the duration of the block.
13951409
let saved_vars = self.variables.clone();
1410+
let saved_types = self.variable_types.clone();
13961411
let saved_lets = self.let_bindings.clone();
13971412
let mut result = None;
13981413
for expr in exprs {
@@ -1403,6 +1418,7 @@ impl<'a> FunctionTranslator<'a> {
14031418
}
14041419
}
14051420
self.variables = saved_vars;
1421+
self.variable_types = saved_types;
14061422
self.let_bindings = saved_lets;
14071423
result.unwrap()
14081424
}
@@ -1492,6 +1508,8 @@ impl<'a> FunctionTranslator<'a> {
14921508
// Create a variable for the loop counter.
14931509
let loop_var = self.declare_variable(var, I32);
14941510
self.builder.def_var(loop_var, start_val);
1511+
self.variable_types
1512+
.insert(var.to_string(), crate::types::mk_type(crate::Type::Int32));
14951513
self.let_bindings.insert(var.to_string());
14961514

14971515
// Create blocks for header, body, latch, and exit.
@@ -2147,7 +2165,7 @@ impl<'a> FunctionTranslator<'a> {
21472165
}
21482166
}
21492167
Binop::Assign => {
2150-
let t = decl.types[lhs_id];
2168+
let t = self.representation_type(lhs_id, decl, decls);
21512169
// f32x4 field assignment: v.x = val → insertlane
21522170
if let Expr::Field(vec_id, field_name) = &decl.arena[lhs_id] {
21532171
let vec_ty = decl.types[*vec_id];
@@ -2182,6 +2200,7 @@ impl<'a> FunctionTranslator<'a> {
21822200
}
21832201
let lhs = self.translate_lvalue(lhs_id, decl, decls);
21842202
let rhs = self.translate_expr(rhs_id, decl, decls);
2203+
let rhs = self.wrap_for_expected_slice(rhs, t, rhs_id, decl, decls);
21852204
self.gen_copy(t, lhs, rhs, decls);
21862205
rhs
21872206
}
@@ -2459,6 +2478,51 @@ impl<'a> FunctionTranslator<'a> {
24592478
}
24602479
}
24612480

2481+
fn representation_type(
2482+
&self,
2483+
expr: ExprID,
2484+
decl: &FuncDecl,
2485+
decls: &crate::DeclTable,
2486+
) -> crate::TypeID {
2487+
match &decl.arena.exprs[expr] {
2488+
Expr::Id(name) => self
2489+
.variable_types
2490+
.get(name.as_str())
2491+
.copied()
2492+
.or_else(|| {
2493+
decls.find(*name).iter().find_map(|decl| {
2494+
if let crate::Decl::Global { ty, .. } = decl {
2495+
Some(*ty)
2496+
} else {
2497+
None
2498+
}
2499+
})
2500+
})
2501+
.unwrap_or(decl.types[expr]),
2502+
Expr::ArrayIndex(arr_id, _) => match &*self.representation_type(*arr_id, decl, decls) {
2503+
crate::Type::Array(elem, _) | crate::Type::Slice(elem) => *elem,
2504+
_ => decl.types[expr],
2505+
},
2506+
_ => decl.types[expr],
2507+
}
2508+
}
2509+
2510+
fn wrap_for_expected_slice(
2511+
&mut self,
2512+
val: Value,
2513+
expected_ty: crate::TypeID,
2514+
actual_expr: ExprID,
2515+
decl: &FuncDecl,
2516+
decls: &crate::DeclTable,
2517+
) -> Value {
2518+
if matches!(&*expected_ty, crate::Type::Slice(_)) {
2519+
let actual_ty = self.representation_type(actual_expr, decl, decls);
2520+
self.wrap_as_slice(val, actual_ty, decls)
2521+
} else {
2522+
val
2523+
}
2524+
}
2525+
24622526
fn declare_variable(&mut self, name: &String, ty: Type) -> Variable {
24632527
// Always create a fresh Cranelift variable — even if a variable with
24642528
// the same name exists, this declaration shadows it.

src/llvm_jit.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::decl::*;
55
use crate::defs::*;
66
use crate::expr::*;
77
use crate::DeclTable;
8+
use crate::TypeID;
89

910
use std::convert::TryFrom;
1011

@@ -822,6 +823,7 @@ impl<'ctx> LLVMJITState<'ctx> {
822823

823824
// Set up local variable map: name → alloca pointer.
824825
let mut variables: HashMap<String, PointerValue<'ctx>> = HashMap::new();
826+
let mut variable_types: HashMap<String, TypeID> = HashMap::new();
825827
let mut let_bindings: HashSet<String> = HashSet::new();
826828

827829
// Load closure variables (captured variables).
@@ -850,6 +852,7 @@ impl<'ctx> LLVMJITState<'ctx> {
850852
.unwrap();
851853
self.builder.build_store(alloca, var_ptr).unwrap();
852854
variables.insert(cv.name.to_string(), alloca);
855+
variable_types.insert(cv.name.to_string(), cv.ty);
853856
// closure vars are treated like var bindings (pointer-indirected)
854857
}
855858

@@ -878,13 +881,15 @@ impl<'ctx> LLVMJITState<'ctx> {
878881
.unwrap();
879882
self.builder.build_store(alloca, param_val).unwrap();
880883
variables.insert(param.name.to_string(), alloca);
884+
variable_types.insert(param.name.to_string(), ty);
881885
let_bindings.insert(param.name.to_string());
882886
}
883887

884888
let mut trans = FunctionTranslator {
885889
state: self,
886890
function,
887891
variables,
892+
variable_types,
888893
let_bindings,
889894
globals_base,
890895
output_ptr,
@@ -965,6 +970,7 @@ struct FunctionTranslator<'a, 'ctx> {
965970
/// name → alloca. For let-bindings the alloca holds the value directly.
966971
/// For var-bindings the alloca holds a pointer to the actual stack slot.
967972
variables: HashMap<String, PointerValue<'ctx>>,
973+
variable_types: HashMap<String, TypeID>,
968974
let_bindings: HashSet<String>,
969975
globals_base: PointerValue<'ctx>,
970976
output_ptr: Option<PointerValue<'ctx>>,
@@ -1313,6 +1319,48 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
13131319
}
13141320
}
13151321

1322+
fn representation_type(&self, expr: ExprID, decl: &FuncDecl) -> crate::TypeID {
1323+
match &decl.arena.exprs[expr] {
1324+
Expr::Id(name) => self
1325+
.variable_types
1326+
.get(name.as_str())
1327+
.copied()
1328+
.or_else(|| {
1329+
self.decls.find(*name).iter().find_map(|decl| {
1330+
if let crate::Decl::Global { ty, .. } = decl {
1331+
Some(*ty)
1332+
} else {
1333+
None
1334+
}
1335+
})
1336+
})
1337+
.unwrap_or(decl.types[expr]),
1338+
Expr::ArrayIndex(arr_id, _) => match &*self.representation_type(*arr_id, decl) {
1339+
crate::Type::Array(elem, _) | crate::Type::Slice(elem) => *elem,
1340+
_ => decl.types[expr],
1341+
},
1342+
_ => decl.types[expr],
1343+
}
1344+
}
1345+
1346+
fn wrap_for_expected_slice(
1347+
&self,
1348+
val: BasicValueEnum<'ctx>,
1349+
expected_ty: crate::TypeID,
1350+
actual_expr: ExprID,
1351+
decl: &FuncDecl,
1352+
) -> BasicValueEnum<'ctx> {
1353+
if matches!(&*expected_ty, crate::Type::Slice(_)) {
1354+
self.wrap_as_slice(
1355+
val.into_pointer_value(),
1356+
self.representation_type(actual_expr, decl),
1357+
)
1358+
.into()
1359+
} else {
1360+
val
1361+
}
1362+
}
1363+
13161364
fn gen_zero_mem(&self, dst: PointerValue<'ctx>, size: usize) {
13171365
self.emit_memzero(dst, size);
13181366
}
@@ -1620,9 +1668,11 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
16201668
let (name, init_id) = (*name, *init_id);
16211669
let ty = decl.types[expr];
16221670
let init_val = self.translate_expr(init_id, decl);
1671+
let init_val = self.wrap_for_expected_slice(init_val, ty, init_id, decl);
16231672
let alloca = self.entry_alloca(ty.llvm_basic_type(self.ctx()), &*name);
16241673
self.builder().build_store(alloca, init_val).unwrap();
16251674
self.variables.insert(name.to_string(), alloca);
1675+
self.variable_types.insert(name.to_string(), ty);
16261676
self.let_bindings.insert(name.to_string());
16271677
init_val
16281678
}
@@ -1644,6 +1694,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
16441694
self.builder().build_store(alloca, zero).unwrap();
16451695
}
16461696
self.variables.insert(name.to_string(), alloca);
1697+
self.variable_types.insert(name.to_string(), ty);
16471698
self.let_bindings.insert(name.to_string());
16481699
} else {
16491700
// Pointer/struct var: allocate byte storage + ptr alloca.
@@ -1655,9 +1706,11 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
16551706
let alloca = self.entry_alloca(self.ptr_ty().into(), &*name);
16561707
self.builder().build_store(alloca, storage).unwrap();
16571708
self.variables.insert(name.to_string(), alloca);
1709+
self.variable_types.insert(name.to_string(), ty);
16581710

16591711
if let Some(init_id) = init_id {
16601712
let init_val = self.translate_expr(init_id, decl);
1713+
let init_val = self.wrap_for_expected_slice(init_val, ty, init_id, decl);
16611714
self.gen_copy(ty, storage, init_val);
16621715
} else {
16631716
self.gen_zero_mem(storage, sz);
@@ -1772,6 +1825,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
17721825
// Save variable scope — declarations inside this block
17731826
// shadow outer names only for the duration of the block.
17741827
let saved_vars = self.variables.clone();
1828+
let saved_types = self.variable_types.clone();
17751829
let saved_lets = self.let_bindings.clone();
17761830
let mut result = self.zero_i32();
17771831
for e in &exprs {
@@ -1781,6 +1835,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
17811835
result = self.translate_expr(*e, decl);
17821836
}
17831837
self.variables = saved_vars;
1838+
self.variable_types = saved_types;
17841839
self.let_bindings = saved_lets;
17851840
result
17861841
}
@@ -1927,6 +1982,8 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
19271982
self.builder().build_store(loop_alloca, start_val).unwrap();
19281983
// Treat as let binding (holds value directly).
19291984
self.variables.insert(var.to_string(), loop_alloca);
1985+
self.variable_types
1986+
.insert(var.to_string(), crate::types::mk_type(crate::Type::Int32));
19301987
self.let_bindings.insert(var.to_string());
19311988

19321989
let header_bb = self.append_bb("for_header");
@@ -2408,7 +2465,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
24082465
}
24092466
}
24102467
// f32x4 full assignment: v = expr → store vector to alloca
2411-
let t = decl.types[lhs_id];
2468+
let t = self.representation_type(lhs_id, decl);
24122469
if matches!(*t, crate::Type::Float32x4) {
24132470
if let Expr::Id(name) = &decl.arena.exprs[lhs_id] {
24142471
if let Some(&alloca) = self.variables.get(&**name) {
@@ -2420,6 +2477,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
24202477
}
24212478
let lhs_addr = self.translate_lvalue(lhs_id, decl);
24222479
let rhs_val = self.translate_expr(rhs_id, decl);
2480+
let rhs_val = self.wrap_for_expected_slice(rhs_val, t, rhs_id, decl);
24232481
self.gen_copy(t, lhs_addr, rhs_val);
24242482
rhs_val
24252483
}
@@ -2896,7 +2954,7 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
28962954
let arg_val = self.translate_expr(*arg_id, decl);
28972955
let param_ty = callee_decl.params[i].ty.unwrap();
28982956
if matches!(&*param_ty, crate::Type::Slice(_)) {
2899-
let actual_ty = decl.types[*arg_id];
2957+
let actual_ty = self.representation_type(*arg_id, decl);
29002958
match &*actual_ty {
29012959
crate::Type::Slice(_) => {
29022960
// Already a fat pointer: load data_ptr and len.
@@ -3025,8 +3083,10 @@ impl<'a, 'ctx> FunctionTranslator<'a, 'ctx> {
30253083
for (i, arg_id) in arg_ids.iter().enumerate() {
30263084
let arg_val = self.translate_expr(*arg_id, decl);
30273085
if i < param_types.len() && is_slice(param_types[i]) {
3028-
let wrapped =
3029-
self.wrap_as_slice(arg_val.into_pointer_value(), decl.types[*arg_id]);
3086+
let wrapped = self.wrap_as_slice(
3087+
arg_val.into_pointer_value(),
3088+
self.representation_type(*arg_id, decl),
3089+
);
30303090
args.push(wrapped.into());
30313091
} else {
30323092
let pi = arg_start + i;

0 commit comments

Comments
 (0)