ARM Assembly Is Too High Level: ROR and RRX
I don&#x27;t quite understand the objection here, this is fairly elegant in my opinion, you have a single opcode used to encode several operations by using &quot;special cases&quot;. In my experience it&#x27;s rather common in RISC IAs.<p>If the author doesn&#x27;t like this they shouldn&#x27;t look into MIPS because it goes well beyond that. You see, MIPS has a special &quot;R0&quot; register that&#x27;s always 0 (AARCH 64 does as well by the way) so you can always use it as a placeholder in other instructions.<p>As such, there&#x27;s no real MOVE instruction, it&#x27;s just an assembler mnemonic that assembles down to `OR $target, $src, $R0`. NOP? It&#x27;s by convention `SLL $R0, $R0, 0` (which has the nice property of being an instruction encoding as &quot;0x00000000&quot;). You want to negate a number? `SUB $target, $R0, $src&quot;.<p>Since all instructions are 32bit wide you can&#x27;t load a 32bit immediate value in a single instruction, instead the assembler&#x27;s &quot;LI&quot; mnemonic generates a pair of instructions (LUI&#x2F;ORI) for large immediate values (ARM prefers PC-relative loads).<p>You have a whole bunch of mnemonics in MIPS that are just aliases around other instructions. I always thought it was pretty clever.<p>In summary you can have this assembler listing:<p><pre><code>    1:
        sll $0, $0, 0
        or  $t0, $t1, $0
        li  $t0, 0xabcdef
        sub $t0, $0, $t1
        j   1b
</code></pre>
That will disassemble to:<p><pre><code>        nop
        move    t0,t1
        lui     t0,0xab
        ori     t0,t0,0xcdef
        j       0x0
        neg     t0,t1
</code></pre>
The only operation here that I would qualify as &quot;high level&quot; is
the reordering of the &quot;neg&quot; instruction into the delay slot (note
that j is no longer the last instruction). Everything else is
very straightforward substitution and if the assembler didn&#x27;t
support these mnemonics we could implement them with very trivial
macros.<p>Note that even x86 assemblers do that to some extent, for
instance &quot;nop&quot; assembles down to an instruction with no side
effect (typically `xchg eax, eax`). Furthermore there are a bunch
of mnemonics for the same encoding, for instance JAE (jump if
above or equal), JNB (jump if not below) and JNC (jump if not
carry). Overall instruction encoding is also massively more
complicated in x86 (and even more for amd64) so the assembler
needs to handle many more corner cases than the simple
substitutions of ARM and MIPS. As a brain teaser, consider the
following similar looking amd64 instructions that load the 32bit
value pointed at by a register (the only difference is that the
first one dereferences the pointer in %rax, the second in %r12):<p><pre><code>        mov �x, (%rax) ; assembles to 89 00
        mov �x, (%r12) ; assembles to 41 89 04 24
</code></pre>
I can&#x27;t even be bothered to walk you through this but basically
it has to do with the fact that %r12 happens to be encoded as
%rsp + 8 (because registers r8 to r15 are effectively a hack
since x86 only supported 8 GPRs) and %rsp has special semantics
in this addressing mode which mandate a different, longer
encoding otherwise you end up with an ambiguous instruction.<p>Yeah, I think in retrospect we can give ARM a pass for their ROR
shenanigans.