List scheduling is good in Basic Block, but in a function, there are a list of basic blocks needed to be in order. Therefore how order those basic blocks to gain some performance.
Well, the simple options are
1. Order basic blocks in their created order (original order).
2. Topological sorted order, etc.
But keep in mind that the entry basic block must be the first one.
Order basic blocks in their original order has benefit that it need not fixup code at the end for adjustment caused by basic block reordering.
However, we can do a bit effort to gain some performance to take advantage of the last instruction in basic block should be terminator or branching, and the first instruction should be the target of branching. Then how about we order those basic blocks in an order that the branch targeted basic block following the branching basic block on false condition or uncondition to minify the branching instruction.
That is the base idea for simple trace schedule.
procedure generate_traces( BasicBlocks, Traces)
// BasicBlocks: std::list<BasicBlock>
// Traces: std::vector<std::list<BasicBlock>>
while BasicBlocks != {} {
std::list<BasicBlock> trace;
bb = BasicBlocks.removeHead();
while bb.inTrace == false {
bb.inTrace = true;
trace += bb;
foreach suc in bb.sucessors {
// suppose the false condition successor will be first.
if suc.inTrace == false { bb = suc; break;}
}
}
}
After the above procedure, we got several traces of the given basic blocks, each basic block will be in exactly one trace. Then we just order basic block in Traces order and in-trace oder. That is:
procedure ordering(OrderedBasicBlocks, Traces)
foreach trace in Traces
foreach bb in trace
OrderedBasicBlocks += bb;
Of course, we need some fix up at the end of some basic block. Particularly, the branch instruction needs to be adjusted for new basic block order. That is easy and straight forward therefore not showed here.