|
| 1 | +--- |
| 2 | +simd: '0174' |
| 3 | +title: SBPF arithmetics improvements |
| 4 | +authors: |
| 5 | + - Alexander Meißner |
| 6 | +category: Standard |
| 7 | +type: Core |
| 8 | +status: Draft |
| 9 | +created: 2024-09-06 |
| 10 | +feature: TBD |
| 11 | +extends: SIMD-0161 |
| 12 | +--- |
| 13 | + |
| 14 | +## Summary |
| 15 | + |
| 16 | +This proposal introduces wide multiplication, signed division and explicit sign |
| 17 | +extension to SBPF. |
| 18 | + |
| 19 | +## Motivation |
| 20 | + |
| 21 | +All major hardware ISAs support 64 x 64 = 128 bit multiplication; BPF does not. |
| 22 | +This hurts performance of big integer arithmetics. Similarly, signed division |
| 23 | +and signed remainder / mudolo instructions must be emulated in software as |
| 24 | +well. |
| 25 | + |
| 26 | +Another issue related to arithemtics is that some 32 bit instructions perform |
| 27 | +sign extension of their results (output, **not** input, there is a difference) |
| 28 | +implicitly. This is first of all useless because source languages do not read |
| 29 | +the 32 MSBs of a 32 bit result stored in a 64 bit register. And second, it |
| 30 | +requires interpreters and compilers to perform extra work to add sign extension |
| 31 | +at the end of these instructions. Instead we should go the same route as the |
| 32 | +underlying hardware ISAs and require sign extension to be made explicit in a |
| 33 | +dedicated instruction. |
| 34 | + |
| 35 | +Furthermore, the instruction `sub dst, imm` is redundant as it can also be |
| 36 | +encoded as `add dst, -imm`. If we were to swap the operands meaning of minuend |
| 37 | +and subtrahend, then the instruction would become usefull and would even render |
| 38 | +`neg dst` redundant. Negation would then be encoded as `reg = 0 - reg`. This |
| 39 | +would also make it clear how sign extension rules work for negation. |
| 40 | + |
| 41 | +## Alternatives Considered |
| 42 | + |
| 43 | +None. |
| 44 | + |
| 45 | +## New Terminology |
| 46 | + |
| 47 | +None. |
| 48 | + |
| 49 | +## Detailed Design |
| 50 | + |
| 51 | +The following must go into effect if and only if a program indicates the |
| 52 | +SBPF-version (TBD) or higher in its program header (see SIMD-0161). |
| 53 | + |
| 54 | +### Changes to the Machinecode Verifier |
| 55 | + |
| 56 | +A program containing one of the following instructions must throw |
| 57 | +`VerifierError::UnknownOpCode` during verification: |
| 58 | + |
| 59 | +- the `MUL` instruction (opcodes `0x24`, `0x2C`, `0x27` and `0x2F`) |
| 60 | +- the `DIV` instruction (opcodes `0x34`, `0x3C`, `0x37` and `0x3F`) |
| 61 | +- the `MOD` instruction (opcodes `0x94`, `0x9C`, `0x97` and `0x9F`) |
| 62 | +- the `NEG` instruction (opcodes `0x84` and `0x87`) |
| 63 | + |
| 64 | +A program containing one of the following instructions must **not** throw |
| 65 | +`VerifierError::UnknownOpCode` during verification anymore (opcodes are for |
| 66 | +immediate and register variant each, in that order): |
| 67 | + |
| 68 | +- the `UHMUL64` instruction (opcode `0x36` and `0x3E`) |
| 69 | +- the `UDIV32` instruction (opcode `0x46` and `0x4E`) |
| 70 | +- the `UDIV64` instruction (opcode `0x56` and `0x5E`) |
| 71 | +- the `UREM32` instruction (opcode `0x66` and `0x6E`) |
| 72 | +- the `UREM64` instruction (opcode `0x76` and `0x7E`) |
| 73 | +- the `LMUL32` instruction (opcode `0x86` and `0x8E`) |
| 74 | +- the `LMUL64` instruction (opcode `0x96` and `0x9E`) |
| 75 | +- the `SHMUL64` instruction (opcode `0xB6` and `0xBE`) |
| 76 | +- the `SDIV32` instruction (opcode `0xC6` and `0xCE`) |
| 77 | +- the `SDIV64` instruction (opcode `0xD6` and `0xDE`) |
| 78 | +- the `SREM32` instruction (opcode `0xE6` and `0xEE`) |
| 79 | +- the `SREM64` instruction (opcode `0xF6` and `0xFE`) |
| 80 | + |
| 81 | +The verification rule, that an immediate divisor must not be zero or else |
| 82 | +`VerifierError::DivisionByZero` is thrown, is moved to the new division like |
| 83 | +instructions: `UDIV32_IMM`, `UDIV64_IMM`, `UREM32_IMM`, `UREM64_IMM`, |
| 84 | +`SDIV32_IMM`, `SDIV64_IMM`, `SREM32_IMM`, `SREM64_IMM`. |
| 85 | + |
| 86 | +### Changes to Execution |
| 87 | + |
| 88 | +#### PQR Instruction Class |
| 89 | + |
| 90 | +A new instruction class product, quotient and remainder (PQR) is introduced: |
| 91 | + |
| 92 | +- the `UHMUL64` instruction (opcode `0x36` and `0x3E`) produces the 64 MSBs of |
| 93 | +the product of an unsigned 64 x 64 bit multiplication (`dst * imm` and |
| 94 | +`dst * src`). |
| 95 | +- the `UDIV32` instruction (opcode `0x46` and `0x4E`) produces the quotient of |
| 96 | +an unsigned 32 bit division (`dst / imm` and `dst / src`). |
| 97 | +- the `UDIV64` instruction (opcode `0x56` and `0x5E`) produces the quotient of |
| 98 | +an unsigned 64 bit division (`dst / imm` and `dst / src`). |
| 99 | +- the `UREM32` instruction (opcode `0x66` and `0x6E`) produces the remainder of |
| 100 | +an unsigned 64 bit division (`dst % imm` and `dst % src`). |
| 101 | +- the `UREM64` instruction (opcode `0x76` and `0x7E`) produces the remainder of |
| 102 | +an unsigned 64 bit division (`dst % imm` and `dst % src`). |
| 103 | +- the `LMUL32` instruction (opcode `0x86` and `0x8E`) produces the 32 LSBs of |
| 104 | +the product of any 32 x 32 bit multiplication (`dst * imm` and `dst * src`). |
| 105 | +- the `LMUL64` instruction (opcode `0x96` and `0x9E`) produces the 64 LSBs of |
| 106 | +the product of any 64 x 64 bit multiplication (`dst * imm` and `dst * src`). |
| 107 | +- the `SHMUL64` instruction (opcode `0xB6` and `0xBE`) produces the 64 MSBs of |
| 108 | +the product of a signed 64 x 64 bit multiplication (`dst * imm` and |
| 109 | +`dst * src`). |
| 110 | +- the `SDIV32` instruction (opcode `0xC6` and `0xCE`) produces the quotient of |
| 111 | +a signed 32 bit division (`dst / imm` and `dst / src`). |
| 112 | +- the `SDIV64` instruction (opcode `0xD6` and `0xDE`) produces the quotient of |
| 113 | +a signed 64 bit division (`dst / imm` and `dst / src`). |
| 114 | +- the `SREM32` instruction (opcode `0xE6` and `0xEE`) produces the remainder of |
| 115 | +a signed 32 bit division (`dst / imm` and `dst / src`). |
| 116 | +- the `SREM64` instruction (opcode `0xF6` and `0xFE`) produces the remainder of |
| 117 | +a signed 64 bit division (`dst / imm` and `dst / src`). |
| 118 | + |
| 119 | +Runtime exceptions are: |
| 120 | + |
| 121 | +- If the divisor (`imm` or `src`) of any division is zero, |
| 122 | +`EbpfError::DivideByZero` must be thrown. |
| 123 | +- If the dividend (`dst`) of a signed division has the minimal value for its |
| 124 | +bitwidth and the divisor (`imm` or `src`) is `-1`, then |
| 125 | +`EbpfError::DivideOverflow` must be thrown. |
| 126 | + |
| 127 | +#### Explicit Sign Extension |
| 128 | + |
| 129 | +The following instructions must stop performing implicit sign extension of |
| 130 | +their results, instead filling the 32 MSBs of `dst` with zeros: |
| 131 | + |
| 132 | +- the `ADD32` instruction (opcode `0x04` and `0x0C`) |
| 133 | +- the `SUB32` instruction (opcode `0x14` and `0x1C`) |
| 134 | +- all of the new 32 bit PQR instructions: `UDIV32`, `UREM32`, `SDIV32`, |
| 135 | +`SREM32` and `LMUL32` |
| 136 | + |
| 137 | +Instead the `MOV32_REG` instruction (opcode `0xBC`) which until now did zero |
| 138 | +out the 32 MSBs, must now perform sign extension in the 32 MSBs. Meaning this |
| 139 | +instruction becomes the explicit sign extension operation. |
| 140 | + |
| 141 | +#### Register Immediate Subtraction |
| 142 | + |
| 143 | +The operands roles of `SUB32_IMM` (opcode `0x14`) and `SUB64_IMM` (opcode |
| 144 | +`0x17`) must be swapped: Until now the resulting difference was `src - imm` and |
| 145 | +it must be changed to `imm - src`. |
| 146 | + |
| 147 | +## Impact |
| 148 | + |
| 149 | +The toolchain will emit machinecode according to the selected SBPF version. |
| 150 | +Big integer arithmetics and signed divisions will become cheaper CU wise. |
| 151 | + |
| 152 | +## Security Considerations |
| 153 | + |
| 154 | +None. |
0 commit comments