Skip to main content

Module simplify

Module simplify 

Source
Expand description

Peephole rewrites: a small pattern of instructions becomes a smaller one.

The third pass, and the one that will eventually not exist. Section 9.3 of spec/09-optimizer.md says the value level optimizer is an acyclic e-graph, and that an e-graph replaces what would otherwise be a folding pass, a peephole pass, a GVN pass, a reassociation pass and an instcombine pass, all with a pass ordering problem between them. This is the peephole pass, written now because the e-graph is a milestone away and because there is a rewrite that unblocks twelve lowering rules today.

Every rewrite here has to survive being moved into the rule set later, so each one is stated as a pattern and a replacement in its own function and nothing shares state with anything.

§The rewrites

One so far: an exclusive or of a comparison with an i1 of all ones is that comparison with the opposite predicate. That is issue 379, and it is worth more than the instruction it saves.

C spells eight of the sixteen floating point predicates. The six relational and equality operators give the six ordered ones, != gives une, and __builtin_isunordered gives uno. The other eight are what the negation of one of those means, and the front end writes a negation as an exclusive or rather than as a flipped predicate, so !(x < y) lowers to an fcmp olt and an xor where the machine has an fcmp uge. Twelve rules in the x86-64 rule set are written on those predicates and none of them has ever fired, over the whole torture suite at every optimization level, because no IR that reaches selection contains one.

The integer case comes with it. !(a < b) on integers is the same shape, the same rewrite and the same saving, and leaving it out because the coverage report did not complain about it would be picking the rewrite by what measures it rather than by what it does.

§Why it needs dead code elimination after it

The rewrite turns the xor into the comparison and leaves the original comparison where it was, used by nothing when the negation was its only reader. Rewriting in place keeps the result value, so every use of it is already correct and there is nothing to rewrite, and what is left over is exactly what crate::dce takes out. That is why the pipeline runs the two in this order, and it is why the pass before the dead code eliminator was written first.

Structs§

Simplify
The pass. It holds nothing, because a peephole needs to know nothing beyond the pattern.