Skip to content

Commit ad84a1b

Browse files
committed
Fix AOT-C unary result left unmasked in a 65..128-bit context
1 parent cce1bf1 commit ad84a1b

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,6 +3557,15 @@ fn emit_expr_inner(expr: &ProtoExpression, needs_clean: bool) -> Option<String>
35573557
if needs_clean && expr_context.width > 0 && expr_context.width < 64 {
35583558
let mask = (1u64 << expr_context.width) - 1;
35593559
Some(format!("(({}) & 0x{:x}ULL)", inner, mask))
3560+
} else if needs_clean && expr_context.width > 64 && expr_context.width < 128 {
3561+
// 65..128-bit context over a ≤64-bit operand: the
3562+
// int64 result sign-extends through the __uint128_t
3563+
// promotion (supplying the ones in [xw..width) for
3564+
// ~/-), then the mask trims [width..128).
3565+
Some(mask_u128(
3566+
&format!("((__uint128_t)(__int128_t)({inner}))"),
3567+
expr_context.width,
3568+
))
35603569
} else {
35613570
Some(inner)
35623571
}

crates/simulator/src/tests/simulation.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19039,3 +19039,42 @@ fn reduction_xnor_is_even_parity() {
1903919039
}
1904019040
}
1904119041
}
19042+
19043+
#[test]
19044+
fn aot_c_unary_masked_in_wide_context() {
19045+
// A unary ~/- over a ≤64-bit operand evaluated in a 65..128-bit context
19046+
// was emitted as a dirty int64 by the AOT-C backend: promoted to
19047+
// __uint128_t it sign-extends past the context width, so comparisons
19048+
// reading the high bits miscompiled (eq/en = 0 instead of 1).
19049+
let code = r#"
19050+
module Top (
19051+
a : input logic<32>,
19052+
eq: output logic,
19053+
en: output logic,
19054+
) {
19055+
var b: logic<100>;
19056+
var c: logic<100>;
19057+
assign b = ~{68'd0, a};
19058+
assign c = 100'd0 - {68'd0, a};
19059+
assign eq = b == ~a;
19060+
assign en = c == -a;
19061+
}
19062+
"#;
19063+
19064+
for config in Config::all() {
19065+
let ir = analyze(code, &config);
19066+
let mut sim = Simulator::new(ir, None);
19067+
sim.set("a", Value::new(5, 32, false));
19068+
sim.step(&Event::Clock(VarId::SYNTHETIC));
19069+
assert_eq!(
19070+
sim.get("eq").unwrap(),
19071+
Value::new(1, 1, false),
19072+
"eq config={config:?}"
19073+
);
19074+
assert_eq!(
19075+
sim.get("en").unwrap(),
19076+
Value::new(1, 1, false),
19077+
"en config={config:?}"
19078+
);
19079+
}
19080+
}

0 commit comments

Comments
 (0)