55
66//! SSA-related utilities.
77
8- use crate :: cfg :: CFGInfo ;
8+ use std :: collections :: HashSet ;
99
10- use crate :: { Block , Function , Inst , OperandKind , RegAllocError } ;
10+ use crate :: cfg:: CFGInfo ;
11+ use crate :: { Block , Function , Inst , OperandKind , RegAllocError , VReg } ;
1112
1213pub fn validate_ssa < F : Function > ( f : & F , cfginfo : & CFGInfo ) -> Result < ( ) , RegAllocError > {
13- // For each vreg, the instruction that defines it, if any.
14- let mut vreg_def_inst = vec ! [ Inst :: invalid( ) ; f. num_vregs( ) ] ;
15- // For each vreg, the block that defines it as a blockparam, if
16- // any. (Every vreg must have a valid entry in either
17- // `vreg_def_inst` or `vreg_def_blockparam`.)
18- let mut vreg_def_blockparam = vec ! [ ( Block :: invalid( ) , 0 ) ; f. num_vregs( ) ] ;
19-
14+ // For every block param and inst def, check that this is the only def.
15+ let mut defined_in = vec ! [ Block :: invalid( ) ; f. num_vregs( ) ] ;
2016 for block in 0 ..f. num_blocks ( ) {
2117 let block = Block :: new ( block) ;
22- for ( i, param) in f. block_params ( block) . iter ( ) . enumerate ( ) {
23- vreg_def_blockparam[ param. vreg ( ) ] = ( block, i as u32 ) ;
18+ let mut def = |vreg : VReg , inst| {
19+ if defined_in[ vreg. vreg ( ) ] . is_valid ( ) {
20+ Err ( RegAllocError :: SSA ( vreg, inst) )
21+ } else {
22+ defined_in[ vreg. vreg ( ) ] = block;
23+ Ok ( ( ) )
24+ }
25+ } ;
26+ for & param in f. block_params ( block) {
27+ def ( param, Inst :: invalid ( ) ) ?;
2428 }
2529 for inst in f. block_insns ( block) . iter ( ) {
2630 for operand in f. inst_operands ( inst) {
27- match operand. kind ( ) {
28- OperandKind :: Def => {
29- vreg_def_inst[ operand. vreg ( ) . vreg ( ) ] = inst;
30- }
31- _ => { }
31+ if let OperandKind :: Def = operand. kind ( ) {
32+ def ( operand. vreg ( ) , inst) ?;
3233 }
3334 }
3435 }
@@ -37,39 +38,32 @@ pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllo
3738 // Walk the blocks in arbitrary order. Check, for every use, that
3839 // the def is either in the same block in an earlier inst, or is
3940 // defined (by inst or blockparam) in some other block that
40- // dominates this one. Also check that for every block param and
41- // inst def, that this is the only def.
42- let mut defined = vec ! [ false ; f. num_vregs( ) ] ;
41+ // dominates this one.
42+ let mut local = HashSet :: new ( ) ;
4343 for block in 0 ..f. num_blocks ( ) {
4444 let block = Block :: new ( block) ;
45- for blockparam in f. block_params ( block) {
46- if defined[ blockparam. vreg ( ) ] {
47- return Err ( RegAllocError :: SSA ( * blockparam, Inst :: invalid ( ) ) ) ;
48- }
49- defined[ blockparam. vreg ( ) ] = true ;
50- }
45+ local. clear ( ) ;
46+ local. extend ( f. block_params ( block) ) ;
47+
5148 for iix in f. block_insns ( block) . iter ( ) {
5249 let operands = f. inst_operands ( iix) ;
5350 for operand in operands {
5451 match operand. kind ( ) {
5552 OperandKind :: Use => {
56- let def_block = if vreg_def_inst[ operand. vreg ( ) . vreg ( ) ] . is_valid ( ) {
57- cfginfo. insn_block [ vreg_def_inst[ operand. vreg ( ) . vreg ( ) ] . index ( ) ]
58- } else {
59- vreg_def_blockparam[ operand. vreg ( ) . vreg ( ) ] . 0
60- } ;
61- if def_block. is_invalid ( ) {
62- return Err ( RegAllocError :: SSA ( operand. vreg ( ) , iix) ) ;
63- }
64- if !cfginfo. dominates ( def_block, block) {
53+ let def_block = defined_in[ operand. vreg ( ) . vreg ( ) ] ;
54+ let okay = def_block. is_valid ( )
55+ && if def_block == block {
56+ local. contains ( & operand. vreg ( ) )
57+ } else {
58+ cfginfo. dominates ( def_block, block)
59+ } ;
60+ if !okay {
6561 return Err ( RegAllocError :: SSA ( operand. vreg ( ) , iix) ) ;
6662 }
6763 }
6864 OperandKind :: Def => {
69- if defined[ operand. vreg ( ) . vreg ( ) ] {
70- return Err ( RegAllocError :: SSA ( operand. vreg ( ) , iix) ) ;
71- }
72- defined[ operand. vreg ( ) . vreg ( ) ] = true ;
65+ // Check all the uses in this instruction
66+ // first, before recording its defs below.
7367 }
7468 OperandKind :: Mod => {
7569 // Mod (modify) operands are not used in SSA,
@@ -79,6 +73,14 @@ pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllo
7973 }
8074 }
8175 }
76+ // In SSA form, an instruction can't use a VReg that it
77+ // also defines. So only record this instruction's defs
78+ // after its uses have been checked.
79+ for operand in operands {
80+ if let OperandKind :: Def = operand. kind ( ) {
81+ local. insert ( operand. vreg ( ) ) ;
82+ }
83+ }
8284 }
8385 }
8486
0 commit comments