ISAx86-64armaarch64risc-vencodingecosystem

x86-64, ARM and RISC-V: Three Families, Three Histories

Three instruction sets dominate current computing, and their differences are largely differences of origin and constraint rather than of achievable performance. Knowing what each optimised for explains their shape better than any claim about which is better.

Follow the mechanism

Software view, hardware view

The gap between what you wrote and what the machine does is where this whole domain lives.

The question
What actually distinguishes the major instruction sets, and does the choice determine anything a programmer will notice?
What you wrote
My code runs on whichever machine it is deployed to; the instruction set is a build target.
What the hardware does
Three families with different encodings, different register counts, different memory ordering guarantees and very different licensing and ecosystem positions — differences that surface in generated code, in concurrent-code portability and in what hardware you can buy.
Cross-architecture deployment is now routine, and the two differences that actually bite — memory ordering and extension baselines — are exactly the ones people do not anticipate.
SourceCompilerInstructionsFront EndExecutionRegistersCachesMemoryI/OBehavior

Three families, and what each was designed under

x86-64 descends from a design lineage stretching back decades, extended repeatedly while preserving backward compatibility throughout. Its encoding is variable-length, its architectural register count is modest by modern standards, and it carries genuine historical accretion — all of which are consequences of never having broken compatibility.

AArch64 is ARM's 64-bit architecture, and it had the advantage of being designed comparatively recently with the benefit of hindsight. Fixed-length instructions, more architectural registers, and a memory model that permits more reordering — a choice that trades some ease of concurrent programming for implementation freedom, and one that reflects ARM's origins in power-constrained designs.

RISC-V is an open standard rather than a proprietary architecture, structured as a small mandatory base plus optional extensions. Its distinguishing feature is not technical elegance so much as licensing: anyone may implement it without a licence fee, which is why it appears in research, in education and increasingly in embedded and specialised silicon.

The three families at a glance — properties, not verdicts
x86-64AArch64RISC-V
Instruction encodingVariable lengthFixed lengthFixed length base, optional compressed extension
Architectural GPRsFewerMoreMore
Memory orderingRelatively strongWeaker — more reordering permittedWeaker; explicit ordering instructions
Design originDecades of backward-compatible extensionClean-sheet 64-bit designOpen standard, modular by construction
LicensingProprietaryProprietary, licensedOpen — no licence fee to implement
Where you meet itDesktops, most serversMobile, laptops, a growing server shareEmbedded, research, specialised accelerators

Variable versus fixed length, concretely

The encoding difference is the one most often discussed and the one with the clearest engineering consequence. On a variable-length ISA, an instruction may occupy anywhere from one byte to many, so a decoder cannot know where the next instruction begins until it has partially decoded the current one — which makes decoding several instructions per cycle genuinely hard, and is why high-performance implementations invest heavily in caching already-decoded operations.

On a fixed-length ISA, instruction boundaries are known in advance. Decoding several at once is straightforward, since their positions are arithmetic. The cost is code density: some operations that a variable-length encoding expresses compactly need more bytes, which is why several fixed-length ISAs add optional compressed encodings to claw density back.

The honest summary is that this is a real trade with real consequences for decoder area and power, and that it is not the dominant term in delivered performance on high-end implementations — where the front end is heavily engineered specifically to make it stop being one. It matters most where there is no budget for that engineering.

Instruction boundaries: found by decoding versus known by arithmetic
Variable-length (x86-64 style)
  offset 0x00:  48 89 e5              ; 3 bytes
  offset 0x03:  48 83 ec 20           ; 4 bytes
  offset 0x07:  8b 45 fc              ; 3 bytes
  offset 0x0a:  ...
  -> the start of instruction N+1 is not known until N is decoded,
     so parallel decode requires speculation or pre-decode metadata.

Fixed-length (AArch64 style)
  offset 0x00:  aa0003e1              ; 4 bytes
  offset 0x04:  91008021              ; 4 bytes
  offset 0x08:  b9400fe0              ; 4 bytes
  -> every boundary is offset + 4k, so N instructions can be
     fetched and decoded in parallel without ambiguity.

(Byte values are illustrative of shape, not disassembly of real code.)

The differences that actually reach your code

Two differences matter to a working programmer, and neither is encoding. The first is memory ordering. x86-64 provides comparatively strong ordering guarantees; AArch64 permits more reordering. Concurrent code with a missing synchronisation annotation can work by accident on the stronger model and fail on the weaker one — which is exactly the shape of bug that surfaces when a service is ported to a different architecture after years of running fine (Hardware Memory Models Are Not Language Memory Models, Why Your Loads and Stores Happen Out of Order).

The second is extension baselines. All three families are really a base plus a large set of optional extensions. Building with extensions your deployment hardware lacks produces a binary that fails at startup or, worse, when it first reaches the offending code path. This is a routine cross-architecture deployment problem and it is entirely avoidable by specifying the baseline explicitly at build time.

Everything else — register count, encoding, philosophical lineage — reaches you only through the compiler, which handles it. These two reach you directly, and both are worth checking before a port rather than after.

  • Memory ordering differs, and code that relies on the stronger model can fail on the weaker one.
  • Extension baselines differ; build for the baseline you deploy to, not the one you compile on.
  • Register count changes generated code quality but is handled by the compiler.
  • Encoding affects decoder design far more than it affects your program.
  • Before porting: audit synchronisation annotations and pin the ISA baseline. Those two are the ones that bite.
What actually breaks during a cross-architecture port
DifferenceReaches your code how?What to do before porting
Memory orderingConcurrency bugs that never appeared on the stronger modelAudit synchronisation annotations; test on the weaker model
Extension baselineIllegal instruction at startup or on a rare pathPin the baseline explicitly at build time
Register countDifferent spilling behaviour in generated codeNothing — the compiler handles it
Instruction encodingNothing directlyNothing
Instruction timingDifferent hot spotsRe-profile on the target; do not extrapolate

Key points

  • The three families differ mainly in encoding, register count, memory ordering strength and licensing — not in achievable performance.
  • Variable-length encoding makes parallel decode hard; fixed-length makes it easy at some cost in code density.
  • x86-64 orders memory more strongly than AArch64, which is where cross-architecture concurrency bugs come from.
  • All three are a base plus optional extensions; the baseline you build for is your minimum deployable hardware.
  • Everything except ordering and extensions reaches you only through the compiler.

Follow the mechanism

The path through the machine, hop by hop — and the conclusions it invites that are wrong.

  1. 1
    Source → compiler: a target ISA and extension baseline are selected, explicitly or by defaulting to the build machine.
  2. 2
    Compiler → encoding: instructions are emitted in the target's format, variable or fixed length.
  3. 3
    Binary → decoder: fixed-length boundaries are computed; variable-length boundaries must be discovered by decoding.
  4. 4
    Concurrent code → memory model: the architecture's ordering guarantees determine whether the synchronisation is sufficient.
  5. 5
    Runtime → extension check: an instruction outside the hardware baseline faults rather than executing.
What people conclude from this — wrongly
  • "It compiles for both architectures, so it works on both." Compilation checks the instruction set, not the memory model your code assumes.
  • "RISC-V is faster because it is a cleaner design." Openness and modularity are its distinguishing properties; performance belongs to implementations.
  • "Fixed-length encoding means faster." It makes parallel decode easier and costs code density. Neither dominates delivered performance on high-end designs.

Consequences, controls and cost

What it causes
  • • Concurrent code correct on x86-64 can exhibit real ordering bugs when ported to AArch64.
  • • A binary built with newer extensions fails on older hardware, sometimes only on a rarely-taken path.
  • • Generated code for the same source differs in register spilling behaviour between ISAs with different register counts.
What you can do
  • • Audit synchronisation annotations before porting to a weaker memory model — do not rely on testing to find the gaps.
  • • Pin the ISA baseline explicitly in build configuration rather than inheriting the build machine's capabilities.
  • • Test on the target architecture in CI; cross-architecture behaviour differences do not show up on the developer machine.
  • • Use runtime feature detection with fallbacks where extension-dependent code paths are worth the complexity.
How to see it
  • • Run the concurrency test suite on the weaker memory model specifically; passing on x86-64 tells you very little about AArch64.
  • • Inspect built binaries for the extensions they actually require before deploying to a different hardware baseline.
  • • Benchmark on the target architecture rather than extrapolating from a different one.
What it costs
  • • Supporting multiple architectures multiplies build, test and debugging surface for real portability.
  • • A conservative extension baseline maximises compatibility and forgoes performance available on newer hardware.

Scope

§224 — what these claims are specific to.

What these claims are specific to
  • ISA-SPECIFICEvery claim here is about a specific instruction set family; encoding, register count and ordering guarantees differ between all three.
  • SIMPLIFIEDEach family spans many profiles and extension sets. "AArch64" and "RISC-V" in particular cover configurations with materially different capabilities.

Misconceptions

Claim
“ARM is inherently more power-efficient than x86.”
Reality
Efficiency is dominated by implementation and manufacturing process, not by instruction set. ARM's association with efficiency comes from decades of designs targeting power-constrained markets, not from the encoding.
Claim
“RISC-V being open makes it faster.”
Reality
Openness is a licensing property. It lowers the barrier to building a processor; it says nothing about how good any particular implementation is.
Claim
“Porting between architectures is a recompile.”
Reality
Usually, but the exceptions are expensive: memory-ordering assumptions in concurrent code and extension-baseline mismatches both survive a clean compile and fail at runtime.