I’m implementing a target-specific pseudo-instruction expanded via EmitInstrWithCustomInserter. For security reasons, the emitted instruction sequence must remain intact until after register allocation, unaffected by pre-RA passes like peephole, CSE, sinking or scheduling.
My approach is to wrap the sequence in a finalizeBundle to make it atomic to the pipeline and set MIFlag::NoMerge on all bundled instructions to block branch folding or merging. This combination is intended to preserve the sequence’s semantics and layout until RA completes.
How reliable is this approach in practice, and are bundled instructions truly treated as atomic units by all pre-RA passes?
If you have a pseudoinstruction to begin with, you should just expand that into the bundle post-RA. It’s discouraged to send bundles through register allocation.
However the point of the bundle is that it won’t be broken up, so it should work either way.
Hi @arsenm, thanks for your response. I checked the post-RA expansion pass, and ideally, the pseudo instruction should be expanded there.
However, in my case, the pseudo instruction expands into a multi-instruction sequence that requires temporary registers. Expanding it post-RA would mean dealing with physical register allocation, which can be tricky—especially for X86 or ARM targets.
Your pseudo needs to include a register def to use for your temporary, that’s not a barrier. One of the risks of pre-RA bundling is the unrestricted freedom to write unallocatable instructions.
Hi @arsenm Thanks for the pointers. I included temp register definition with pseudo instruction in tablegen and can use the same during expansion. This way I will not have to deal with allocating physical register or use Register Scavenger to get available one.