/* jit.h Copyright (C) 2006-2007 J O'Connell & Codemist Ltd */
#ifndef header_jit_h
#define header_jit_h 1
/*
* This code may be used and modified, and redistributed in binary
* or source form, subject to the "CCL Public License", which should
* accompany it. This license is a variant on the BSD license, and thus
* permits use of code derived from this in either open and commercial
* projects: but it does require that updates to this code be made
* available back to the originators of the package.
* Before merging other code in with this or linking this code
* with other packages or libraries please check that the license terms
* of the other material are compatible with those of this.
*/
/* Signature: 4e53f50d 18-Jan-2007 */
/*
* At present the CSL JIT only supports the Intel/AMD x86 architecture.
* Attempts to use it on other sorts of machine may have really bad
* confusing consequences!
*/
#define x86arch 1
/*
* Debug switch for the JIT
*/
#define JDEBUG 1
/* register, eg EAX */
#define EAX 0x0
#define ECX 0x1
#define EDX 0x2
#define EBX 0x3
#define ESP 0x4
#define EBP 0x5
#define ESI 0x6
#define EDI 0x7
/* memory indirection, eg [EAX] */
#define EAXM 0x8
#define ECXM 0x9
#define EDXM 0xa
#define EBXM 0xb
#define ESPM 0xc
#define EBPM 0xd
#define ESIM 0xe
#define EDIM 0xf
/* memory offset */
#define DISP32 0x10
/*
* At some stage it may be good to arrange that the JIT assembler can decide
* whether it needs a long-form branch or if a short one will suffice. At this
* stage the choice is made globally. Define JUMPREL8 if you guarantee
* all functions are tiny and you want the shortest code, or leave it
* undefined for safer treatment of bigger examples.
*/
#ifdef JUMPREL8
/* Conditional branches with rel8 offset */
#define JA 0x77
#define JAE 0x73
#define JB 0x72
#define JBE 0x76
#define JC 0x72
#define JCXZ 0xe3
#define JECXZ 0xe3
#define JRCXZ 0xe3
#define JE 0x74
#define JG 0x7f
#define JGE 0x7d
#define JL 0x7c
#define JLE 0x7e
#define JNA 0x76
#define JNAE 0x72
#define JNB 0x73
#define JNBE 0x77
#define JNC 0x73
#define JNE 0x75
#define JNG 0x7e
#define JNGE 0x7c
#define JNL 0x7d
#define JNLE 0x7f
#define JNO 0x71
#define JNP 0x7b
#define JNS 0x79
#define JNZ 0x75
#define JO 0x70
#define JP 0x7a
#define JPE 0x7a
#define JPO 0x7b
#define JS 0x78
#define JZ 0x74
#else
/* Conditional branches with rel32 offset */
#define JA 0x0f87
#define JAE 0x0f83
#define JB 0x0f82
#define JBE 0x0f86
#define JC 0x0f82
#define JE 0x0f84
#define JG 0x0f8f
#define JGE 0x0f8d
#define JL 0x0f8c
#define JLE 0x0f8e
#define JNA 0x0f86
#define JNAE 0x0f82
#define JNB 0x0f83
#define JNBE 0x0f87
#define JNC 0x0f83
#define JNE 0x0f85
#define JNG 0x0f8e
#define JNGE 0x0f8c
#define JNL 0x0f8d
#define JNLE 0x0f8f
#define JNO 0x0f81
#define JNP 0x0f8b
#define JNS 0x0f89
#define JNZ 0x0f85
#define JO 0x0f80
#define JP 0x0f8a
#define JPE 0x0f8a
#define JPO 0x0f8b
#define JS 0x0f88
#define JZ 0x0f84
#endif /* JUMPREL */
/* Function defintions */
/* jitx86.h */
extern void inc_reg(int reg);
extern void dec_reg(int reg);
extern void sub_imm8_rm32(int size, int reg);
extern void sub_imm32_rm32(int size, int reg);
extern void add_imm8_addr(int size, void *addr);
extern void sub_imm8_addr(int size, void *addr);
extern void add_imm8_rm32(int size, int reg);
extern void add_imm32_rm32(int size, int reg);
extern void and_imm_rm32(int size, int reg);
extern void mov_rm32_rm32(int dest, int source);
extern void mov_rm32_rm32_disp(int dest, int source, int disp);
extern void cmp_imm_r32(int size, int reg);
extern void cmp_rm32_rm32(int dest, int source);
extern void cmp_rm32_rm32_disp(int dest, int source, int disp);
extern void mov_r32_addr(int dest, void *source);
extern void mov_addr_r32(void *dest, int source);
extern void lea_m32_r32_disp(int source, int dest, int disp);
extern void lea_m32_r32_disp(int source, int dest, int disp);
extern void MS_CDECL Jpush(int nargs, ...);
extern void MS_CDECL Jpop(int nargs, ...);
/* jit2.c */
typedef struct reloc_table_struct
{
char *label;
unsigned long pos;
struct reloc_table_struct *next;
} reloc_table;
typedef struct variables_table_struct
{
int addr;
unsigned long pos;
struct variables_table_struct *next;
} variables_table;
extern reloc_table *labels_table;
extern reloc_table *callers_table;
extern reloc_table *jumpers_table;
extern variables_table *vars_table;
extern reloc_table *disassembler_labels;
extern unsigned char codebuffer[8192]; /* rather arbitrary size! */
extern unsigned long codep;
extern void free_labels_table(reloc_table *head);
extern void free_var_table(variables_table *head);
extern void reloc_calls();
extern void reloc_jumps();
extern void reloc_vars();
extern void startcode();
extern void putbyte(int c);
extern void put2bytes(int c);
extern void put3bytes(int c);
extern void put4bytes(int c);
extern void put5bytes(long long c);
extern void put_little_endian(Lisp_Object c);
extern void put_addr(void *c);
extern int isreg(int reg);
extern void call_rel_fn(char *label);
extern void jump(char *label);
extern void cond_jump(char *label, int cond);
extern void add_label(char *label);
extern void add_disassembler_label(char *label);
extern void Jcall_abs_fn(void *addr_big_endian);
/* jit3.c */
#define init_stack_pointers() { put3bytes(0x5589e5); }
#define exit_stack_pointers() { put4bytes(0x89ec5dc3); }
#define exit_bytecode() exit_stack_pointers();
#define Jpush_all() { putbyte(0x60); }
#define Jpop_all() { putbyte(0x61); }
#undef stack
#define stack &C_stack
/*
* 83 ec 28 sub $0x28,%esp
* a1 xx xx xx xx mov 0x0, %eax
* 89 45 f8 mov %eax, 0xfffffff8(%ebp)
*/
#define Jsetup_nil() { put4bytes(0x83ec38a1); \
put_addr(&C_nil); \
mov_rm32_rm32_disp(EAX,EBPM,-2); }
#define Jnil_eq_C_nil() { putbyte(0xa1); \
put_addr(&C_nil); \
mov_rm32_rm32_disp(EAX,EBPM,-2); }
#define Jresult() { put3bytes(0x8b45f4); }
/*
* used in bytecode compiler:
*/
#define load_stack_into(REG) mov_rm32_rm32_disp(EBPM,REG,-2);
#define load_stackaddr_into(REG) lea_m32_r32_disp(EBPM,REG,-2);
#define store_stack_from(REG) mov_rm32_rm32_disp(REG,EBPM,-2);
#define load_nil_into(REG) mov_rm32_rm32_disp(EBPM,REG,-1);
#define store_nil_from(REG) mov_rm32_rm32_disp(REG,EBPM,-1);
#define load_entry_stack_into(REG) mov_rm32_rm32_disp(EBPM,REG,4);
#define store_entry_stack_from(REG) mov_rm32_rm32_disp(REG,EBPM,4);
#define store_result_from(REG) mov_rm32_rm32_disp(REG,EBPM,-15);
/*
* OPTIMISE_REG is a pending enhancement!
*/
#ifndef OPTIMISE_REG
#define load_A_reg_into(REG) mov_rm32_rm32_disp(EBPM,REG,-17);
#define store_A_reg_from(REG) mov_rm32_rm32_disp(REG,EBPM,-17);
#define load_B_reg_into(REG) { load_nil_into(REG); \
add_imm32_rm32(B_REG,REG); }
#else
#define load_A_reg_into(REG) mov_rm32_rm32(EDI,REG);
#define store_A_reg_from(REG) mov_rm32_rm32(REG,EDI);
#define load_B_reg_into(REG) { load_nil_into(REG); \
add_imm32_rm32(B_REG,REG); }
#endif /* OPTIMISE_REG */
#define push_A_reg() mov_rm32_rm32_disp(EDI,EBPM,-17);
#define pop_A_reg() mov_rm32_rm32_disp(EBPM,EDI,-17);
#define load_fringe_into(REG) { load_nil_into(REG); \
add_imm32_rm32(FRINGE,REG); }
#define load_heaplimit_into(REG) { load_nil_into(REG); \
add_imm32_rm32(HEAPLIMIT,REG); }
#define load_codevec_into(REG) { load_nil_into(REG); \
add_imm32_rm32(CODEVEC,REG); }
#ifdef LITVEC_FROM_NIL
#define load_litvec_into(REG) { load_nil_into(REG); \
add_imm32_rm32(LITVEC,REG); }
#else
/*
* Loads litvec into REG from qcdr(def) which is passed as arg
* to bytestream_interpret in 12(ebp)
*/
#define load_litvec_into(REG) mov_rm32_rm32_disp(EBPM,REG,3);
#endif
#define FRINGE 0x48 /* FIXME only works for x86 */
#define HEAPLIMIT 0x4c
#define B_REG 0xd4
#define CODEVEC 0xd8
#define LITVEC 0xdc
#define make_bc_label() sprintf(label,"BC%x",*ppc+bytecodes+1);
#define make_bc_label_backwards() sprintf(label,"BC%x",bytecodes-*ppc+1);
#define make_label(label,op,num) sprintf(label,"%s%i%i",op,num,bytecodes);
#endif /* header_jit_h */
/* end of jit.h */