The optimizer will first focus on simple peephole optimizations.
Since many instructions like brne, brlt, rcall, rjmp, ... can only jump +-64 words from the instruction pointer,
it is required to generate sequences that negate a conditon like brlt and jump over a jmp instruction
to perform the actual jump.
Since we do not know at that time if the brlt is sufficient for the range of the jump.
When the instructions have been selected, we can do peephole optimization to undo some of that redundant
code and make the generated code smaller and more readable.
brlt label_skip jmp label_actual_target label_skip: ... label_actual_target: nopcan be replaced by
brge label_actual_target label_skip: ... label_actual_target: nop
eliminating instructions which overwrite the effects of the previous instruction
cp r2, r4 cp r3, r5can be replaced by
cp r3, r5
Sometimes there are special instructions that can do the work of multiple simple instructions.
We can then use these more powerful instructions, even if the neighboring instructions are not from the same statement in the IR.
mov XL, r17 mov XH, r18can be written as
movw XL:XH, r17:r18
When generating code for a basic block, we do not necessarily know (or need to know) which block will follow afterwards in the assembly code. So they are connected by jumps. But when one block follows another, the redundant jump can be removed later.
tst r2 brne L5 rjmp L6 L6: mov r17, YLcan be replaced by
tst r2 brne L5 L6: mov r17, YL