08 06 operations on fixed width bit types unsigned integers
This section discusses all operations that can be performed on
expressions of type bit<W> for some width W, also known as
bit-strings.
Arithmetic operations “wrap around”, similar to C operations on unsigned values (i.e., representing a large value on W bits will only keep the least-significant W bits of the value). In particular, P4 does not have arithmetic exceptions—the result of an arithmetic operation is defined for all possible inputs.
P4 target architectures may optionally support saturating arithmetic.
All saturating operations are limited to a fixed range between a minimum
and maximum value. Saturating arithmetic has advantages, in particular
when used as counters. The result of a saturating counter max-ing out is
much closer to the real result than a counter that overflows and wraps
around. According to Wikipedia Saturating
Arithmetic
saturating arithmetic is as numerically close to the true answer as
possible; for 8-bit binary signed arithmetic, when the correct answer is
130, it is considerably less surprising to get an answer of 127 from
saturating arithmetic than to get an answer of −126 from modular
arithmetic. Likewise, for 8-bit binary unsigned arithmetic, when the
correct answer is 258, it is less surprising to get an answer of 255
from saturating arithmetic than to get an answer of 2 from modular
arithmetic. At this time, P4 defines saturating operations only for
addition and subtraction. For an unsigned integer with bit-width of W,
the minimum value is 0 and the maximum value is 2^W-1. The
precedence of saturating addition and subtraction operations is the same
as for modular arithmetic addition and subtraction.
All binary operations except shifts and concatenation require both operands to have the same exact type and width; supplying operands with different widths produces an error at compile time. No implicit casts are inserted by the compiler to equalize the widths. There are no other binary operations that accept signed and unsigned values simultaneously besides shifts and concatenation. The following operations are provided on bit-string expressions:
- Test for equality between bit-strings of the same width, designated
by
==. The result is a Boolean value. - Test for inequality between bit-strings of the same width,
designated by
!=. The result is a Boolean value. - Unsigned comparisons
<,>,<=,>=. Both operands must have the same width and the result is a Boolean value.
Each of the following operations produces a bit-string result when applied to bit-strings of the same width:
- Negation, denoted by unary
-. The result is computed by subtracting the value from 2W. The result is unsigned and has the same width as the input. The semantics is the same as the C negation of unsigned numbers. - Unary plus, denoted by
+. This operation behaves like a no-op. - Addition, denoted by
+. This operation is associative. The result is computed by truncating the result of the addition to the width of the output (similar to C). - Subtraction, denoted by
-. The result is unsigned, and has the same type as the operands. It is computed by adding the negation of the second operand (similar to C). - Multiplication, denoted by
*. The result has the same width as the operands and is computed by truncating the result to the output’s width. P4 architectures may impose additional restrictions — e.g., they may only allow multiplication by a non-negative integer power of two. - Bitwise “and” between two bit-strings of the same width, denoted by
&. - Bitwise “or” between two bit-strings of the same width, denoted by
|. - Bitwise “complement” of a single bit-string, denoted by
~. - Bitwise “xor” of two bit-strings of the same width, denoted by
^. - Saturating addition, denoted by
|+|. - Saturating subtraction, denoted by
|-|.
Bit-strings also support the following operations:
- Logical shift left and right by a non-negative integer value (which
need not be a compile-time known value), denoted by
<<and>>respectively. In a shift, the left operand is unsigned, and right operand must be either an expression of typebit<S>or a non-negative integer value that is known at compile time. The result has the same type as the left operand. Shifting by an amount greater than or equal to the width of the input produces a result where all bits are zero. - Extraction of a set of contiguous bits, also known as a slice,
denoted by
[H:L], whereHandLmust be expressions that evaluate to non-negative, local compile-time known values, andH >= L. The types ofHandL(which do not need to be identical) must be numeric (Section Numeric types). The result is a bit-string of widthH - L + 1, including the bits numbered fromL(which becomes the least significant bit of the result) toH(the most significant bit of the result) from the source operand. The conditions0 <= L <= H < Ware checked statically (whereWis the length of the source bit-string). Note that both endpoints of the extraction are inclusive. The bounds are required to be local compile-time known values so that the width of the result can be computed at compile time. Slices are also l-values, which means that P4 supports assigning to a slice:e[H:L] = x. The effect of this statement is to set bitsHthroughL(inclusive of both) ofeto the bit-pattern represented byx, and leaves all other bits ofeunchanged. A slice of an unsigned integer is an unsigned integer. - Concatenation of bit-strings and/or fixed-width signed integers,
denoted by
++. The two operands must be eitherbit<W>orint<W>, and they can be of different signedness and width. The result has the same signedness as the left operand and the width equal to the sum of the two operands’ width. In concatenation, the left operand is placed as the most significant bits.
Additionally, the size of a bit-string can be determined at compile-time (Section Compile-time size determination).