Skip to content

Commit 6b0dda4

Browse files
authored
ZJIT: Add temporary local definite assignment validator (ruby#15973)
Until we get our global register allocator, we need our HIR to be in 100% block-local SSA. Add a validator to enforce that.
1 parent b710293 commit 6b0dda4

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

zjit/src/hir.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5125,6 +5125,34 @@ impl Function {
51255125
Ok(())
51265126
}
51275127

5128+
// Validate that every instruction use is from a block-local definition, which is a temporary
5129+
// constraint until we get a global register allocator.
5130+
// TODO(tenderworks): Remove this
5131+
fn temporary_validate_block_local_definite_assignment(&self) -> Result<(), ValidationError> {
5132+
for block in self.rpo() {
5133+
let mut assigned = InsnSet::with_capacity(self.insns.len());
5134+
for &param in &self.blocks[block.0].params {
5135+
assigned.insert(param);
5136+
}
5137+
// Check that each instruction's operands are assigned
5138+
for &insn_id in &self.blocks[block.0].insns {
5139+
let insn_id = self.union_find.borrow().find_const(insn_id);
5140+
let mut operands = VecDeque::new();
5141+
let insn = self.find(insn_id);
5142+
self.worklist_traverse_single_insn(&insn, &mut operands);
5143+
for operand in operands {
5144+
if !assigned.get(operand) {
5145+
return Err(ValidationError::OperandNotDefined(block, insn_id, operand));
5146+
}
5147+
}
5148+
if insn.has_output() {
5149+
assigned.insert(insn_id);
5150+
}
5151+
}
5152+
}
5153+
Ok(())
5154+
}
5155+
51285156
/// Checks that each instruction('s representative) appears only once in the CFG.
51295157
fn validate_insn_uniqueness(&self) -> Result<(), ValidationError> {
51305158
let mut seen = InsnSet::with_capacity(self.insns.len());
@@ -5425,6 +5453,7 @@ impl Function {
54255453
pub fn validate(&self) -> Result<(), ValidationError> {
54265454
self.validate_block_terminators_and_jumps()?;
54275455
self.validate_definite_assignment()?;
5456+
self.temporary_validate_block_local_definite_assignment()?;
54285457
self.validate_insn_uniqueness()?;
54295458
self.validate_types()?;
54305459
Ok(())
@@ -7577,6 +7606,16 @@ mod validation_tests {
75777606
assert_matches_err(function.validate_definite_assignment(), ValidationError::OperandNotDefined(entry, val, dangling));
75787607
}
75797608

7609+
#[test]
7610+
fn not_defined_within_bb_block_local() {
7611+
let mut function = Function::new(std::ptr::null());
7612+
let entry = function.entry_block;
7613+
// Create an instruction without making it belong to anything.
7614+
let dangling = function.new_insn(Insn::Const{val: Const::CBool(true)});
7615+
let val = function.push_insn(function.entry_block, Insn::ArrayDup { val: dangling, state: InsnId(0usize) });
7616+
assert_matches_err(function.temporary_validate_block_local_definite_assignment(), ValidationError::OperandNotDefined(entry, val, dangling));
7617+
}
7618+
75807619
#[test]
75817620
fn using_non_output_insn() {
75827621
let mut function = Function::new(std::ptr::null());
@@ -7588,6 +7627,17 @@ mod validation_tests {
75887627
assert_matches_err(function.validate_definite_assignment(), ValidationError::OperandNotDefined(entry, val, ret));
75897628
}
75907629

7630+
#[test]
7631+
fn using_non_output_insn_block_local() {
7632+
let mut function = Function::new(std::ptr::null());
7633+
let entry = function.entry_block;
7634+
let const_ = function.push_insn(function.entry_block, Insn::Const{val: Const::CBool(true)});
7635+
// Ret is a non-output instruction.
7636+
let ret = function.push_insn(function.entry_block, Insn::Return { val: const_ });
7637+
let val = function.push_insn(function.entry_block, Insn::ArrayDup { val: ret, state: InsnId(0usize) });
7638+
assert_matches_err(function.temporary_validate_block_local_definite_assignment(), ValidationError::OperandNotDefined(entry, val, ret));
7639+
}
7640+
75917641
#[test]
75927642
fn not_dominated_by_diamond() {
75937643
// This tests that one branch is missing a definition which fails.

0 commit comments

Comments
 (0)