Background
In many optimization passes we need to compute per-basic block info and propagate it through the CFG, or need a numbering order for each basic block. Currently the common way is to use DenseMap<BasicBlock *, T>, managed by whatever pass that needs to per block data. This is not the most efficient (both speed and memory usage) way, especially when the function contains a large amount of basic blocks. Profiling result shows that for the entire compilation duration, operations involving DenseMap<BasicBlock *, T> can account for up to 12% of the time in total. A search for such usage in the entire LLVM project yields more than a hundred results, indicating its prevalence.
Design
There will be a new generic field added to BasicBlock class. The purpose of this field is to supply any auxiliary per-block info used by a compiler pass, rather than storing data inherently tied to the block itself (such as its attributes). Given this, it is the responsibility of each pass to maintain the validity of the field’s value for the duration of the pass, including any memory cleanup should it allocate data and store the pointer in this field. The field’s value is considered undefined outside of the pass’ run() function as it is not owned by the block. In the case a pass generates sub-passes, it is also responsible to save and restore the auxiliary field if necessary.
The reason that this field is not preserved across passes is that many transformation passes can create new basic blocks, and it would reduce modularity to require a pass to initialize a new basic block’s field where others were created by a previous pass.
Implementation Details and Impact
Assuming a standard Linux 64-bit system, currently the first member (ignoring base class) of BasicBlock is bool IsNewDbgInfoFormat (1-bit info, 1-byte aligned) followed by InstListType InstList (8-byte aligned). This leaves a 63-bit gap to fit any info. It is sufficient for assigning a numbering order to basic blocks with uint32_t, which is currently assumed in many places. It is also sufficient to store a 64-bit pointer to a dynamically allocated object, given the max_align_t alignment requirement, which means that the lowest bit is definitely unset, so it can share sapce with the flag IsNewDbgInfoFormat.
Since adding this field will not change the size of BasicBlock, there will not be any change to memory usage. Existing code that access IsNewDbgInfoFormat would likely to emit the same assembly test %al, $1 in x86-64 (and something similar in other CPU), so there’s no performance impact.
As for comparing the performance between using this auxiliary field and using any map data structure mapping basic block to data, loading a field from the block object itself is obviously much faster than performing a map lookup.
Example Use Cases
In Mem2Reg, basic blocks are assigned an ordering for deterministic behavior. It could be beneficial to have the basic block number stored in the auxiliary field rather than in a DenseMap<BasicBlock*, unsigned>.

