(Uploading as a work-in-progress in case anyone wants to comment.)
The two AssertZexts situation arises for boolean arguments on X86_64:
void f(bool x) {
LLVM will copy x from a 32-bit register, insert an AssertZext to capture that bits 8-31 are zero (as byte-sized arguments get extended on x86_64), and then another AssertZext to capture that bits 1-7 are also zero, because that's true for bools.
Combining the two allows us to optimize this code:
void g(bool); void f(bool x) { g(x); }
Previously:
movzbl %dil, %edi jmp _Z1gb
After my patch, no zero-extension is generated, as the value in %edi was already extended by the caller.
This raises a number of questions, though:
- Are 8- and 16-bit arguments really extended on x86_64? LLVM assumes so since http://reviews.llvm.org/rL34623, but the psABI doesn't seem to actually spell that out?
- Are bools really extended to 32 bits on x86_64? http://reviews.llvm.org/rL127766 says they are not and "[...] We still insert an i32 ZextAssert when reading a function's arguments, but it is followed by a truncate and another i8 ZextAssert so it is not optimized." The psABI seems to have gone back and forth here(!).
My patch would break Win64, because there it's clear that a bool argument is extended only to 8 bits, not 32 bits. But from what I understand, this isn't represented well: Clang's WinX86_64ABIInfo::classify will slap a "zext" attribute on the x parameter, and we end up with both AssertZexts.