Kinx has a JIT Compiler Library to use JIT easily.
JIT Library is not an embedded library, so you should load it by using
.
using Jit;
Jit object has methods for Jit parameters and Compiler
class.
As a Jit parameter, there are immediate values, registers, and a memory access. It can be used as the way below.
As for an immediate value and a memory access, the following methods are prepared.
Jit.VAR()
is a special method to use a local variable area. This method will prepare the local variable on the stack and use it.
Method | Remark |
---|---|
Jit.IMM(v) |
64-bit Integer, or floating point number. The type which will be selected is determined with the destination register of assignment. |
Jit.VAR(n) |
This means a local variable. The area on the stack is automatically allocated. The variable is always 8 bytes. |
Jit.MEM1(r1, offset) |
This means a memory address which is the address pointed by r1 register and offset. |
Jit.MEM2(r1, r2, shift) |
This means r1 + r2 * (bytes by shift) and (bytes by shift) means 1 byte when the shift is 0, 2 bytes when the shift is 1, 4 bytes when the shift is 2, or 8 bytes when the shift is 3. |
The following registers are available. The number of available registers in a function will be automatically calculated for each function.
Registers | Meaning |
---|---|
Jit.R0 .. Jit.R5 |
General Purpose Register. It may be destroyed after calling a function. |
Jit.S0 .. Jit.S5 |
General Purpose Register. It is saved and can be used also after calling a function. |
Jit.FR0 .. Jit.FR5 |
Floating Point Register. It may be destroyed after calling a function. |
Jit.FS0 .. Jit.FS5 |
Floating Point Register. It is saved and can be used also after calling a function. |
By the way, note that a Floating Point Register can be used until max 6 registers for both FR
and FS
, that is why only FS0
is available when you use FR5
.
See below for this.
FR* Register |
FS* Register |
---|---|
(Can not be used) | FS0 , FS1 , FS2 , FS3 , FS4 , FS5 |
FR0 |
FS0 , FS1 , FS2 , FS3 , FS4 |
FR0 , FR1 |
FS0 , FS1 , FS2 , FS3 |
FR0 , FR1 , FR2 |
FS0 , FS1 , FS2 |
FR0 , FR1 , FR2 , FR3 |
FS0 , FS1 |
FR0 , FR1 , FR2 , FR3 , FR4 |
FS0 |
FR0 , FR1 , FR2 , FR3 , FR4 , FR5 |
(Can not be used) |
Jit.Compiler()
will create a Jit Compiler object to generate Jit instructions.
var c = new Jit.Compiler();
Jit Compiler has the following methods.
Jit Compiler Methods | Return Value | Outline |
---|---|---|
Jit.Compiler#label() |
label | Adds a label to a current location. |
Jit.Compiler#makeConst(reg, init) |
ConstTarget | Returns a temporary code to set an immediate value after generating the Jit code. |
Jit.Compiler#localp(dst, offset) |
Generates the code to get an address of a local variable. The address will be set to the register of dst . offset means an index of a local variable. |
|
Jit.Compiler#enter(argType) |
label | Generates an entry point of a function. You can specify the argument type, but it can be also omitted. |
Jit.Compiler#fastEnter(reg) |
label | Generates an entry point of a function without prologue and epilogue. reg will hold a return address. |
Jit.Compiler#ret(val) |
Generates a ret code with the return value of val . val will be returned by FR0 register when it is a floating point, otherwise returned by R0 register. |
|
Jit.Compiler#f2i(dst, op1) |
Generates the code to cast from double to int64_t. dst should be a general purpose register and op1 should be a floating point register. |
|
Jit.Compiler#i2f(dst, op1) |
Generates the code to cast from int64_t to double. dst should be a floating point register and op1 should be a general purpose register. |
|
Jit.Compiler#mov(dst, op1) |
Generates the code to assign op1 to dst . It will automatically determine if it is a floating point or not. |
|
Jit.Compiler#neg(dst, op1) |
Generates the code to store a sign inverted op 1 to dst . |
|
Jit.Compiler#clz(dst, op1) |
Generates the code to count the number of bits with 0 from the head of op1 and to store it to dst . |
|
Jit.Compiler#add(dst, op1, op2) |
Generates the code of addition of op1 and op2 and to store it to dst . |
|
Jit.Compiler#sub(dst, op1, op2) |
Generates the code of subtract of op1 and op2 and to store it to dst . |
|
Jit.Compiler#mul(dst, op1, op2) |
Generates the code to multiply op1 by op2 and to store it to dst . |
|
Jit.Compiler#div(dst, op1, op2) |
Only for a floating point number, generates the code to divide op1 and op2 , and store it to dst . |
|
Jit.Compiler#div() |
Generates the code to divide R0 register by R1 register as an unsigned integer, and store a result to R0 register. |
|
Jit.Compiler#sdiv() |
Generates the code to divide R0 register by R1 register as a signed integer, and store a result to R0 register. |
|
Jit.Compiler#divmod() |
Generates the code to divide R0 register by R1 register as an unsigned integer, and store a result to R0 register and to store a reminder to R1 register. |
|
Jit.Compiler#sdivmod() |
Generates the code to divide R0 register by R1 register as a signed integer, and store a result to R0 register and to store a reminder to R1 register. |
|
Jit.Compiler#not(dst, op1) |
Generates the code to store a bitwise inverted op1 to dst . |
|
Jit.Compiler#and(dst, op1, op2) |
Generates the code to store the result of a bitwise AND between op1 and op2 to dst . |
|
Jit.Compiler#or(dst, op1, op2) |
Generates the code to store the result of a bitwise OR between op1 and op2 to dst . |
|
Jit.Compiler#xor(dst, op1, op2) |
Generates the code to store the result of a bitwise XOR between op1 and op2 to dst . |
|
Jit.Compiler#shl(dst, op1, op2) |
Generates the code to store the result shifted op1 by op2 -bits to dst . |
|
Jit.Compiler#lshr(dst, op1, op2) |
Generates the code to store the result of logical-shift of op1 by op2 -bits to dst . |
|
Jit.Compiler#ashr(dst, op1, op2) |
Generates the code to store the result of arithmetic-shift of op1 by op2 -bits to dst . |
|
Jit.Compiler#call(label) |
JumpTarget | Generates the code to call a function defined by enter() . This returns a JumpTarget when label is not specified. |
Jit.Compiler#fastCall(label) |
JumpTarget | Generates the code to call a function defined by fastEnter() . This returns a JumpTarget when label is not specified. |
Jit.Compiler#jmp(label) |
JumpTarget | Generates the code of jmp . Use and set the destination by JumpTarget if you do not specify label . |
Jit.Compiler#ijmp(dst) |
JumpTarget | Generates the code of jmp . dst is an immediate value or a register holding an address. |
Jit.Compiler#eq(op1, op2) |
JumpTarget | Generates the code to check op1 == op2 , and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#neq(op1, op2) |
JumpTarget | Generates the code to check op1 != op2 , and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#lt(op1, op2) |
JumpTarget | Generates the code to check op1 < op2 as an unsigned integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#le(op1, op2) |
JumpTarget | Generates the code to check op1 <= op2 as an unsigned integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#gt(op1, op2) |
JumpTarget | Generates the code to check op1 > op2 as an unsigned integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#ge(op1, op2) |
JumpTarget | Generates the code to check op1 >= op2 as an unsigned integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#slt(op1, op2) |
JumpTarget | Generates the code to check op1 < op2 as a signed integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#sle(op1, op2) |
JumpTarget | Generates the code to check op1 <= op2 as a signed integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#sgt(op1, op2) |
JumpTarget | Generates the code to check op1 > op2 as a signed integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#sge(op1, op2) |
JumpTarget | Generates the code to check op1 >= op2 as a signed integer, and returns JumpTarget used to specify the destination to jump when the result is true. |
Jit.Compiler#generate() |
JitCode | Returns an actual generated code. |
Defines an entry point of a function by enter()
method with argType
like Jit.ArgType.SW_SW_SW
.
The type of argType
is combination of followings and arguments are specified until the max 3 arguments.
SW
... Signed Word (64bit)UW
... Unsigned Word (64bit)FP
... Floating Point (64bit)
If you do not specify the argType
, it means Jit.ArgType.SW_SW_SW
.
But in fact, SW
and UW
is same because its bit sequence is same.
You can omit the type from the tail, so the followings are same meaning.
Jit.ArgType.SW_SW_SW
Jit.ArgType.SW_SW
Jit.ArgType.SW
The registers used as arguments are fixed. See below.
- Caller
Type | 1st argument | 2nd argument | 3rd argument |
---|---|---|---|
Integer | Jit.R0 |
Jit.R1 |
Jit.R2 |
Double | Jit.FR0 |
Jit.FR1 |
Jit.FR2 |
- Callee
Type | 1st argument | 2nd argument | 3rd argument |
---|---|---|---|
Integer | Jit.S0 |
Jit.S1 |
Jit.S2 |
Double | Jit.FS0 |
Jit.FS1 |
Jit.FS2 |
Note that the registers are different between caller and callee.
Label address is set by the method of setLabel()
.
It is used when you want to set the label as an immediate value.
Now it is hard to use this interface so far, so I would like to prepare this as more useful interface.
This object has a setLabel()
method and set the destination to jump, or the destination of a function call.
For example, the following shows a branch.
var c = new Jit.Compiler();
// Entry point
c.enter();
// S0 >= 3
var jump0 = c.ge(Jit.S0, Jit.IMM(3));
... // The code when the condition is false.
var jump1 = c.jmp();
var label0 = c.label();
... // The code when the condition is true.
var label1 = c.label();
...
jump0.setLabel(label0);
jump1.setLabel(label1);
When generating the code is successful, returns a JitCode object. JitCode object has methods below.
メソッド | 概要 |
---|---|
JitCode#run(a1, a2, a3) |
Returns a value as Integer. |
JitCode#frun(a1, a2, a3) |
Returns a value as Double. |
JitCode#dump() |
Output the assemble list to be generated. |
By the way note that you can specify only the max 3 arguments as a specification.
using Jit;
var c = new Jit.Compiler();
var entry1 = c.enter();
var jump0 = c.ge(Jit.S0, Jit.IMM(3));
c.ret(Jit.S0);
var l1 = c.label();
c.sub(Jit.R0, Jit.S0, Jit.IMM(2));
c.call(entry1);
c.mov(Jit.S1, Jit.R0);
c.sub(Jit.R0, Jit.S0, Jit.IMM(1));
c.call(entry1);
c.add(Jit.R0, Jit.R0, Jit.S1);
c.ret(Jit.R0);
jump0.setLabel(l1);
var code = c.generate();
for (var i = 1; i <= 42; ++i) {
var r = code.run(i);
System.println("fib(%2d) = %d" % i % r);
}
fib( 1) = 1
fib( 2) = 2
fib( 3) = 3
fib( 4) = 5
fib( 5) = 8
fib( 6) = 13
fib( 7) = 21
fib( 8) = 34
fib( 9) = 55
fib(10) = 89
fib(11) = 144
fib(12) = 233
fib(13) = 377
fib(14) = 610
fib(15) = 987
fib(16) = 1597
fib(17) = 2584
fib(18) = 4181
fib(19) = 6765
fib(20) = 10946
fib(21) = 17711
fib(22) = 28657
fib(23) = 46368
fib(24) = 75025
fib(25) = 121393
fib(26) = 196418
fib(27) = 317811
fib(28) = 514229
fib(29) = 832040
fib(30) = 1346269
fib(31) = 2178309
fib(32) = 3524578
fib(33) = 5702887
fib(34) = 9227465
fib(35) = 14930352
fib(36) = 24157817
fib(37) = 39088169
fib(38) = 63245986
fib(39) = 102334155
fib(40) = 165580141
fib(41) = 267914296
fib(42) = 433494437
using Jit;
var c = new Jit.Compiler();
var entry1 = c.enter(Jit.ArgType.FP);
c.mov(Jit.FR0, Jit.IMM(0.3));
var jump0 = c.ge(Jit.FS0, Jit.FR0);
c.ret(Jit.FS0);
var l1 = c.label();
c.mov(Jit.FR0, Jit.IMM(0.2));
c.sub(Jit.FR0, Jit.FS0, Jit.FR0);
c.call(entry1);
c.mov(Jit.FS1, Jit.FR0);
c.mov(Jit.FR0, Jit.IMM(0.1));
c.sub(Jit.FR0, Jit.FS0, Jit.FR0);
c.call(entry1);
c.add(Jit.FR0, Jit.FR0, Jit.FS1);
c.ret(Jit.FR0);
jump0.setLabel(l1);
var code = c.generate();
for (var i = 0.1; i < 3.5; i += 0.1) {
var r = code.frun(i);
System.println("fib(%3.1f) = %.1f" % i % r);
}
fib(0.1) = 0.1
fib(0.2) = 0.2
fib(0.3) = 0.3
fib(0.4) = 0.5
fib(0.5) = 0.8
fib(0.6) = 1.3
fib(0.7) = 2.1
fib(0.8) = 3.4
fib(0.9) = 5.5
fib(1.0) = 8.9
fib(1.1) = 14.4
fib(1.2) = 23.3
fib(1.3) = 37.7
fib(1.4) = 61.0
fib(1.5) = 98.7
fib(1.6) = 159.7
fib(1.7) = 258.4
fib(1.8) = 418.1
fib(1.9) = 676.5
fib(2.0) = 1094.6
fib(2.1) = 1771.1
fib(2.2) = 2865.7
fib(2.3) = 4636.8
fib(2.4) = 7502.5
fib(2.5) = 12139.3
fib(2.6) = 19641.8
fib(2.7) = 31781.1
fib(2.8) = 51422.9
fib(2.9) = 83204.0
fib(3.0) = 134626.9
fib(3.1) = 217830.9
fib(3.2) = 352457.8
fib(3.3) = 570288.7
fib(3.4) = 922746.5