Last active
October 25, 2016 07:22
-
-
Save anael-seghezzi/dd89fc64474393b0feec9c0e0de3cb4d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef __TINYC__ | |
#if _WIN32 | |
// TODO VirtualAlloc, VirtualFree | |
#else | |
// mmap | |
#define PROT_READ 1 | |
#define PROT_WRITE 2 | |
#define PROT_EXEC 4 | |
#define MAP_PRIVATE 0x02 | |
#define MAP_ANON 0x1000 | |
void *mmap(void *, size_t, int, int, int, int64_t); | |
int munmap (void *, size_t); | |
int mprotect(void *, size_t, int); | |
// dlfcn | |
#define RTLD_LAZY 0x1 | |
#define RTLD_GLOBAL 0x8 | |
void* dlsym(void* handle, const char* symbol); | |
void *dlopen(const char *filename, int flag); | |
int dlclose(void *handle); | |
#endif | |
#elif _WIN32 | |
#include <windows.h> | |
#else | |
#include <sys/mman.h> | |
#include <dlfcn.h> | |
#ifndef MAP_ANON | |
#define MAP_ANON 0x1000 | |
#endif | |
#endif | |
//////////////////////////////////////////// X86-64 | |
void x8664_encode_rex(uint8_t *buffer, int dest, int src, int op64) | |
{ | |
buffer[0] = (dest > 0x7) | ((src > 0x7) << 2) | (op64 << 3) | (0x40); | |
} | |
void x8664_encode_modrm(uint8_t *buffer, int dest, int src, int mod) | |
{ | |
buffer[0] = (dest & 0x7) | ((src & 0x7) << 3) | (mod << 6); | |
} | |
void x8664_encode(uint8_t *buffer, int dest, int src, int i, int mod, int op64) | |
{ | |
x8664_encode_rex(buffer, dest, src, op64); | |
x8664_encode_modrm(buffer + i, dest, src, mod); | |
} | |
// registers | |
#define RAX 0 | |
#define RCX 1 | |
#define RDX 2 | |
#define RBX 3 | |
#define RSP 4 | |
#define RBP 5 | |
#define RSI 6 | |
#define RDI 7 | |
#define R8 8 | |
#define R9 9 | |
#define R10 10 | |
#define R11 11 | |
#define R12 12 | |
#define R13 13 | |
#define R14 14 | |
#define R15 15 | |
#define XMM0 0 | |
#define XMM1 1 | |
#define XMM2 2 | |
#define XMM3 3 | |
#define XMM4 4 | |
#define XMM5 5 | |
#define XMM6 6 | |
#define XMM7 7 | |
#define XMM8 8 | |
#define XMM9 9 | |
#define XMM10 10 | |
#define XMM11 11 | |
#define XMM12 12 | |
#define XMM13 13 | |
#define XMM14 14 | |
#define XMM15 15 | |
#define AL RAX | |
// integer arguments | |
#ifdef _WIN32 | |
#define RA1 RCX | |
#define RA2 RDX | |
#define RA3 R8 | |
#define RA4 R9 | |
// (...stack) | |
#else // System V | |
#define RA1 RDI | |
#define RA2 RSI | |
#define RA3 RDX | |
#define RA4 RCX | |
#define RA5 R8 | |
#define RA6 R9 | |
// (...stack) | |
#endif | |
#define OPI32(opcode, buffer, im) {\ | |
buffer[0] = opcode;\ | |
*(uint32_t *)(buffer + 1) = im;\ | |
buffer += 5;\ | |
} | |
#define OP0(opcode, buffer, dest, src) {\ | |
buffer[0] = 0x0f;\ | |
buffer[1] = opcode;\ | |
x8664_encode_modrm(buffer + 2, dest, src, 3);\ | |
buffer += 3;\ | |
} | |
#define RR(opcode, buffer, dest, src, op64) {\ | |
buffer[1] = opcode;\ | |
x8664_encode(buffer, dest, src, 2, 3, op64);\ | |
buffer += 3;\ | |
} | |
#define RR0(opcode, buffer, dest, src, mod, op64) {\ | |
buffer[1] = 0x0f;\ | |
buffer[2] = opcode;\ | |
x8664_encode(buffer, dest, src, 3, mod, op64);\ | |
buffer += 4;\ | |
} | |
#define RRF(prefix, opcode, buffer, dest, src, op64) {\ | |
buffer[0] = prefix;\ | |
buffer[2] = 0x0f;\ | |
buffer[3] = opcode;\ | |
x8664_encode(buffer + 1, src, dest, 3, 3, op64);\ | |
buffer += 5;\ | |
} | |
#define RMF(opcode, buffer, dest, src, off) {\ | |
buffer[0] = 0xf3;\ | |
buffer[2] = 0x0f;\ | |
buffer[3] = opcode;\ | |
*(uint32_t *)(buffer + 5) = off;\ | |
x8664_encode(buffer + 1, dest, src, 3, 2, 0);\ | |
buffer += 9;\ | |
} | |
#define RMF4(opcode, buffer, dest, src, off) {\ | |
buffer[1] = 0x0f;\ | |
buffer[2] = opcode;\ | |
*(uint32_t *)(buffer + 4) = off;\ | |
x8664_encode(buffer, dest, src, 3, 2, 0);\ | |
buffer += 8;\ | |
} | |
#define RI8(opcode, buffer, dest, src, im, mod, op64) {\ | |
buffer[1] = opcode;\ | |
buffer[3] = im;\ | |
x8664_encode(buffer, dest, src, 2, mod, op64);\ | |
buffer += 4;\ | |
} | |
#define RI32(opcode, buffer, dest, src, im, mod, op64) {\ | |
buffer[1] = opcode;\ | |
*(uint32_t *)(buffer + 3) = im;\ | |
x8664_encode(buffer, dest, src, 2, mod, op64);\ | |
buffer += 7;\ | |
} | |
#define JZ(buffer, off) {\ | |
*(uint32_t *)(buffer) = 0x840fc085;\ | |
*(uint32_t *)(buffer + 4) = off;\ | |
buffer += 8;\ | |
} | |
#define JNZ(buffer, off) {\ | |
*(uint32_t *)(buffer) = 0x850fc085;\ | |
*(uint32_t *)(buffer + 4) = off;\ | |
buffer += 8;\ | |
} | |
#define PUSH(buffer, src) {\ | |
if (src < 8) { buffer[0] = 80 + src; }\ | |
else {\ | |
buffer[0] = 0b1000001; buffer++;\ | |
buffer[0] = 80 + src - 8;\ | |
}\ | |
buffer++;\ | |
} | |
#define POP(buffer, src) {\ | |
if (src < 8) { buffer[0] = 88 + src; }\ | |
else {\ | |
buffer[0] = 0b1000001; buffer++;\ | |
buffer[0] = 88 + src - 8;\ | |
}\ | |
buffer++;\ | |
} | |
#define CDQ(buffer) { buffer[0] = 0x99; buffer++; } | |
#define RET(buffer) { buffer[0] = 0xc3; buffer++; } | |
#define JMP(buffer, off) OPI32(0xe9, buffer, off) | |
#define CALLI32(buffer, off) OPI32(0xe8, buffer, off) | |
#define SETL(buffer, src) OP0(0x9c, buffer, 0, src) | |
#define SETG(buffer, src) OP0(0x9f, buffer, 0, src) | |
#define SETE(buffer, src) OP0(0x94, buffer, 0, src) | |
#define SETA(buffer, src) OP0(0x97, buffer, 0, src) | |
#define SETNE(buffer, src) OP0(0x95, buffer, 0, src) | |
#define MOVZX(buffer, dest, src) OP0(0xb6, buffer, dest, src) | |
#define MOV(buffer, dest, src) RR(0x89, buffer, dest, src, 1) | |
#define ADD(buffer, dest, src) RR(0x01, buffer, dest, src, 1) | |
#define SUB(buffer, dest, src) RR(0x29, buffer, dest, src, 1) | |
#define AND(buffer, dest, src) RR(0x21, buffer, dest, src, 1) | |
#define OR(buffer, dest, src) RR(0x09, buffer, dest, src, 1) | |
#define XOR(buffer, dest, src) RR(0x31, buffer, dest, src, 1) | |
#define IDIV32(buffer, src) RR(0xf7, buffer, src, 0b111, 0) | |
#define IDIV64(buffer, src) RR(0xf7, buffer, src, 0b111, 1) | |
#define SAR1(buffer, src) RR(0xd1, buffer, src, 0b111, 1) | |
#define SAL1(buffer, src) RR(0xd1, buffer, src, 0b100, 1) | |
#define SAR(buffer, src) RR(0xd3, buffer, src, 0b111, 1) | |
#define SAL(buffer, src) RR(0xd3, buffer, src, 0b100, 1) | |
#define CMP32(buffer, dest, src) RR(0x39, buffer, dest, src, 0) | |
#define CMP64(buffer, dest, src) RR(0x39, buffer, dest, src, 1) | |
#define CALL64(buffer, src) RR(0xff, buffer, src, 0b010, 1) | |
#define IMUL(buffer, dest, src) RR0(0xaf, buffer, src, dest, 3, 1) | |
#define UCOMISS(buffer, dest, src) RR0(0x2e, buffer, src, dest, 3, 0) | |
#define MOVUPS(buffer, dest, src) RR0(0x10, buffer, src, dest, 3, 0) | |
#define ADDPS(buffer, dest, src) RR0(0x58, buffer, src, dest, 3, 0) | |
#define SUBPS(buffer, dest, src) RR0(0x5c, buffer, src, dest, 3, 0) | |
#define MULPS(buffer, dest, src) RR0(0x59, buffer, src, dest, 3, 0) | |
#define DIVPS(buffer, dest, src) RR0(0x5e, buffer, src, dest, 3, 0) | |
#define MINPS(buffer, dest, src) RR0(0x5d, buffer, src, dest, 3, 0) | |
#define MAXPS(buffer, dest, src) RR0(0x5f, buffer, src, dest, 3, 0) | |
#define SQRTPS(buffer, dest, src) RR0(0x51, buffer, src, dest, 3, 0) | |
#define ADDI8(buffer, dest, im) RI8(0x83, buffer, dest, 0b000, im, 3, 1) | |
#define SUBI8(buffer, dest, im) RI8(0x83, buffer, dest, 0b101, im, 3, 1) | |
#define SARI(buffer, src, im) RI8(0xc1, buffer, src, 0b111, im, 3, 1) | |
#define SALI(buffer, src, im) RI8(0xc1, buffer, src, 0b100, im, 3, 1) | |
#define CMPI8(buffer, dest, im) RI8(0x83, buffer, dest, 0b111, im, 3, 1) | |
#define MOVI32(buffer, dest, im) RI32(0xc7, buffer, dest, 0b000, im, 3, 1) | |
#define ADDI32(buffer, dest, im) RI32(0x81, buffer, dest, 0b000, im, 3, 1) | |
#define LOAD64(buffer, dest, src, off) RI32(0x8b, buffer, src, dest, off, 2, 1) | |
#define STORE64(buffer, dest, off, src) RI32(0x89, buffer, dest, src, off, 2, 1) | |
#define LOAD32(buffer, dest, src, off) RI32(0x8b, buffer, src, dest, off, 2, 0) | |
#define STORE32(buffer, dest, off, src) RI32(0x89, buffer, dest, src, off, 2, 0) | |
#define MOVSS(buffer, dest, src) RRF(0xf3, 0x10, buffer, dest, src, 0) | |
#define ADDSS(buffer, dest, src) RRF(0xf3, 0x58, buffer, dest, src, 0) | |
#define SUBSS(buffer, dest, src) RRF(0xf3, 0x5c, buffer, dest, src, 0) | |
#define MULSS(buffer, dest, src) RRF(0xf3, 0x59, buffer, dest, src, 0) | |
#define DIVSS(buffer, dest, src) RRF(0xf3, 0x5e, buffer, dest, src, 0) | |
#define MINSS(buffer, dest, src) RRF(0xf3, 0x5d, buffer, dest, src, 0) | |
#define MAXSS(buffer, dest, src) RRF(0xf3, 0x5f, buffer, dest, src, 0) | |
#define SQRTSS(buffer, dest, src) RRF(0xf3, 0x51, buffer, dest, src, 0) | |
#define CVTSI2SS(buffer, dest, src) RRF(0xf3, 0x2a, buffer, dest, src, 1) | |
#define CVTSS2SI(buffer, dest, src) RRF(0xf3, 0x2d, buffer, dest, src, 1) | |
#define PXOR(buffer, dest, src) RRF(0x66, 0xef, buffer, dest, src, 0) | |
#define LOADSS(buffer, dest, src, off) RMF(0x10, buffer, src, dest, off) | |
#define STORESS(buffer, dest, off, src) RMF(0x11, buffer, dest, src, off) | |
#define LOADUPS(buffer, dest, src, off) RMF4(0x10, buffer, src, dest, off) | |
#define STOREUPS(buffer, dest, off, src) RMF4(0x11, buffer, dest, src, off) | |
//////////////////////////////////////////// JIT MIPS-like | |
struct jit_parsing | |
{ | |
uint8_t *buffer; | |
uint8_t **info1; | |
uint16_t *info2; | |
uint16_t i1; | |
}; | |
struct jit_state | |
{ | |
struct jit_parsing p; | |
uint8_t **info1; | |
uint16_t *info2; | |
void *buffer; | |
int buffer_size; | |
}; | |
// registers | |
#define JIT_R0 -1 // always zero | |
#ifdef _WIN32 | |
#define JIT_R1 R10 // volatile | |
#define JIT_R2 R11 // volatile | |
#else | |
#define JIT_R1 R8 // volatile | |
#define JIT_R2 R9 // volatile | |
#endif | |
#define JIT_R3 RBX // callee must save | |
#define JIT_R4 R12 // callee must save | |
#define JIT_R5 R13 // callee must save | |
#define JIT_R6 R14 // callee must save | |
#define JIT_R7 R15 // callee must save | |
#define JIT_RE RAX // return (very volatile (used internally), use just before calling JIT_RETURN) | |
#define JIT_SP RSP // stack pointer | |
// arguments | |
#define JIT_A1 RA1 | |
#define JIT_A2 RA2 | |
#define JIT_A3 RA3 | |
#define JIT_A4 RA4 | |
// float registers (all volatile) | |
#define JIT_RF0 XMM0 // arg1, return | |
#define JIT_RF1 XMM1 // arg2 | |
#define JIT_RF2 XMM2 // arg3 | |
#define JIT_RF3 XMM3 // arg4 | |
#define JIT_RF4 XMM4 | |
#define JIT_RF5 XMM5 | |
#define JIT_RF6 XMM6 | |
#define JIT_RF7 XMM7 | |
#define JIT_RF8 XMM8 | |
#define JIT_RF9 XMM9 | |
#define JIT_RF10 XMM10 | |
#define JIT_RF11 XMM11 | |
#define JIT_RF12 XMM12 | |
#define JIT_RF13 XMM13 | |
#define JIT_RF14 XMM14 | |
#define JIT_RF15 XMM15 | |
// instructions | |
void JIT_LOAD32(struct jit_parsing *p, int d, int s, int o); | |
void JIT_STORE32(struct jit_parsing *p, int d, int o, int s); | |
void JIT_LOAD64(struct jit_parsing *p, int d, int s, int o); | |
void JIT_STORE64(struct jit_parsing *p, int d, int o, int s); | |
void JIT_ADD(struct jit_parsing *p, int d, int s, int t); | |
void JIT_ADDI(struct jit_parsing *p, int d, int s, int i); | |
void JIT_SUB(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MUL(struct jit_parsing *p, int d, int s, int t); | |
void JIT_DIV(struct jit_parsing *p, int d, int s, int t); | |
void JIT_SHIFTL(struct jit_parsing *p, int d, int s, int t); | |
void JIT_SHIFTR(struct jit_parsing *p, int d, int s, int t); | |
void JIT_SHIFTLI(struct jit_parsing *p, int d, int s, int i); | |
void JIT_SHIFTRI(struct jit_parsing *p, int d, int s, int i); | |
void JIT_AND(struct jit_parsing *p, int d, int s, int t); | |
void JIT_OR(struct jit_parsing *p, int d, int s, int t); | |
void JIT_XOR(struct jit_parsing *p, int d, int s, int t); | |
void JIT_LESS(struct jit_parsing *p, int d, int s, int t); | |
void JIT_JUMP(struct jit_parsing *p, int o); | |
void JIT_BRANCH(struct jit_parsing *p, int s, int t, int o); | |
void JIT_NBRANCH(struct jit_parsing *p, int s, int t, int o); | |
void JIT_CALL(struct jit_parsing *p, int o); | |
void JIT_CALLEX(struct jit_parsing *p, int s); | |
void JIT_RETURN(struct jit_parsing *p); | |
void JIT_LOADF(struct jit_parsing *p, int d, int s, int o); | |
void JIT_STOREF(struct jit_parsing *p, int d, int o, int s); | |
void JIT_ITOF(struct jit_parsing *p, int d, int s); | |
void JIT_FTOI(struct jit_parsing *p, int d, int s); | |
void JIT_ADDF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_SUBF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MULF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_DIVF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_LESSF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MINF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MAXF(struct jit_parsing *p, int d, int s, int t); | |
void JIT_LOADF4(struct jit_parsing *p, int d, int s, int o); | |
void JIT_STOREF4(struct jit_parsing *p, int d, int o, int s); | |
void JIT_ADDF4(struct jit_parsing *p, int d, int s, int t); | |
void JIT_SUBF4(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MULF4(struct jit_parsing *p, int d, int s, int t); | |
void JIT_DIVF4(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MINF4(struct jit_parsing *p, int d, int s, int t); | |
void JIT_MAXF4(struct jit_parsing *p, int d, int s, int t); | |
#define JIT__INFO(p)\ | |
p->info1[0] = p->buffer;\ | |
p->info1++;\ | |
p->i1++; | |
#define JIT__INFO2(p)\ | |
p->info2[0] = p->i1;\ | |
p->info2++; | |
void JIT_LOAD32(struct jit_parsing *p, int d, int s, int o) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (s == JIT_SP) { | |
MOV(p->buffer, RAX, s) | |
LOAD32(p->buffer, d, RAX, o) | |
} | |
else { | |
LOAD32(p->buffer, d, s, o) | |
} | |
} | |
} | |
void JIT_STORE32(struct jit_parsing *p, int d, int o, int s) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (d == JIT_SP) { | |
MOV(p->buffer, RAX, d) | |
STORE32(p->buffer, RAX, o, s) | |
} | |
else { | |
STORE32(p->buffer, d, o, s) | |
} | |
} | |
} | |
void JIT_LOAD64(struct jit_parsing *p, int d, int s, int o) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (s == JIT_SP) { | |
MOV(p->buffer, RAX, s) | |
LOAD64(p->buffer, d, RAX, o) | |
} | |
else { | |
LOAD64(p->buffer, d, s, o) | |
} | |
} | |
} | |
void JIT_STORE64(struct jit_parsing *p, int d, int o, int s) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (d == JIT_SP) { | |
MOV(p->buffer, RAX, d) | |
STORE64(p->buffer, RAX, o, s) | |
} | |
else { | |
STORE64(p->buffer, d, o, s) | |
} | |
} | |
} | |
void JIT_ADD(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0 && t == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (s == JIT_R0) { | |
if (t != d) MOV(p->buffer, d, t) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
ADD(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_ADDI(struct jit_parsing *p, int d, int s, int i) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0) { | |
MOVI32(p->buffer, d, i) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
if (i != 0) ADDI32(p->buffer, d, i) | |
} | |
} | |
} | |
void JIT_SUB(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == t) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (s == JIT_R0) { | |
if (t != d) MOV(p->buffer, d, t) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
SUB(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_MUL(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0 || t == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
IMUL(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_DIV(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0 || t == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
// use rax / rdx | |
PUSH(p->buffer, RDX) | |
MOV(p->buffer, RAX, s) | |
CDQ(p->buffer) | |
IDIV64(p->buffer, t) | |
MOV(p->buffer, d, RAX) | |
POP(p->buffer, RDX) | |
} | |
} | |
} | |
void JIT_SHIFTL(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
PUSH(p->buffer, RCX) | |
MOV(p->buffer, RCX, t) | |
SAL(p->buffer, d) | |
POP(p->buffer, RCX) | |
} | |
} | |
} | |
void JIT_SHIFTR(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
PUSH(p->buffer, RCX) | |
MOV(p->buffer, RCX, t) | |
SAR(p->buffer, d) | |
POP(p->buffer, RCX) | |
} | |
} | |
} | |
void JIT_SHIFTLI(struct jit_parsing *p, int d, int s, int i) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
SALI(p->buffer, d, i) | |
} | |
} | |
} | |
void JIT_SHIFTRI(struct jit_parsing *p, int d, int s, int i) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
SARI(p->buffer, d, i) | |
} | |
} | |
} | |
void JIT_AND(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == t) { | |
if (s == JIT_R0) MOVI32(p->buffer, d, 0) | |
else if (s != d) MOV(p->buffer, d, s) | |
} | |
else if (s == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (t == JIT_R0) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
AND(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_OR(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == t) { | |
if (s == JIT_R0) MOVI32(p->buffer, d, 0) | |
else if (s != d) MOV(p->buffer, d, s) | |
} | |
else if (s == JIT_R0) { | |
if (t != d) MOV(p->buffer, d, t) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
OR(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_XOR(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == t) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else if (s == JIT_R0) { | |
if (t != d) MOV(p->buffer, d, t) | |
} | |
else if (t == JIT_R0) { | |
if (s != d) MOV(p->buffer, d, s) | |
} | |
else { | |
if (s != d) MOV(p->buffer, d, s) | |
XOR(p->buffer, d, t) | |
} | |
} | |
} | |
void JIT_LESS(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) { | |
if (s == t) { | |
MOVI32(p->buffer, d, 0) | |
} | |
else { | |
if (s == JIT_R0) CMPI8(p->buffer, t, 0) | |
else if (t == JIT_R0) CMPI8(p->buffer, s, 0) | |
else CMP64(p->buffer, s, t) | |
SETL(p->buffer, AL) | |
MOVZX(p->buffer, RAX, AL) | |
MOV(p->buffer, d, RAX) | |
} | |
} | |
} | |
void JIT_JUMP(struct jit_parsing *p, int o) | |
{ | |
JIT__INFO(p) | |
if (o > 0 || o < -1) { | |
JMP(p->buffer, o) | |
JIT__INFO2(p) | |
} | |
} | |
void JIT_BRANCH(struct jit_parsing *p, int s, int t, int o) | |
{ | |
if (s == t) { | |
JIT_JUMP(p, o); | |
return; | |
} | |
JIT__INFO(p) | |
if (o > 0 || o < -1) { | |
if (s == JIT_R0) CMPI8(p->buffer, t, 0) | |
else if (t == JIT_R0) CMPI8(p->buffer, s, 0) | |
else CMP64(p->buffer, s, t) | |
SETE(p->buffer, AL) | |
MOVZX(p->buffer, RAX, AL) | |
JNZ(p->buffer, o) | |
JIT__INFO2(p) | |
} | |
} | |
void JIT_NBRANCH(struct jit_parsing *p, int s, int t, int o) | |
{ | |
JIT__INFO(p) | |
if ((o > 0 || o < -1) && (s != t)) { | |
if (s == JIT_R0) CMPI8(p->buffer, t, 0) | |
else if (t == JIT_R0) CMPI8(p->buffer, s, 0) | |
else CMP64(p->buffer, s, t) | |
SETE(p->buffer, AL) | |
MOVZX(p->buffer, RAX, AL) | |
JZ(p->buffer, o) | |
JIT__INFO2(p) | |
} | |
} | |
void JIT_CALL(struct jit_parsing *p, int o) | |
{ | |
JIT__INFO(p) | |
if (o > 0 || o < -1) { | |
CALLI32(p->buffer, o) | |
JIT__INFO2(p) | |
} | |
} | |
void JIT_CALLEX(struct jit_parsing *p, int s) | |
{ | |
JIT__INFO(p) | |
if (s != JIT_R0) CALL64(p->buffer, s) | |
} | |
void JIT_RETURN(struct jit_parsing *p) | |
{ | |
JIT__INFO(p) | |
RET(p->buffer) | |
} | |
void JIT_LOADF(struct jit_parsing *p, int d, int s, int o) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (s == JIT_SP) { | |
MOV(p->buffer, RAX, s) | |
LOADSS(p->buffer, d, RAX, o) | |
} | |
else { | |
LOADSS(p->buffer, d, s, o) | |
} | |
} | |
} | |
void JIT_STOREF(struct jit_parsing *p, int d, int o, int s) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (d == JIT_SP) { | |
MOV(p->buffer, RAX, d) | |
STORESS(p->buffer, RAX, o, s) | |
} | |
else { | |
STORESS(p->buffer, d, o, s) | |
} | |
} | |
} | |
void JIT_ITOF(struct jit_parsing *p, int d, int s) | |
{ | |
JIT__INFO(p) | |
PXOR(p->buffer, d, d) | |
if (s != JIT_R0) CVTSI2SS(p->buffer, d, s) | |
} | |
void JIT_FTOI(struct jit_parsing *p, int d, int s) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0) CVTSS2SI(p->buffer, d, s) | |
} | |
void JIT_ADDF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
ADDSS(p->buffer, d, t) | |
} | |
void JIT_SUBF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
SUBSS(p->buffer, d, t) | |
} | |
void JIT_MULF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
MULSS(p->buffer, d, t) | |
} | |
void JIT_DIVF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
DIVSS(p->buffer, d, t) | |
} | |
void JIT_LESSF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
UCOMISS(p->buffer, s, t) | |
SETA(p->buffer, AL) | |
MOVZX(p->buffer, RAX, AL) | |
MOV(p->buffer, d, RAX) | |
} | |
void JIT_MINF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
MINSS(p->buffer, d, t) | |
} | |
void JIT_MAXF(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVSS(p->buffer, d, s) | |
MAXSS(p->buffer, d, t) | |
} | |
void JIT_LOADF4(struct jit_parsing *p, int d, int s, int o) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (s == JIT_SP) { | |
MOV(p->buffer, RAX, s) | |
LOADUPS(p->buffer, d, RAX, o) | |
} | |
else { | |
LOADUPS(p->buffer, d, s, o) | |
} | |
} | |
} | |
void JIT_STOREF4(struct jit_parsing *p, int d, int o, int s) | |
{ | |
JIT__INFO(p) | |
if (d != JIT_R0 && s != JIT_R0) { | |
if (d == JIT_SP) { | |
MOV(p->buffer, RAX, d) | |
STOREUPS(p->buffer, RAX, o, s) | |
} | |
else { | |
STOREUPS(p->buffer, d, o, s) | |
} | |
} | |
} | |
void JIT_ADDF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
ADDPS(p->buffer, d, t) | |
} | |
void JIT_SUBF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
SUBPS(p->buffer, d, t) | |
} | |
void JIT_MULF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
MULPS(p->buffer, d, t) | |
} | |
void JIT_DIVF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
DIVPS(p->buffer, d, t) | |
} | |
void JIT_MINF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
MINPS(p->buffer, d, t) | |
} | |
void JIT_MAXF4(struct jit_parsing *p, int d, int s, int t) | |
{ | |
JIT__INFO(p) | |
if (s != d) MOVUPS(p->buffer, d, s) | |
MAXPS(p->buffer, d, t) | |
} | |
void jit_create(struct jit_state *s, int size) | |
{ | |
s->buffer_size = size * 32; | |
#ifdef _WIN32 | |
s->buffer = VirtualAlloc(NULL, s->buffer_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); | |
#else | |
s->buffer = mmap(0, s->buffer_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0); | |
#endif | |
if (s->buffer == (void*)-1) { | |
printf("jit mmap error\n"); | |
return; | |
} | |
s->info1 = malloc(size * sizeof(uint8_t *)); | |
s->info2 = malloc(size * sizeof(uint16_t)); | |
} | |
void jit_destroy(struct jit_state *s) | |
{ | |
free(s->info2); | |
free(s->info1); | |
#ifdef _WIN32 | |
VirtualFree(s->buffer, 0, MEM_RELEASE); | |
#else | |
munmap(s->buffer, s->buffer_size); | |
#endif | |
} | |
void jit_begin(struct jit_state *s) | |
{ | |
s->p.buffer = s->buffer; | |
s->p.info1 = s->info1; | |
s->p.info2 = s->info2; | |
s->p.i1 = 0; | |
} | |
void jit_relocate(struct jit_state *s) | |
{ | |
uint8_t **info1 = s->info1; | |
uint16_t *info2 = s->info2; | |
struct jit_parsing *p = &s->p; | |
uint16_t *i = info2; | |
while (i < p->info2) { | |
int i2o; | |
int i2 = i[0]; | |
int32_t *o = (int32_t *)(info1[i2] - 4); | |
i2o = info1[i2 + *o] - info1[i2]; | |
*o = i2o; | |
i++; | |
} | |
} | |
struct jit_state jit_s; | |
void test_x8664(uint8_t *buffer) | |
{ | |
RET(buffer) | |
} | |
void test_risc_equ(struct jit_parsing *p) | |
{ | |
// == | |
JIT_BRANCH(p, JIT_A1, JIT_A2, 2); | |
JIT_ADDI(p, JIT_RE, JIT_R0, 0); | |
JIT_RETURN(p); | |
JIT_ADDI(p, JIT_RE, JIT_R0, 1); | |
JIT_RETURN(p); | |
//JIT_LESS(p, JIT_RE, JIT_A1, JIT_A2); | |
//JIT_RETURN(p); | |
// == avec jump < 0 | |
/* | |
JIT_JUMP(p, 2); | |
JIT_ADDI(p, JIT_RE, JIT_R0, 1); | |
JIT_RETURN(p); | |
JIT_BRANCH(p, JIT_A1, JIT_A2, -3); | |
JIT_ADDI(p, JIT_RE, JIT_R0, 0); | |
JIT_RETURN(p); | |
*/ | |
} | |
void test_risc(struct jit_parsing *p) | |
{ | |
// push stack | |
JIT_ADDI(p, JIT_SP, JIT_SP, -8); | |
// save R3 | |
JIT_STORE64(p, JIT_SP, 0, JIT_R3); | |
// add | |
JIT_ADD(p, JIT_R1, JIT_A1, JIT_A2); | |
// counter | |
JIT_LOAD32(p, JIT_R2, JIT_A3, 0); | |
JIT_ADDI(p, JIT_R2, JIT_R2, 1); | |
JIT_STORE32(p, JIT_A3, 0, JIT_R2); | |
// restore R3 | |
JIT_LOAD64(p, JIT_R3, JIT_SP, 0); | |
// pop stack | |
JIT_ADDI(p, JIT_SP, JIT_SP, 8); | |
JIT_ADDI(p, JIT_RE, JIT_R1, 0); | |
JIT_RETURN(p); | |
} | |
void test_risc_float(struct jit_parsing *p) | |
{ | |
JIT_ADDF(p, JIT_RF0, JIT_RF0, JIT_RF1); | |
JIT_RETURN(p); | |
} | |
void test_risc_float4(struct jit_parsing *p) | |
{ | |
JIT_LOADF4(p, JIT_RF0, JIT_A1, 0); | |
JIT_LOADF4(p, JIT_RF1, JIT_A1, 16); | |
JIT_ADDF4(p, JIT_RF0, JIT_RF0, JIT_RF1); | |
JIT_STOREF4(p, JIT_A1, 32, JIT_RF0); | |
JIT_RETURN(p); | |
} | |
void test_int() | |
{ | |
int mem[4] = {1, 10, 0, 0}; | |
typedef int (*fun_t)(int, int, int *); | |
int i; | |
jit_begin(&jit_s); | |
test_risc(&jit_s.p); | |
jit_relocate(&jit_s); | |
fun_t func = (fun_t)jit_s.buffer; | |
for (i = 0; i < 10; i++) | |
mem[2] = func(mem[0], mem[1], &mem[3]); | |
printf("result = %d %d\n", mem[2], mem[3]); | |
} | |
void test_float() | |
{ | |
float mem[4] = {2.2, 10.10, 22.22, 0.1}; | |
typedef float (*fun_t)(float, float, float *); | |
int i; | |
jit_begin(&jit_s); | |
test_risc_float(&jit_s.p); | |
jit_relocate(&jit_s); | |
fun_t func = (fun_t)jit_s.buffer; | |
//void *dl = dlopen(0, RTLD_LAZY | RTLD_GLOBAL); | |
//void *ptr = dlsym(dl, "sinf"); | |
//dlclose(dl); | |
float d; | |
for (i = 0; i < 1000; i++) | |
d = func(mem[0], mem[1], mem); | |
printf("result = %f\n", d); | |
} | |
void test_float4() | |
{ | |
float mem[12] = { | |
2.2, 10.10, 22.22, 0.1, | |
0.1, 0.20, 0.3, 0.4, | |
0.0, 0.0, 0.0, 0.0 | |
}; | |
typedef void (*fun_t)(float *); | |
int i; | |
jit_begin(&jit_s); | |
test_risc_float4(&jit_s.p); | |
jit_relocate(&jit_s); | |
fun_t func = (fun_t)jit_s.buffer; | |
for (i = 0; i < 1000; i++) | |
func(mem); | |
printf("result = %f %f %f %f\n", mem[8], mem[9], mem[10], mem[11]); | |
} | |
void test_jit() | |
{ | |
//test_int(); | |
test_float4(); | |
} | |
void ctoy_begin(void) | |
{ | |
jit_create(&jit_s, 256); | |
double t = ctoy_get_time(); | |
test_jit(); | |
printf("(%f sec)\n", ctoy_get_time() - t); | |
jit_destroy(&jit_s); | |
} | |
void ctoy_main_loop(void) | |
{ | |
ctoy_sleep(0, 1000000); | |
} | |
void ctoy_end(void) | |
{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment