Rather than tracking 3 maps of {VariableID: SomeInfo} per block, use a BitVector indexed by VariableID to mask 3 vectors of SomeInfo.
BlockInfos now need to be initialised with a call to init which sets the BitVector width to the number of partially promoted variables in the function and fills the vectors with Top values.
Prior to this patch, in joinBlockInfo, it was necessary to insert Top values into the Join result for variables in A XOR B after joining the variables in A AND B. Now, because the vectors are pre-filled with Top values we need only join the variables A AND B and set the BitVector of tracked variables to A OR B.
The patch achieves an average of 0.25% reduction in instructions retired and a 1.1% max-rss for the CTMark suite in LTO-O3-g builds.
It's a matter of taste, but I find the algorithms approach easier to read. Alternatively, I think this loop can at least use the set_bits() range rather than find_first+find_next