I did a test to confirm that the corrected instruction sizes ensure that there are no more issues with invalid displacements being used with conditional jumps. The good news is that I can see the expected cutoff where the compiler switches from using a conditional jump (jeq ADDR) and a compound jump (jne +4; b @addr) to execute the right branch. The examples below should make this clearer.
While testing, I realized that the maximum displacement of conditional jumps is wrong. I forgot that the the instruction is encoded with half the true signed displacement. This gives us a range between -256 and +254 bytes counted from the start of the next instruction, not the +-128 I was using.
GCC calculates the displacement from the start of the instruction, while the processor uses the end. This means that the size of whatever jump code is used must be taken into account when determining the displacement limits.
NEG_DISP = 256 - CODE_SIZE
POS_DISP = 254 + CODE_SIZE
Here are the possible patterns for jump instructions and their maximum displacements from the initial PC. When multiple jumps are used, the largest displacement which satisfies all instructions is used.
jlt : [-254 .. 256]
jlt; jeq : [-252 .. 256]
jlt; b @ADDR : [-254 .. 256]
jlt; jeq; b @ADDR : [-252 .. 256]
jmp : [-254 .. 256]
b @ADDR : No limits
So to play it safe and prevent a situation where changing from one form to another causes an illegal instruction, let's just use the smallest common range of [-252 .. 256].
OK, new limits are in and tested. Looks good.
Well, back to wrangling subregs. Ugh.