Hi All,
I work on a backend for a target similar to Mips, where large immediates are loaded into registers with 2 instructions, 1 to load the MSBits and 1 to load the LSBits. I've noticed a recurring pattern where, despite low register pressure, these constants will be rematerialized in every iteration of a loop, rather than being hoisted. Here's an example using the mips-unknown-unknown target and Clang/LLVM HEAD. From newlib's implementation of strncat:
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
while (!DETECTNULL (*aligned_s1))
aligned_s1++;
This loop gets lowered under -O3 to:
$BB0_5:
lui $3, 32896
lui $7, 65278
ori $3, $3, 32896 ###### Materialize 0x80808080
lw $8, 4($2)
nop
and $9, $8, $3
ori $7, $7, 65279 ###### Materialize -(0x01010101)
addiu $2, $2, 4
xor $3, $9, $3
addu $7, $8, $7
and $3, $3, $7
beq $3, $zero, $BB0_5
There are a ton of unused caller-saved registers in this small function, so I expected the constant materialization to be hoisted out of the tight loop. I'm still learning about the new register allocator and am not immediately able to make sense of its debug output (and the 'problem' may be elsewhere in any case). I'm happy to post the results of -debug-only regalloc if they're useful.
Is my desire to hoist the constants out of the loop reasonable? Is there something I can do (hints or passes in my backend, clang/opt flag, etc.) to make this happen today? If not, what is the root cause? Maybe there's no way to hoist things out of a loop once IR is lowered into a SelectionDAG?
Thanks,
Matt