Expressions
<expr> ::=
| <int> // Integer constant.
| <bool> // Boolean constant.
| <var> // Variable.
| (<wsize>)[<var> + <expr>] // Memory access.
| (<wsize>)[<var> - <expr>] // Memory access.
| <var>[<expr>] // Array access.
| <var>[<wsize> <expr>] // Array access.
| <var>.[<wsize> <expr>] // Unscaled array access.
| <var>[<wsize> <expr> : <expr>] // Subarray.
| <var>.[<wsize> <expr> : <expr>] // Unscaled subarray.
| <op1> <expr> // Unary operation.
| <expr> <op2> <expr> // Binary operation.
| <expr> ? <expr> : <expr> // Conditional.
| (<int><sign><int>)[<expr>, ..., <expr>] // Packing.
| (<expr>)
At source level, Jasmin program contain expressions whose concrete syntax is described below.
Expressions are made of:
constants (
true
,false
,42
,0xabcd
);packs (
(4u2)[0, 3, 2, 1]
);variables (
x
);parenthesized subexpressions (
(e)
);memory loads (
(u16)[p + 2 * i]
);array accesses (
x[i]
);unary operators (
- e
);binary operators (
e - f
);conditional expressions (
c ? th : el
);function calls (
f(x, y)
);primitive instructions (
#copy_32(t)
).
Unary operators
<op1> ::=
| ! // Boolean and bitwise negation.
| - // Arithmetic negation.
| (<cast>) // Cast.
<cast> ::=
| <wsize_size><sign>
| int
Unary operators are, by decreasing precedence:
zero- or sign-extension (
(16s)e
);boolean / bitwise negation (
! b
);opposite (
- e
).
Binary operators
<op2> ::=
| + // Addition.
| - // Subtraction.
| * // Multiplication.
| / // Integer division.
| % // Modulo.
| & // Bitwise AND.
| | // Bitwise OR.
| ^ // Bitwise XOR (exclusive OR).
| == // Equality test.
| != // Inequality test.
| < // Unsgined less than test.
| <s // Signed less than test.
| > // Unsigned greater than test.
| >s // Signed greater than test.
| <= // Unsigned less than or equal test.
| <=s // Signed less than or equal test.
| >= // Unsigned greater than or equal test.
| >=s // Signed greater than or equal test.
| << // Left shift.
| >> // Right shift.
| >>s // Arithmetic right shift.
| <<r // Left rotation.
| >>r // Right rotation.
| && // Boolean AND.
| || // Boolean OR.
+
: Addition.<<
: Left shift.>>
: Right shift.>>s
: Arithmetic right shift. In ARM-M4, an arithmetic right shift by 0 is compiled to aMOV
.<<r
: Left rotation.>>r
: Right rotation. In ARM-M4, a right rotation by 0 is compiled to aMOV
.
Binary operators are, by decreasing precedence:
multiplication (
x * y
), integer division (x / y
), and remainder (x % y
);addition (
x + y
) and subtraction (x - y
);shifts (
x << y
;x >>s y
) and rotations (x <<r y
;x >>r y
);bitwise and (
x & y
);bitwise exclusive or (
x ^ y
);bitwise or (
x | y
);comparisons (
x < y
;x >= y
);equality test (
x == y
;x != y
);boolean conjunction (
b && c
);boolean disjunction (
b || c
).
Note that most operators accept as suffix a size annotation. For instance +32u
is the 32-bit (unsigned) addition and +8u16
is the parallel 16-bit (unsigned) addition for vectors of 8 elements (i.e., 128 bit). Said annotation can be limited to a sign annotation, for instance >>u
is the logical right shift whereas >>s
is the arithmetic right shift.
Array access
For an array
stack u64[10] x;
x[i]
accesses the i-th element of the array (the first index is 0).
Other indexing syntaxes are available, since Jasmin arrays of any type are
fundamentally byte arrays.
Therefore, accesses with a different type than the declared type of the array
are possible, such as x[u16 i]
which views x
as a length 40 array of u16
and accesses the i-th element.
Further, non-scaled array accesses are also possible:
x.[u16 1]
returns the u16
composed of the second and third bytes of the array.
The explicit type can also be left out x.[i]
is equivalent to x.[u64 i]
.
Note: Jasmin semantics specifies the conversion between bytes and words as little-endian.
Subarrays
To facilitate array handling, subarray notation was introduced. Consider the following example,
a[i:N] = add_array(a[i:N], b[j:N]);
with,
inline fn add_array(stack u64[N] a b) -> stack u64[N] {
inline int i;
for i = 0 to N {
reg u64 ai bi;
ai = a[i];
bi = b[i];
ai += bi;
a[i] = ai;
}
return a;
}
Subarrays consists on two elements:
index: where the access starts
length: amount of elements to access (must be a constant
int
).
Similarly to array indexing, non-scaled subarrays and subarrays with
type-casting are supported: a.[i:N]
, a[u16 i:N]
, a.[u16 i:N]
.
Memory accesses
Suppose a register reg u64
whose value is a memory address.
Then, for loading values from memory the notation is as follows:
reg u64 var;
var = [ptr + offset];
// or for better understanding
var = (64u)[ptr + offset];
offset
is measured in bytes.