Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Instructions x86 has and RISC-V doesn’t

Several x86 staples have no direct single-instruction equivalent in the base RISC-V ISA. The table below shows what you might instinctively reach for and what you should write instead.

Arithmetic

You want …In x86RISC-V replacement
subtract immediatesub r, immaddi rd, rs, -imm (no subi exists; negate the immediate)

ADDI sign-extends its 12-bit immediate, so a single addi covers any small subi. For subtract-immediate with an out-of-range constant, load the immediate then use SUB.

# x86:  sub eax, 42
addi a0, a0, -42

# x86:  sub eax, 100000        (fits in 12-bit signed?  -100000 = 0xFFFE7960, no)
li   t0, 100000
sub  a0, a0, t0

Moves

You want …In x86RISC-V replacement
register-to-register copymov r1, r2mv rd, rs (pseudo: addi rd, rs, 0)
immediate-to-registermov r, imm32li rd, imm (pseudo, may expand to addi + lui + shifts)
memory-to-registermov r, [addr]load instruction (lb/lh/lw/ld) with address in a register
register-to-memorymov [addr], rstore instruction (sb/sh/sw/sd) with address in a register

x86’s mov is overloaded across widths, addressing modes, and source types. RISC-V separates each concern into distinct instructions. The only “move” in the base ISA is ADDI with a zero immediate — everything else is a pseudoinstruction or an explicit load/store.

# x86: mov eax, ebx
mv a0, a1                    # actually addi a0, a1, 0

# x86: mov eax, 0x1234
li  a0, 0x1234

# x86: mov eax, [ebx]
lw  a0, 0(a1)

# x86: mov [ebx], eax
sw  a0, 0(a1)

Logical

You want …In x86RISC-V replacement
bitwise NOTnot rnot rd, rs (pseudo: xori rd, rs, -1)
two’s-complement negateneg rneg rd, rs (pseudo: sub rd, x0, rs)

Neither NOT nor NEG are real RISC-V instructions. The assembler accepts them as pseudoinstructions that expand to a single XORI or SUB with x0.

not a0, a1                   # actually xori a0, a1, -1
neg a0, a1                   # actually sub  a0, x0, a1

Branches

You want …In x86RISC-V replacement
branch if zerojz labelbeqz rs, label (pseudo: beq rs, x0, label)
branch if not zerojnz labelbnez rs, label (pseudo: bne rs, x0, label)

RISC-V branches always take two register operands — there is no single-operand branch in the base ISA. The common beqz/bnez mnemonics are pseudoinstructions supplied by the assembler.

beqz a0, target               # actually beq a0, x0, target
bnez a0, target               # actually bne a0, x0, target

Stack

You want …In x86RISC-V replacement
push registerpush raddi sp, sp, -8 / sd rs, 0(sp)
pop registerpop rld rd, 0(sp) / addi sp, sp, 8

RISC-V has no stack-oriented instructions. The stack pointer (sp = x2) is a regular register with no hardware-backed push/pop semantics. Stack frames are managed explicitly.

# push a0
addi sp, sp, -8
sd   a0, 0(sp)

# pop a0
ld   a0, 0(sp)
addi sp, sp, 8

The standard calling convention designates sp as the stack pointer and requires it to remain 16-byte aligned at function-call boundaries, but no instruction enforces this — it is purely ABI convention.

Summary

x86 mnemonicExists in RISC-V?What to use
sub with immediateNo real subiaddi with negated immediate
movNo single instructionmv, li, loads, stores
notNo real instructionnot pseudo (xori)
negNo real instructionneg pseudo (sub rd, x0, rs)
jz / jnzNo single-operand branchbeqz / bnez pseudo
push / popNoexplicit sp adjustment + load/store

Related: What deliberately has no direct equivalent, Pseudoinstructions.