# Operators¶

This section describes TPC-C operators and their results:

## TPC-C Type Standards¶

• If the type is not specified, in the case of all scalar operands, the operation the result is evaluated according to the C99 standard.

• Scalar floating types are `float` and `_Bfloat16`.

• Vector floating types are `float64` and `bfloat128`.

• Integer vector types are `char256`, `uchar256`, `short128`, `ushort128`, `int64`, `uint64` and tensor coordinate type `int5`.

## Arithmetic Operators¶

### Binary Operators¶

The arithmetic operators add (+), subtract (-), and multiply (*) operate on built-in integer and floating-point scalar and vector data types. All arithmetic operators return a result of the same built-in type (integer or floating-point) as the type of the operands, after operand type conversion. The following cases are valid after the conversion:

• The two operands are scalars. In this case, the operation is applied, resulting in a scalar.

• One operand is a scalar, and the other is a vector. In this case, the scalar may be subject to the usual arithmetic conversion to the element type used by the vector operand. The scalar type is then widened to a vector that has the same number of components as the vector operand. The operation is done component-wise, resulting in the same size vector.

• The two operands are vectors of the same type. In this case, the operation is done component-wise, resulting in the same size vector.

division (/) and remainder (%) operators are supported by calling a TPC compiler procedure.

### Unary Operators¶

The arithmetic operators (+ and -) operate on built-in scalar and vector types except for bool256. All other cases of implicit conversions are illegal.

The arithmetic post- and pre-increment and decrement operators (– and ++) operate on built-in scalar and integer vector types. All unary operators work component-wise on their operands. These result with the same type they operated on. For post- and pre-increment and decrement, the expression must be one that could be assigned to l-value.

Pre-increment and pre-decrement add or subtract 1 to the contents of the expression they operate on, and the value of the pre-increment or pre-decrement expression is the resulting value of that modification. Post-increment and post-decrement expressions add or subtract 1 to the contents of the expression they operate on, but the resulting expression has the expression’s value before the post-increment or post-decrement was executed.

Note

The pre- and post- increment operators may have an unexpected behavior on floating-point values and are, therefore, not supported for floating-point scalar and vector built-in types.

## Relational Operators¶

• The relational operators are greater than (>), less than (<), greater than or equal (>=), less than or equal (<=).

• Quality operators are equal (==), not equal to(!=) operate only on scalar types and result in an integer type.

The relational operators return 0 if the specified relation is false, and 1 if the specified relation is true. The relational and equality operators always return 0 if either argument is not a number (NaN).

## Bitwise Operators¶

The bitwise operators and (&), or (|), exclusive or (^), not (~) operate on all scalar and vector built-in types except the built-in scalar and vector float types. For vector built-in types, the operators are applied component-wise. If one operand is a scalar and the other is a vector, the scalar may be subject to the usual arithmetic conversion to the element type used by the vector operand. The scalar type is then widened to a vector that has the same number of components as the vector operand.

The operation is done component-wise, resulting in the same size vector.

## Logical Operators¶

### Binary Operators¶

The logical operators and (&&), or (||) operate on all scalar and vector built-in types. For scalar built-in types only, and (&&) only evaluates the right hand operand if the left hand operand compares unequal to 0. For scalar built-in types only, or (||) only evaluates the right hand operand if the left hand operand compares equal to 0. For built-in vector types, both operands are evaluated, and the operators are applied component-wise. If one operand is a scalar and the other is a vector, then the scalar may be subject to the usual arithmetic conversion to the element type used by the vector operand. The scalar type then widens to a vector that has the same number of components as the vector operand. The operation is done component-wise, resulting in the same size vector. The logical operator exclusive or (^^) is reserved.

• The result is a scalar signed integer of type int if the source operands are scalar, and a vector signed integer type of the same size as the source operands if the source operands are vector types. Vector source operands of type char256 and uchar256 return a char256 result; vector source operands of type bfloat128, short128 and ushort128 return a short128 result; vector source operands of type int64, uint64 and float64 return an int64 result.

• For scalar types, the logical operators return 0 if the result of the operation is false, and 1 if the result is true. For vector types, the logical operators are evaluated component-wise return 0 if the result of the operation is false, and –1 (i.e. all bits set) if the result is true.

### Unary Operators¶

The logical unary operator not (!) operates on all scalar and vector built-in types. For built-in vector types, the operators are applied component-wise.

• The result is a scalar signed integer of type int if the source operands are scalar, and a vector signed integer type of the same size as the source operands if the source operands are vector types. Vector source operands of type char256 and uchar256 return a char256 result; vector source operands of type bfloat128, short128 and ushort128 return a short128 result; vector source operands of type int64, uint64 and float64 return an int64 result.

• For scalar types, the result of the logical unary operator is 0 if the value of its operand compares unequal to 0, and 1 if the value of its operand compares equal to 0. For vector types, the unary operator returns a 0 if the value of its operand compares unequal to 0, and -1 (i.e. all bits set) if the value of its operand compares equal to 0.

### Ternary Operators¶

The ternary selection operator (?:) operates on three expressions (exp1 ? exp2 : exp3). This operator evaluates the first expression exp1, which can be a scalar only. The operator selects to evaluate the second expression if the result compares unequal to 0, otherwise it selects to evaluate the third expression. The second and third expressions can be any type, as long their types match, or implicit conversions can be applied to one of the expressions to make their types match, or one is a vector and the other is a scalar and the scalar may be subject to the usual arithmetic conversion to the element type used by the vector operand and widened to the same type as the vector type.

Note

This resulting matching type is the type of the entire expression.

## Right Shift and Left Shift Operators in C/C++¶

The operators right-shift (>>), left-shift (<<) operate on all integer and floating scalar and vector built-in types. For built-in vector types, the operators are applied component-wise. For the right-shift (>>), left-shift (<<) operators, the rightmost operand must be a scalar if the first operand is a scalar, and the rightmost operand can be a uchar256 or scalar if the first operand is a vector.

• The result of E1 << E2 is E1 left-shifted by log 2 (N) least significant bits in E2 viewed as an unsigned integer value, where N is the number of bits used to represent the data type of E1 after integer promotion, if E1 is a scalar, or the number of bits used to represent the type of E1 elements, if E1 is a vector. Zeros fill the vacated bits.

• The result of E1 >> E2 is E1 right-shifted by log 2 (N) least significant bits in E2 viewed as an unsigned integer value, where N is the number of bits used to represent the data type of E1 after integer promotion when E1 is a scalar, or the number of bits used to represent the type of E1 elements when E1 is a vector. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, zeros fill the vacated bits. If E1 has a signed type and a negative value, ones fill the vacated bits.

## sizeof Operator¶

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The type of the operand determins the size.

The result is of type size_t. If the type of the operand is a fixed length array type, the operand is evaluated; otherwise, the operand is not evaluated, and the result is an integer constant.

When applied to an operand that has type `_Bool`, char, uchar, the result is 1. When applied to an operand that has type short, ushort, or _Bfloat16 the result is 2. When applied to an operand that has type int, uint or float, the result is 4. When applied to an operand that is bool256 result is 32. For integer and float vector types, the result is 256 (equal to number of components * size of each scalar component). When applied to an operand that has array type, the result is the total number of bytes in the array.

When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding. The sizeof operator is not applied to an expression that has function type or an incomplete type, or to the parenthesized name of such a type.

## Memory Operands¶

The unary (*) operator denotes indirection. If the operand points to an object, the result is a lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If the pointer is assigned an invalid value, then the behavior of the unary * operator is undefined.

The unary (&) operator returns the address of its operand in local memory (see Address Space Qualifiers). If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated, and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not a lvalue.

Note

If the operand is the result of a [] operator, neither the (&) operator nor the unary (*) that is implied by the [] is evaluated and the result is as if the (&) operator is removed and the [] operator is changed to a (+) operator. Otherwise, the result is a pointer to the object designated by its operand.

## Assignment Operator¶

The assignment operator ( = ) assigns values to variable names, like lvalue = expression.

The assignment operator stores the value of expression into lvalue. The expression and lvalue must have the same type, or the expression must have a type described in Table 1, in which case an implicit conversion is done on the expression before the assignment is done.

If expression is a scalar type and lvalue is a vector type, the scalar is converted to the element type used by the vector operand. The scalar type is then widened to a vector that has the same number of components as the vector operand. The operation is done component-wise resulting in the same size vector.

Any other desired type-conversions must be specified explicitly. L-values must be writable.

Variables that are built-in types, entire structures or arrays, structure fields, l-values with the field selector ( . ) applied to select components or swizzles without repeated fields, l-values within parentheses, and l-values dereferenced with the array subscript operator ( [ ] ) are all l-values. Other binary or unary expressions, function names, swizzles with repeated fields, and constants cannot be l-values. The ternary operator (?:) is also not allowed as an l-value.

The order of evaluation of the operands is unspecified. If an attempt is made to modify the result of an assignment operator or to access it after the next sequence point, then the behavior is undefined. Other assignment operators are the assignments add into (+=), subtract from (-=), multiply into (*=), divide into (/=), modulus into (%=), left shift by (<<=), right shift by (>>=), and into (&=), inclusive or into (|=), and exclusive or into (^=).

Note

`lvalue op= expression` is equivalent to `lvalue = lvalue op expression`. and the l-value and expression must satisfy the requirements for both operator op and assignment (=).

## Comma Operator¶

The comma (,) operator operates on expressions by returning the type and value of the right-most expression in a comma separated list of expressions. All expressions are evaluated, in order, from left to right.