@@ -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