Skip to content

Commit 7f7961e

Browse files
committed
Validate operand type widths in emission to reject cross-width unification
The egraph uses IntExpr/FloatExpr sorts that don't distinguish SPIR-V type widths, so i32 and i64 values can share e-classes. When extraction picks a mismatched-width operand, the emitted instruction would violate SPIR-V type rules (e.g. ShiftRightLogical with i32 base but i64 result). Bail out of emission when operand width differs from result width for same-class operations, causing the extraction loop to keep the original instruction.
1 parent 26e35d6 commit 7f7961e

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

  • rust/spirv-tools-opt/src/direct

rust/spirv-tools-opt/src/direct/emit.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,24 @@ fn emit_pattern(
12671267
synth.append(&mut s);
12681268
operand_ids.push(rspirv::dr::Operand::IdRef(arg_id));
12691269
}
1270+
// Validate operand type widths match the result type.
1271+
// The egraph may unify values of different SPIR-V widths (e.g. i32
1272+
// and i64 are both IntExpr). When extraction picks a mismatched-width
1273+
// operand, the emitted instruction would be invalid. Bail out so the
1274+
// extraction loop keeps the original instruction.
1275+
let result_width = ctx.type_widths.get(&op_result_type);
1276+
if result_width.is_some() && result_class == operand_class {
1277+
for op_id in &operand_ids {
1278+
if let rspirv::dr::Operand::IdRef(id) = op_id {
1279+
if let Some(arg_type) = ctx.id_to_type.get(id) {
1280+
let arg_width = ctx.type_widths.get(arg_type);
1281+
if arg_width.is_some() && arg_width != result_width {
1282+
return None;
1283+
}
1284+
}
1285+
}
1286+
}
1287+
}
12701288
let id = alloc_id(ctx);
12711289
synth.push(Instruction::new(
12721290
opcode,

0 commit comments

Comments
 (0)