Numeric Operations
Arithmetic, comparison, bitwise, and conversion primitives for Bool, integer, floating-point, and imaginary types.
Binary numeric primitives require operands of matching types. Heterogeneous-type conversion is left to the library. Complex math is also library-provided. None of these primitives may be overloaded.
boolNot
boolNot(x:Bool) : Bool;
Returns the complement of x. Equivalent to the not operator.
numericEquals?
[T | Numeric?(T)]
numericEquals?(a:T, b:T) : Bool;
Numeric equality.
- Integer: LLVM
icmp eq. - Floating-point: LLVM
fcmp ueq(IEEE 754 unordered).+0.0 == -0.0. Any comparison with NaN is false.
numericLesser?
[T | Numeric?(T)]
numericLesser?(a:T, b:T) : Bool;
true if a < b.
- Signed integer: LLVM
icmp slt. - Unsigned integer: LLVM
icmp ult. - Floating-point: LLVM
fcmp ult(IEEE 754 unordered).-0.0 < +0.0is false. NaN comparisons are false.
__primitives__ does not expose the full set of FP comparisons. The library implements ordered and unordered FP comparison via inline LLVM. These primitives are only used during compile-time evaluation, which cannot run inline LLVM.
numericAdd / numericSubtract / numericMultiply
[T | Numeric?(T)]
numericAdd(a:T, b:T) : T;
numericSubtract(a:T, b:T) : T;
numericMultiply(a:T, b:T) : T;
Standard arithmetic. Integer overflow wraps (two's-complement). Integer ops lower to add, sub, mul. Floating-point ops lower to fadd, fsub, fmul.
numericDivide
[T | Numeric?(T)]
numericDivide(a:T, b:T) : T;
Integer division truncates toward zero. Integer division by zero is undefined, as is signed overflow (e.g. -0x8000_0000 / -1). Floating-point division follows IEEE 754.
- Signed:
sdiv. Unsigned:udiv. Floating-point:fdiv.
numericNegate
[T | Numeric?(T)]
numericNegate(a:T) : T;
Negation.
- Integer: behaves as two's-complement subtraction from zero (LLVM
sub 0, %a). Unsigned negation gives the two's complement. Signed overflow (negating-0x8000_0000) gives the original value. - Floating-point: LLVM
fsub -0.0, %a. Negating a zero yields the other zero. Negating a NaN yields an unspecified other NaN.
integerRemainder
[T | Integer?(T)]
integerRemainder(a:T, b:T) : T;
Remainder of a / b. For signed types, a nonzero remainder takes the sign of a. Division by zero and signed overflow are undefined (LLVM defines the remainder of overflowing division as undefined as well).
- Signed:
srem. Unsigned:urem.
integerShiftLeft / integerShiftRight
[T | Integer?(T)]
integerShiftLeft(a:T, b:T) : T;
integerShiftRight(a:T, b:T) : T;
Shift a by b bits. Undefined if b is negative or >= bitwidth(T).
integerShiftLeft→ LLVMshl. Overflowed bits discarded.integerShiftRight→ arithmetic shift (ashr) for signed types, logical (lshr) for unsigned.
integerBitwiseAnd / Or / Xor
[T | Integer?(T)]
integerBitwiseAnd(a:T, b:T) : T;
integerBitwiseOr(a:T, b:T) : T;
integerBitwiseXor(a:T, b:T) : T;
Bitwise AND, OR, XOR. Lower to LLVM and, or, xor.
integerBitwiseNot
[T | Integer?(T)]
integerBitwiseNot(a:T) : T;
Bitwise complement. Lowers to LLVM xor %T %a, -1.
numericConvert
[T, U | Numeric?(T) and Numeric?(U)]
numericConvert(static T, a:U) : T;
Converts a to type T while preserving its numeric value. If T == U, the value is copied. Otherwise, the conversion depends on the kinds of T and U:
Integer → Integer
| Direction | LLVM |
|---|---|
| Narrowing | trunc (bitwise truncation) |
| Widening to signed | sext (sign-extend) |
| Widening to unsigned | zext (zero-extend) |
| Same width, sign change | bitcast |
Float → Float
- Narrowing:
fptrunc. Overflowing truncation is undefined. - Widening:
fpext.
Integer → Float
- Signed:
sitofp. Unsigned:uitofp. - Overflowing conversion is undefined.
Float → Integer
- Signed:
fptosi. Unsigned:fptoui. - Overflowing conversion is undefined.
Checked Integer Operations
Variants of the integer primitives that also return a Bool overflow flag. On overflow, the numeric result is undefined and the flag is true. Otherwise the result matches the unchecked version and the flag is false. None may be overloaded.
[T | Integer?(T)]
integerAddChecked(a:T, b:T) : T, Bool;
integerSubtractChecked(a:T, b:T) : T, Bool;
integerMultiplyChecked(a:T, b:T) : T, Bool;
integerDivideChecked(a:T, b:T) : T, Bool;
integerNegateChecked(a:T) : T, Bool;
integerRemainderChecked(a:T, b:T): T, Bool;
integerShiftLeftChecked(a:T, b:T): T, Bool;
[T, U | Integer?(T) and Integer?(U)]
integerConvertChecked(static T, a:U) : T, Bool;