Skip to main content
Technical proposal SIMD-0174 Review

SBPF arithmetics improvements

  1. Idea
  2. Draft
  3. Review
  4. Accept
  5. Implement
  6. Active

Decision brief

Why this proposal matters

This proposal introduces wide multiplication, signed division and explicit sign extension to SBPF.

Source-backed reading aid · source language: EN

Proposal at a glance

What changes

  • the MUL instruction (opcodes 0x24, 0x2C, 0x27 and 0x2F)
  • the DIV instruction (opcodes 0x34, 0x3C, 0x37 and 0x3F)
  • the MOD instruction (opcodes 0x94, 0x9C, 0x97 and 0x9F)

Stakeholder map

Who is affected

Builders & client teams Medium impact

The following must go into effect if and only if a program indicates the SBPF-version (v2) or higher in its program header (see SIMD-0161).

Action may be required
Validators & operators Impact unknown

No proposal-specific evidence was found for this group.

Action requirement unknown
Users & stakers Impact unknown

No proposal-specific evidence was found for this group.

Action requirement unknown
Governance & ecosystem Medium impact

This proposal introduces wide multiplication, signed division and explicit sign extension to SBPF.

Action requirement unknown

Exact source revision

Full proposal document

Source-language document. Technical identifiers and evidence remain unchanged. 0616093b2952

Summary

This proposal introduces wide multiplication, signed division and explicit sign extension to SBPF.

Motivation

All major hardware ISAs support 64 x 64 = 128 bit multiplication; BPF does not. This hurts performance of big integer arithmetics. Similarly, signed division and signed remainder / modulo instructions must be emulated in software as well.

Another issue related to arithmetics is that some 32 bit instructions perform sign extension of their results (output, not input, there is a difference) implicitly. This is first of all useless because source languages do not read the 32 MSBs of a 32 bit result stored in a 64 bit register. And second, it requires interpreters and compilers to perform extra work to add sign extension at the end of these instructions. Instead we should go the same route as the underlying hardware ISAs and require sign extension to be made explicit in a dedicated instruction.

Furthermore, the instruction sub dst, imm is redundant as it can also be encoded as add dst, -imm. If we were to swap the operands meaning of minuend and subtrahend, then the instruction would become useful and would even render neg dst redundant. Negation would then be encoded as reg = 0 - reg. This would also make it clear how sign extension rules work for negation.

Alternatives Considered

None.

New Terminology

None.

Detailed Design

The following must go into effect if and only if a program indicates the SBPF-version (v2) or higher in its program header (see SIMD-0161).

Changes to the Bytecode Verifier

A program containing one of the following instructions must throw VerifierError::UnknownOpCode during verification:

  • the MUL instruction (opcodes 0x24, 0x2C, 0x27 and 0x2F)
  • the DIV instruction (opcodes 0x34, 0x3C, 0x37 and 0x3F)
  • the MOD instruction (opcodes 0x94, 0x9C, 0x97 and 0x9F)
  • the NEG instruction (opcodes 0x84 and 0x87)

A program containing one of the following instructions must not throw VerifierError::UnknownOpCode during verification anymore (opcodes are for immediate and register variant each, in that order):

  • the UHMUL64 instruction (opcode 0x36 and 0x3E)
  • the UDIV32 instruction (opcode 0x46 and 0x4E)
  • the UDIV64 instruction (opcode 0x56 and 0x5E)
  • the UREM32 instruction (opcode 0x66 and 0x6E)
  • the UREM64 instruction (opcode 0x76 and 0x7E)
  • the LMUL32 instruction (opcode 0x86 and 0x8E)
  • the LMUL64 instruction (opcode 0x96 and 0x9E)
  • the SHMUL64 instruction (opcode 0xB6 and 0xBE)
  • the SDIV32 instruction (opcode 0xC6 and 0xCE)
  • the SDIV64 instruction (opcode 0xD6 and 0xDE)
  • the SREM32 instruction (opcode 0xE6 and 0xEE)
  • the SREM64 instruction (opcode 0xF6 and 0xFE)

The verification rule, that an immediate divisor must not be zero or else VerifierError::DivisionByZero is thrown, is moved to the new division like instructions: UDIV32_IMM, UDIV64_IMM, UREM32_IMM, UREM64_IMM, SDIV32_IMM, SDIV64_IMM, SREM32_IMM, SREM64_IMM.

Changes to Execution

PQR Instruction Class

A new instruction class product, quotient and remainder (PQR) is introduced:

  • the UHMUL64 instruction (opcode 0x36 and 0x3E) produces the 64 MSBs of the product of an unsigned 64 x 64 bit multiplication (dst * imm and dst * src).
  • the UDIV32 instruction (opcode 0x46 and 0x4E) produces the quotient of an unsigned 32 bit division (dst / imm and dst / src).
  • the UDIV64 instruction (opcode 0x56 and 0x5E) produces the quotient of an unsigned 64 bit division (dst / imm and dst / src).
  • the UREM32 instruction (opcode 0x66 and 0x6E) produces the remainder of an unsigned 64 bit division (dst % imm and dst % src).
  • the UREM64 instruction (opcode 0x76 and 0x7E) produces the remainder of an unsigned 64 bit division (dst % imm and dst % src).
  • the LMUL32 instruction (opcode 0x86 and 0x8E) produces the 32 LSBs of the product of any 32 x 32 bit multiplication (dst * imm and dst * src).
  • the LMUL64 instruction (opcode 0x96 and 0x9E) produces the 64 LSBs of the product of any 64 x 64 bit multiplication (dst * imm and dst * src).
  • the SHMUL64 instruction (opcode 0xB6 and 0xBE) produces the 64 MSBs of the product of a signed 64 x 64 bit multiplication (dst * imm and dst * src).
  • the SDIV32 instruction (opcode 0xC6 and 0xCE) produces the quotient of a signed 32 bit division (dst / imm and dst / src).
  • the SDIV64 instruction (opcode 0xD6 and 0xDE) produces the quotient of a signed 64 bit division (dst / imm and dst / src).
  • the SREM32 instruction (opcode 0xE6 and 0xEE) produces the remainder of a signed 32 bit division (dst / imm and dst / src).
  • the SREM64 instruction (opcode 0xF6 and 0xFE) produces the remainder of a signed 64 bit division (dst / imm and dst / src).

Runtime exceptions are:

  • If the divisor (imm or src) of any division is zero, EbpfError::DivideByZero must be thrown.
  • If the dividend (dst) of a signed division has the minimal value for its bit-width and the divisor (imm or src) is -1, then EbpfError::DivideOverflow must be thrown.

Explicit Sign Extension

The following instructions must stop performing implicit sign extension of their results, instead filling the 32 MSBs of dst with zeros:

  • the ADD32 instruction (opcode 0x04 and 0x0C)
  • the SUB32 instruction (opcode 0x14 and 0x1C)
  • all of the new 32 bit PQR instructions: UDIV32, UREM32, SDIV32, SREM32 and LMUL32

Instead the MOV32_REG instruction (opcode 0xBC) which until now did zero out the 32 MSBs, must now perform sign extension in the 32 MSBs. Meaning this instruction becomes the explicit sign extension operation.

Register Immediate Subtraction

The operands roles of SUB32_IMM (opcode 0x14) and SUB64_IMM (opcode 0x17) must be swapped: Until now the resulting difference was src - imm and it must be changed to imm - src.

Impact

The toolchain will emit machine-code according to the selected SBPF version. Big integer arithmetics and signed divisions will become cheaper CU wise.

Security Considerations

None.

Evidence graph

Related proposals and rollout

One or more sources are unavailable.

Upstream review record

Upstream discussion & review

GitHub review is editorial context, not evidence of on-chain support, voting, or outcome.

PR #174 · merged SIMD-0174: SBPF arithmetics improvements 8 comments and reviews · Jan 19, 2026
@LucasSte

I think these instruction opcodes is a bit of a departure from the pattern we had until now. In BPF, opcode for 32-bit and 64-bit instructions differs in the least significant bits: mul64 dest, reg is 0x2F and mul32 dest, reg is 0x2C. For these new instructions, we change the most significant bits. Maintaining the same pattern simplifies code generation.

GitHub ↗
@LucasSte

Why is it important to error out for this case? We don't error for any other overflows (add, mul, and sub).

GitHub ↗
@Lichtso

Yes, but that bit is part of the instruction class. Meaning the 32 bit ALU instruction class and the 64 bit ALU instruction class are two different instruction classes. And this SIMD introduces a new instruction class for PQR because they don't fit into the ALU classes (not enough free opcodes).

GitHub ↗
@Lichtso

Because some machine code ISAs (such as x86) throw exceptions (divide error) in that case: https://www.felixcloutier.com/x86/idiv

GitHub ↗
@topointon-jump

Let's specify which SBPF version this will be released in.

GitHub ↗
@0x0ece

SDIV64IMM and SREM64IMM are exceptions. IMM is 32-bit, so it can't be 64-bit -1. I think it'd be better to remove the check for these.

GitHub ↗
@Lichtso

There is sign extension of the inputs (not the outputs). Thus the name "signed division".

GitHub ↗
@0x0ece

Just an impl note for UHMUL64IMM: imm is sign extended to 64-bits. Practically speaking, this means that to do 64x64=128 bit umul one should use UHMUL64REG.

GitHub ↗

simd.watch community discussion · SIMD-0174

Powered by Giscus · Sign in with GitHub to comment

Community comments load when this section approaches the viewport.

Provenance

Evidence & technical details

Rollout or chain data, source revisions, freshness and integrity.
1

SIMD

Deployment Status

Document lifecycleReview
CategoryCore protocol
Devnetactive Epoch 918
Testnetactive Epoch 814
Mainnet-Betaactive Epoch 825
F6UVKh1ujTEFK3en2SyAL3cdVnqko1FVEXWhmdLRu6WP

Exact source revision

Sources & integrity

  • Proposal document pinned_commit_blob
    0616093b2952ed6de52c4a27d66aadd11d48d4f9
  • simd-document document · current · Sep 11, 2026
    0616093b2952ed6de52c4a27d66aadd11d48d4f9

One or more sources are unavailable.