Skip to content

Commit

Permalink
First draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Sep 6, 2024
1 parent 4b1eaaf commit 42ba0ff
Showing 1 changed file with 154 additions and 0 deletions.
154 changes: 154 additions & 0 deletions proposals/0174-sbpf-arithmetics-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
simd: '0174'
title: SBPF arithmetics improvements
authors:
- Alexander Meißner
category: Standard
type: Core
status: Draft
created: 2024-09-06
feature: TBD
extends: SIMD-0161
---

## 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 (TBD) 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.

0 comments on commit 42ba0ff

Please sign in to comment.