In Nanojit, LIR is the source language for compilation to machine code. LIR stands for low-level intermediate representation.
The LIR instruction set
Types in LIR. Values in LIR have a type: either 32-bit or 64-bit. A 32-bit value, additionally, may be a condition or not. Each instruction requires operands of a specific type and produces a result of a specific type.
LIR makes no distinction at all between pointers and integers of the same size, between signed and unsigned integer values, or between 64-bit floating-point and 64-bit integer values. It is acceptable to load a 64-bit value from memory using
ldq and then use the result with a floating-point arithmetic operation such as
The names of the operands and results below indicate the types required by LIR. Names starting with i indicate 32-bit values. Results starting with b are 32-bit integers and additionally are conditions. Operand names starting with b must be conditions. Names starting with q or f indicate 64-bit values. (f and q indicate the same type as far as LIR is concerned, but f is used here for floating-point operations.) Operand names starting with p must be pointer-sized integers. That is, they must be 64 bits on a 64-bit platform and 32 bits otherwise.
Operations that are weird but don't count as special
Allocate stack space, as though with the C standard library function
Extend live range of reference.
Loads and stores
st p1[offset] = i2
stq p1[offset] = q2
sti p1[offset] = i2
stqi p1[offset] = q2
32-bit load. This instruction is never removed by common subexpression elimination.
i = ld p1[p2]
64-bit load. This instruction is never removed by common subexpression elimination.
q = ldq p1[offset]
8-bit load. This instruction may be removed by common subexpression elimination.
i = ldcb p1[offset]
16-bit load. This instruction may be removed by common subexpression elimination.
i = ldcs p1[offset]
32-bit load. This instruction may be removed by common subexpression elimination.
i = ldc p1[offset]
64-bit load. This instruction may be removed by common subexpression elimination.
q = ldqc p1[offset]
Indirect subroutine call returning a 32-bit integer value.
Subroutine call returning a 32-bit integer value.
Indirect subroutine call returning a 64-bit value.
Subroutine call returning a 64-bit value.
Exit if true.
Exit if false.
Do not exit but emit writes to flush all values to the stack.
Jump if true.
Jump if false.
A jump target.
32-bit integer equality test.
result = eq i1, i2
There is no not-equal instruction. Instead, flip the instruction that uses the result, or add a
Signed 32-bit integer less-than test.
b = lt i1, i2
Signed 32-bit integer greater-than test.
b = gt i1, i2
Signed 32-bit integer less-than-or-equals test.
b = le i1, i2
Signed 32-bit integer greater-than-or-equals test.
b = ge i1, i2
Unsigned 32-bit integer less-than test.
b = ult i1, i2
Unsigned 32-bit integer greater-than test.
b = ugt i1, i2
Unsigned 32-bit integer less-than-or-equals test.
b = ule i1, i2
Unsigned 32-bit integer greater-than-or-equals test.
b = uge i1, i2
Floating-point equality test.
b = feq f1, f2
Floating-point less-than test.
b = flt f1, f2
Floating-point greater-than test.
b = fgt f1, f2
Floating-point less-than-or-equals test.
b = fle f1, f2
Floating-point greater-than-or-equals test.
b = fge f1, f2
Note: These instructions are currently rendered in
VerboseWriter output as lines containing only the symbolic name of the immediate value being loaded. The instruction name and numeric value are not displayed for
int instructions. This is arguably a bug.
An immediate 32-bit integer that fits in a signed 16-bit integer.
i = short <number>
<number> must be an integer that fits in the range of a signed 16-bit integer (-32768 to 32767). The result of a
short instruction is a 32-bit integer with the same value (sign-extended).
An immediate 32-bit integer.
i = int <number>
An immediate 64-bit value.
q = quad <number>
Note: These two instructions can be written using the idiom
lirwriter->ins2(LIR_cmov, b1, lirwriter->ins2(LIR_2, i2, i3)). The
LIR_2 instruction serves only to group the second and third operands, since
LirWriter has no
LirWriter::ins_choose() convenience method can be used instead. It uses the above idiom.
Choice of two 32-bit values.
i = cmov b1, i2, i3
Choice of two 64-bit values.
Note: This instruction currently does not work on 32-bit Intel platforms.
q = qcmov b1, q2, q3
32-bit integer negation.
i = neg i1
32-bit integer addition.
i = add i1, i2
64-bit integer addition.
q = qiadd q1, q2
32-bit integer subtraction.
i = sub i1, i2
32-bit integer multiplication.
i = mul i1, i2
32-bit bitwise AND.
i = and i1, i2
64-bit bitwise AND.
q = qiand q1, q2
32-bit bitwise OR.
i = or i1, i2
64-bit bitwise OR.
q = qior q1, q2
32-bit bitwise XOR.
i = or i1, i2
32-bit bitwise NOT.
i = not i1
32-bit left shift.
i = lsh i1, i2
64-bit left shift.
q = qilsh q1, q2
32-bit right shift with sign extend.
i = rsh i1, i2
The two most significant bits of the result value are the same.
32-bit unsigned right shift.
i = ush i1, i2
The most significant bit of the result value is 0.
Test for overflow.
b = ov i1
On Intel, this reads the overflow condition flag. Other platforms have to emulate this behavior.
The result is
i1 is the result of an
add that changed the value of the most significant bit, for example.
Test for carry.
b = cs i1
On Intel, this reads the carry condition flag. Other platforms have to emulate this behavior.
The result is
i1 is the result of an
add that overflowed the range of an unsigned 32-bit integer, for example.
result = fneg f1
result = fadd f1, f2
result = fsub f1, f2
result = mul f1, f2
f = div f1, f2
Get the low 32 bits of a 64-bit value.
i = qlo q
Get the high 32 bits of a 64-bit value.
i = qhi q
Join two 32-bit values to form a 64-bit value.
q = qjoin i1, i2
Convert signed 32-bit integer to floating-point number.
f = i2f i1
Convert unsigned 32-bit integer to floating-point number.
f = u2f i1