Alternative opcodes

|

A support question brought up an interesting optimization topic: alternative opcodes.

We've all heard stories of using undocumented or unofficial opcodes to squeeze out a few cycles' extra performance. It's much easier, not to mention safer, to work within the published instruction set but to approach it in novel ways.

Here's an example:

In the HC08, opcode 65 is a CPHX immediate. However, if you don't care how the condition codes are set or what the contents of the next two bytes are, it can also be a "skip the next two bytes" instruction.

00FF                                   unsigned int8 val;
00FE                                   unsigned int8 result;

8000 B6 FF        LDA    $FF           if(val < 177)
8002 A1 B1        CMP    #$B1        
8004 24 03        BCC    $8009       
8006 3C FE        INC    $FE             result++;
8008 65           SKP2                 else
8009 3A FE        DEC    $FE             result--;

If the INC happens, the SKP2 at 8008 performs a useless CPHX. If the DEC is to happen, the BCC at 8004 jumps to 8009, which is the second byte of the CPHX. The arguments of the useless CPHX are actually a DEC instruction.

Why do we do it? It is a way to save a byte of generated code, and, in some processors, it is a way to eliminate a pipeline stall that would happen it the SKP2 were replaced with a normal branch.

(There is a SKP1 as well. In the HC08, there is a "branch never" instruction whose only practical purpose is to skip a byte.)

In some cases these pseudo-instructions are so specific that specialized code generation rules in a compiler are needed to determine if they can be used to an advantage. The non-standard opcodes make it more clear what's going on, for compiler developers and end users alike.