Immediate Encoding: Packing Literals in Machine Code

Immediate encoding is a CPU instruction format technique where constant numeric values—known as literal values or immediates—are embedded directly inside the binary instruction word rather than stored in separate memory locations or registers. This article explores the architecture of immediate encoding, detailing how binary literals are partitioned, formatted, sign-extended, and packed into fixed-width and variable-length machine instructions to maximize processor efficiency and execution speed.

What Is an Immediate Operand?

In assembly language and machine code, an immediate operand is a hardcoded constant value used directly by an operation. For instance, in an instruction like ADD R1, R2, #5, the number 5 is an immediate value. Instead of requiring the central processing unit (CPU) to perform an extra memory access cycle to fetch this constant from the data cache or RAM, the processor reads the value directly from the instruction stream as it decodes the binary word.

Structure of an Instruction Word

CPU architectures process instructions as binary words, commonly 32 or 64 bits wide in modern Reduced Instruction Set Computer (RISC) systems, or variable lengths in Complex Instruction Set Computer (CISC) systems like x86. An instruction word is divided into distinct bit fields:

In a standard 32-bit RISC instruction (such as a MIPS I-type instruction), the layout typically allocates 6 bits for the opcode, 5 bits for the source register (\(R_s\)), 5 bits for the destination register (\(R_t\)), and the remaining 16 bits for the immediate value:

[ Opcode (6 bits) | Rs (5 bits) | Rt (5 bits) | Immediate Literal (16 bits) ]

How Binary Literals Are Packed

When an assembler translates code containing a constant, it converts the literal number into a binary integer and inserts it directly into the allocated bit positions of the instruction.

1. Bit-Width Constraints and Range

The number of bits allocated to the immediate field determines the range of values that can be encoded: - An unsigned \(n\)-bit field represents values from \(0\) to \(2^n - 1\). - A signed \(n\)-bit field represents values from \(-2^{n-1}\) to \(2^{n-1} - 1\) using two’s complement binary notation.

For a 12-bit signed immediate (common in ARM and RISC-V architectures), the literal can range from \(-2048\) (0x800) to \(+2047\) (0x7FF).

2. Sign Extension and Zero Extension

Because immediate fields are usually smaller than the CPU’s general-purpose register width (e.g., a 12-bit or 16-bit immediate loaded into a 32-bit or 64-bit register), the CPU must expand the literal during execution: - Sign Extension: For signed arithmetic and memory offsets, the most significant bit (MSB) of the immediate field—the sign bit—is replicated across all higher-order bits of the register. If the sign bit is 1 (negative), the upper bits become 1s; if 0 (positive), the upper bits become 0s. - Zero Extension: For logical operations (like ANDI or ORI), the upper bits of the register are filled strictly with 0s to preserve the literal as an unsigned value.

3. Split-Field Immediate Encoding

Some modern architectures, such as RISC-V, intentionally split immediate fields across non-contiguous bit positions in the instruction word. This design keeps the register specifiers in fixed bit locations across all instruction formats, simplifying the hardware decoder.

For example, a RISC-V store instruction (S-type) splits a 12-bit immediate into two chunks: - Bits 11:5 are placed in instruction bits 31:25. - Bits 4:0 are placed in instruction bits 11:7.

The CPU hardware routes these separate bit slices through internal wiring to reconstruct the original 12-bit two’s complement number before feeding it into the Arithmetic Logic Unit (ALU).

4. Scaled and Shifted Immediates

To extend the effective reach of small immediate fields without increasing instruction length, architectures often apply implicit scaling: - PC-Relative Branching: Since instructions are typically aligned to 2-byte or 4-byte boundaries, the least significant bit(s) of branch target offsets are always 0. Instruction encodings omit these trailing zeros, shifting the immediate value left by 1 or 2 bits during decoding. A 12-bit branch field can thus address a \(\pm 4\text{KB}\) or \(\pm 8\text{KB}\) range. - Shifted Literals: Architectures like ARM provide instructions where an 8-bit immediate is paired with a 4-bit rotation or shift factor, allowing a compact field to represent large sparse numbers (e.g., 0xFF000000).

Handling Large Literals

When a literal value exceeds the bit capacity of a single instruction’s immediate field, architectures handle it using multi-instruction sequences: 1. Upper Immediate Instructions: An instruction such as LUI (Load Upper Immediate) loads the upper 20 bits of a 32-bit constant into a register. 2. Lower Immediate Instructions: A subsequent instruction, such as ADDI or ORI, provides the lower 12 bits, combining them into the full 32-bit literal.

By tightly packing constant values into the binary instruction layout, processors avoid extraneous memory lookups, minimize pipeline stalls, and optimize the execution footprint of software programs.