Skip to content

Commit 6cb4b22

Browse files
authored
Merge pull request #3158 from veryl-lang/fix/aot-c-zero-length-wide-scratch
fix(simulator): avoid zero-length wide scratch arrays in AOT-C emit
2 parents 1dc2f94 + e54712d commit 6cb4b22

1 file changed

Lines changed: 27 additions & 19 deletions

File tree

  • crates/simulator/src/backend/aot_c

crates/simulator/src/backend/aot_c/emit.rs

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,14 @@ fn wideops_table() -> WideOpsTable {
257257
thread_local! {
258258
static WIDE_TMP_CTR: Cell<usize> = const { Cell::new(0) };
259259
}
260+
/// 64-bit word count for a `native_bytes` size class — the length of the
261+
/// `uint64_t _wN[]` scratch that holds a value of that size. Must round UP:
262+
/// `native_bytes` returns 4 for widths <= 32, and a truncating `/ 8` would
263+
/// declare a zero-length array whose word-0 store is out of bounds.
264+
fn wide_words(nb: usize) -> usize {
265+
nb.div_ceil(8)
266+
}
267+
260268
/// Fresh `_wN` index, unique within a function emit (monotonic; reset by
261269
/// `emit_function` / `emit_event_function` so emitted source is deterministic).
262270
fn next_wide_tmp() -> usize {
@@ -761,7 +769,7 @@ fn emit_wide_const(
761769
let (width, digits): (usize, Vec<u64>) = match value {
762770
Value::U64(x) if x.width == 0 => {
763771
let target = ctx_width.max(proto_width);
764-
let count = native_bytes(target) / 8;
772+
let count = wide_words(native_bytes(target));
765773
let d = if x.payload != 0 {
766774
vec![u64::MAX; count]
767775
} else {
@@ -773,7 +781,7 @@ fn emit_wide_const(
773781
Value::BigUint(x) => (proto_width, x.payload.to_u64_digits()),
774782
};
775783
let nb = native_bytes(width);
776-
let nw = nb / 8;
784+
let nw = wide_words(nb);
777785
let t = next_wide_tmp();
778786
let mut init = String::new();
779787
for i in 0..nw {
@@ -833,7 +841,7 @@ fn emit_wide_expr(expr: &ProtoExpression, pre: &mut String) -> Option<WideRef> {
833841
let idx = emit_expr(&dyn_sel.index_expr)?;
834842
let max_idx = dyn_sel.num_elements - 1;
835843
let src_nb = native_bytes(*var_full_width);
836-
let src_nw = src_nb / 8;
844+
let src_nw = wide_words(src_nb);
837845
let t = next_wide_tmp();
838846
pre.push_str(&format!(
839847
"uint64_t _w{t}[{src_nw}]; \
@@ -861,7 +869,7 @@ fn emit_wide_expr(expr: &ProtoExpression, pre: &mut String) -> Option<WideRef> {
861869
return None;
862870
}
863871
let src_nb = native_bytes(*var_full_width);
864-
let src_nw = src_nb / 8;
872+
let src_nw = wide_words(src_nb);
865873
let res_nb = native_bytes(nbits);
866874
let t = next_wide_tmp();
867875
pre.push_str(&format!(
@@ -964,7 +972,7 @@ fn emit_wide_operand(
964972
target_nb: usize,
965973
pre: &mut String,
966974
) -> Option<WideRef> {
967-
let tnw = target_nb / 8;
975+
let tnw = wide_words(target_nb);
968976
// A wide-pointer NODE whose wide emit has no arm may still be scalar-
969977
// emittable when its RESULT is ≤128 bits (e.g. a dynamic select on a
970978
// >128-bit var, which reads a 64..128-bit element into a register):
@@ -1053,7 +1061,7 @@ fn emit_wide_rhs_field(
10531061
return None;
10541062
}
10551063
let src_nb = native_bytes(src_w);
1056-
let src_nw = src_nb / 8;
1064+
let src_nw = wide_words(src_nb);
10571065
let r = emit_wide_operand(expr, src_nb, pre)?;
10581066
let fld = next_wide_tmp();
10591067
pre.push_str(&format!(
@@ -1122,7 +1130,7 @@ fn emit_wide_operand_signed(
11221130
let w = expr.width();
11231131
if signed && w > 0 && w < target_nb * 8 {
11241132
let t = next_wide_tmp();
1125-
let tnw = target_nb / 8;
1133+
let tnw = wide_words(target_nb);
11261134
pre.push_str(&format!(
11271135
"uint64_t _w{t}[{tnw}]; vw_sext_copy((uint8_t*)_w{t}, {src}, {w}u, {target_nb}u); ",
11281136
src = r.addr,
@@ -1229,7 +1237,7 @@ fn emit_wide_binary(
12291237
let width = expr_context.width;
12301238
let result_nb = native_bytes(width);
12311239
let op_nb = native_bytes(width.max(x.width()).max(y.width()));
1232-
let nw = op_nb / 8;
1240+
let nw = wide_words(op_nb);
12331241
let mask_pack = wpack(op_nb, width);
12341242
match op {
12351243
Op::BitAnd | Op::BitOr | Op::BitXor | Op::BitXnor | Op::Add | Op::Sub | Op::Mul => {
@@ -1307,7 +1315,7 @@ fn emit_wide_binary(
13071315
/// mask after the op; identity is unmasked.
13081316
fn emit_wide_unary(op: Op, x: &ProtoExpression, width: usize, pre: &mut String) -> Option<WideRef> {
13091317
let nb = native_bytes(width);
1310-
let nw = nb / 8;
1318+
let nw = wide_words(nb);
13111319
let x_ref = emit_wide_operand(x, nb, pre)?;
13121320
match op {
13131321
Op::Add => Some(WideRef {
@@ -1373,7 +1381,7 @@ fn emit_wide_ternary(
13731381
pre: &mut String,
13741382
) -> Option<WideRef> {
13751383
let nb = native_bytes(width);
1376-
let nw = nb / 8;
1384+
let nw = wide_words(nb);
13771385
let c = emit_expr(cond)?;
13781386
let mut t_ref = emit_wide_operand(true_expr, nb, pre)?;
13791387
let mut f_ref = emit_wide_operand(false_expr, nb, pre)?;
@@ -1435,7 +1443,7 @@ fn emit_wide_concat(
14351443
pre: &mut String,
14361444
) -> Option<WideRef> {
14371445
let nb = native_bytes(width);
1438-
let nw = nb / 8;
1446+
let nw = wide_words(nb);
14391447
let acc = next_wide_tmp();
14401448
pre.push_str(&format!("uint64_t _w{acc}[{nw}] = {{0}}; "));
14411449

@@ -2283,7 +2291,7 @@ fn emit_event_ff_assign_wide(a: &ProtoAssignStatement) -> Option<String> {
22832291
}
22842292
let packed = dst_raw == cur_off;
22852293
let nb = native_bytes(a.dst_width);
2286-
let nw = nb / 8;
2294+
let nw = wide_words(nb);
22872295
let mut pre = String::new();
22882296
// Build the RHS to `nb` bytes, then copy into a fresh scratch and mask it
22892297
// there (the canonical FF slot must not be clobbered before commit; the
@@ -2549,7 +2557,7 @@ fn emit_event_ff_assign_dynamic_wide(a: &ProtoAssignDynamicStatement) -> Option<
25492557
return None;
25502558
}
25512559
let nb = native_bytes(a.dst_width);
2552-
let nw = nb / 8;
2560+
let nw = wide_words(nb);
25532561
let max_idx = a.dst_num_elements.saturating_sub(1);
25542562
let idx = emit_expr(&a.dst_index_expr)?;
25552563
let mut pre = String::new();
@@ -3560,7 +3568,7 @@ pub fn emit_stmt(stmt: &ProtoStatement) -> Option<String> {
35603568
return None;
35613569
}
35623570
let nb = native_bytes(a.dst_width);
3563-
let nw = nb / 8;
3571+
let nw = wide_words(nb);
35643572
if win > nb * 8 {
35653573
return None;
35663574
}
@@ -3629,7 +3637,7 @@ pub fn emit_stmt(stmt: &ProtoStatement) -> Option<String> {
36293637
return None;
36303638
}
36313639
let nb = native_bytes(a.dst_width);
3632-
let nw = nb / 8;
3640+
let nw = wide_words(nb);
36333641
let dst = format!("(uint8_t*)(comb_values + {store_off:#x})");
36343642
let dmask = wpack(nb, a.dst_width);
36353643
// Non-foldable rhs_select (rhs isn't a plain variable):
@@ -4075,7 +4083,7 @@ pub fn emit_stmt(stmt: &ProtoStatement) -> Option<String> {
40754083
return None;
40764084
}
40774085
let nb = native_bytes(a.dst_width);
4078-
let nw = nb / 8;
4086+
let nw = wide_words(nb);
40794087
let max_idx = a.dst_num_elements.saturating_sub(1);
40804088
let idx_str = emit_expr(&a.dst_index_expr)?;
40814089
let dmask = wpack(nb, a.dst_width);
@@ -4495,7 +4503,7 @@ fn emit_expr_inner(expr: &ProtoExpression, needs_clean: bool) -> Option<String>
44954503
if off < 0 {
44964504
return None;
44974505
}
4498-
let nw = native_bytes(*var_full_width) / 8;
4506+
let nw = wide_words(native_bytes(*var_full_width));
44994507
let m: u128 = if dyn_sel.window >= 128 {
45004508
!0u128
45014509
} else {
@@ -4534,7 +4542,7 @@ fn emit_expr_inner(expr: &ProtoExpression, needs_clean: bool) -> Option<String>
45344542
if off < 0 {
45354543
return None;
45364544
}
4537-
let nw = native_bytes(*var_full_width) / 8;
4545+
let nw = wide_words(native_bytes(*var_full_width));
45384546
return Some(format!(
45394547
"({{ uint64_t _idx_raw = (uint64_t)({idx}); \
45404548
uint64_t _idx = _idx_raw < {max} ? _idx_raw : {max}; \
@@ -5281,7 +5289,7 @@ fn emit_expr_inner(expr: &ProtoExpression, needs_clean: bool) -> Option<String>
52815289
return None;
52825290
}
52835291
let src_nb = native_bytes(x_w);
5284-
let src_nw = src_nb / 8;
5292+
let src_nw = wide_words(src_nb);
52855293
let mut pre = String::new();
52865294
let xr = emit_wide_operand(x, src_nb, &mut pre)?;
52875295
let count = emit_expr(y)?;

0 commit comments

Comments
 (0)