1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00
guile/include/lightning/jit_private.h
pcpa 9afca85921 Rework to better describe what is used only during jit generation.
* include/lightning/jit_private.h, lib/jit_arm-cpu.c,
	lib/jit_arm.c, lib/jit_disasm.c, lib/jit_mips-cpu.c,
	lib/jit_mips.c, lib/jit_note.c, lib/jit_ppc-cpu.c,
	lib/jit_ppc.c, lib/jit_print.c, lib/jit_sparc-cpu.c,
	lib/jit_sparc.c, lib/jit_x86-cpu.c, lib/jit_x86.c,
	lib/lightning.c: Add an extra structure for data storage
	during jit generation, and release it after generating
	jit, to reduce a bit memory usage, and also to make it
	easier to understand what data is available during
	jit runtime.
2013-03-06 16:49:26 -03:00

478 lines
13 KiB
C

/*
* Copyright (C) 2012 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Authors:
* Paulo Cesar Pereira de Andrade
*/
#ifndef _jit_private_h
#define _jit_private_h
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <gmp.h>
#if defined(__GNUC__)
# define maybe_unused __attribute__ ((unused))
# define unlikely(exprn) __builtin_expect(!!(exprn), 0)
# define likely(exprn) __builtin_expect(!!(exprn), 1)
# if (__GNUC__ >= 4)
# define PUBLIC __attribute__ ((visibility("default")))
# define HIDDEN __attribute__ ((visibility("hidden")))
# else
# define PUBLIC /**/
# define HIDDEN /**/
# endif
#else
# define maybe_unused /**/
# define unlikely(exprn) exprn
# define likely(exprn) exprn
# define PUBLIC /**/
# define HIDDEN /**/
#endif
#if defined(__i386__) || defined(__x86_64__)
# define JIT_SP _RSP
# define JIT_RET _RAX
# if __WORDSIZE == 32
# define JIT_FRET _ST0
# else
# define JIT_FRET _XMM0
# endif
#elif defined(__mips__)
# define JIT_SP _SP
# define JIT_RET _V0
# define JIT_FRET _F0
#elif defined(__arm__)
# define JIT_SP _R13
# define JIT_RET _R0
# if defined(__ARM_PCS_VFP)
# define JIT_FRET _D0
# else
# define JIT_FRET _R0
# endif
#elif defined(__ppc__)
# define JIT_SP _R1
# define JIT_RET _R3
# define JIT_FRET _F1
#elif defined(__sparc__)
# define JIT_SP _SP
# define JIT_RET _I0
# define JIT_FRET _F0
#endif
#define jit_size(vector) (sizeof(vector) / sizeof((vector)[0]))
#define jit_reg_free_p(regno) \
(!jit_regset_tstbit(_jitc->reglive, regno) && \
!jit_regset_tstbit(_jitc->regarg, regno) && \
!jit_regset_tstbit(_jitc->regsav, regno))
/*
* Private jit_class bitmasks
*/
#define jit_class_named 0x00400000 /* hit must be the named reg */
#define jit_class_nospill 0x00800000 /* hint to fail if need spill */
#define jit_class_sft 0x01000000 /* not a hardware register */
#define jit_class_rg8 0x04000000 /* x86 8 bits */
#define jit_class_xpr 0x80000000 /* float / vector */
#define jit_regno_patch 0x00008000 /* this is a register
* returned by a "user" call
* to jit_get_reg() */
#define jit_call_default 0
#define jit_call_varargs 1
#define jit_kind_register 1
#define jit_kind_code 2
#define jit_kind_word 3
#define jit_kind_float32 4
#define jit_kind_float64 5
#define jit_cc_a0_reg 0x00000001 /* arg0 is a register */
#define jit_cc_a0_chg 0x00000002 /* arg0 is modified */
#define jit_cc_a0_jmp 0x00000004 /* arg0 is a jump target */
#define jit_cc_a0_rlh 0x00000008 /* arg0 is a register pair */
#define jit_cc_a0_int 0x00000010 /* arg0 is immediate word */
#define jit_cc_a0_flt 0x00000020 /* arg0 is immediate float */
#define jit_cc_a0_dbl 0x00000040 /* arg0 is immediate double */
#define jit_cc_a1_reg 0x00000100 /* arg1 is a register */
#define jit_cc_a1_chg 0x00000200 /* arg1 is modified */
#define jit_cc_a1_int 0x00001000 /* arg1 is immediate word */
#define jit_cc_a1_flt 0x00002000 /* arg1 is immediate float */
#define jit_cc_a1_dbl 0x00004000 /* arg1 is immediate double */
#define jit_cc_a2_reg 0x00010000 /* arg2 is a register */
#define jit_cc_a2_chg 0x00020000 /* arg2 is modified */
#define jit_cc_a2_int 0x00100000 /* arg2 is immediate word */
#define jit_cc_a2_flt 0x00200000 /* arg2 is immediate float */
#define jit_cc_a2_dbl 0x00400000 /* arg2 is immediate double */
#define jit_regset_com(u, v) ((u) = ~(v))
#define jit_regset_and(u, v, w) ((u) = (v) & (w))
#define jit_regset_ior(u, v, w) ((u) = (v) | (w))
#define jit_regset_xor(u, v, w) ((u) = (v) ^ (w))
#define jit_regset_set(u, v) ((u) = (v))
#define jit_regset_cmp_ui(u, v) ((u) != (v))
#define jit_regset_set_ui(u, v) ((u) = (v))
#define jit_regset_set_p(set) (set)
#if DEBUG
# define jit_regset_clrbit(set, bit) \
(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)), \
(set) &= ~(1LL << (bit)))
# define jit_regset_setbit(set, bit) \
(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)), \
(set) |= 1LL << (bit))
# define jit_regset_tstbit(set, bit) \
(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)), \
(set) & (1LL << (bit)))
#else
# define jit_regset_clrbit(set, bit) ((set) &= ~(1LL << (bit)))
# define jit_regset_setbit(set, bit) ((set) |= 1LL << (bit))
# define jit_regset_tstbit(set, bit) ((set) & (1LL << (bit)))
#endif
#define jit_regset_new(set) ((set) = 0)
#define jit_regset_del(set) ((set) = 0)
extern unsigned long
jit_regset_scan1(jit_regset_t, jit_int32_t);
#define jit_reglive_setup() \
do { \
jit_regset_set_ui(_jitc->reglive, 0); \
jit_regset_set_ui(_jitc->regmask, 0); \
} while (0)
/*
* Types
*/
typedef union jit_data jit_data_t;
typedef struct jit_note jit_note_t;
typedef struct jit_line jit_line_t;
typedef struct jit_block jit_block_t;
typedef struct jit_value jit_value_t;
typedef struct jit_compiler jit_compiler_t;
typedef struct jit_function jit_function_t;
typedef struct jit_register jit_register_t;
#if __arm__
# if DISASSEMBLER
typedef struct jit_data_info jit_data_info_t;
# endif
#endif
union jit_data {
struct {
#if __BYTE_ORDER == __LITTLE_ENDIAN
jit_int32_t l;
jit_int32_t h;
#else
jit_int32_t h;
jit_int32_t l;
#endif
} q;
jit_word_t w;
jit_float32_t f;
jit_float64_t d;
jit_pointer_t p;
jit_node_t *n;
};
struct jit_note {
jit_uint8_t *code;
char *name;
jit_line_t *lines;
jit_word_t length;
jit_word_t size; /* of code */
};
struct jit_line {
char *file;
jit_int32_t *linenos;
jit_int32_t *offsets;
jit_word_t length;
};
struct jit_node {
jit_node_t *next;
jit_code_t code;
jit_int32_t flag;
jit_data_t u;
jit_data_t v;
jit_data_t w;
jit_node_t *link;
};
struct jit_block {
jit_node_t *label;
jit_regset_t reglive;
jit_regset_t regmask;
};
struct jit_value {
jit_int32_t kind;
jit_code_t code;
jit_data_t base;
jit_data_t disp;
};
typedef struct {
#if __arm__
jit_word_t kind;
#endif
jit_word_t inst;
jit_node_t *node;
} jit_patch_t;
#if __arm__ && DISASSEMBLER
struct jit_data_info {
jit_uword_t code; /* pointer in code buffer */
jit_word_t length; /* length of constant vector */
};
#endif
struct jit_function {
struct {
jit_int32_t argi;
jit_int32_t argf;
jit_int32_t size;
jit_int32_t aoff;
jit_int32_t alen;
jit_int32_t call;
} self;
struct {
jit_int32_t argi;
jit_int32_t argf;
jit_int32_t size;
jit_int32_t call;
} call;
jit_node_t *prolog;
jit_node_t *epilog;
jit_int32_t *regoff;
jit_regset_t regset;
jit_int32_t stack;
};
/* data used only during jit generation */
struct jit_compiler {
jit_node_t *head;
jit_node_t *tail;
jit_uint32_t done : 1; /* emit state finished */
jit_uint32_t emit : 1; /* emit state entered */
jit_uint32_t again : 1; /* start over emiting function */
jit_uint32_t prepare : 1; /* inside prepare/finish* block */
jit_int32_t reglen; /* number of registers */
jit_regset_t regarg; /* cannot allocate */
jit_regset_t regsav; /* automatic spill only once */
jit_regset_t reglive; /* known live registers at some point */
jit_regset_t regmask; /* register mask to update reglive */
mpz_t blockmask; /* mask of visited basic blocks */
struct {
jit_uint8_t *end;
} code;
struct {
jit_node_t **table; /* very simple hash table */
jit_word_t size; /* number of vectors in table */
jit_word_t count; /* number of hash table entries */
jit_word_t offset; /* offset in bytes in ptr */
} data;
jit_node_t **spill;
jit_int32_t *gen; /* ssa like "register version" */
jit_value_t *values; /* temporary jit_value_t vector */
struct {
jit_block_t *ptr;
jit_word_t offset;
jit_word_t length;
} blocks; /* basic blocks */
struct {
jit_patch_t *ptr;
jit_word_t offset;
jit_word_t length;
} patches; /* forward patch information */
jit_function_t *function; /* current function */
struct {
jit_function_t *ptr;
jit_word_t offset;
jit_word_t length;
} functions; /* prolog/epilogue offsets in code */
struct {
jit_node_t **ptr;
jit_word_t offset;
jit_word_t length;
} pool;
jit_node_t *list;
struct {
jit_node_t *head; /* first note node */
jit_node_t *tail; /* linked list insertion */
/* fields to store temporary state information */
jit_word_t size;
jit_node_t *name;
jit_node_t *note;
jit_uint8_t *base;
} note;
#if __arm__
# if DISASSEMBLER
struct {
jit_data_info_t *ptr;
jit_word_t offset;
jit_word_t length;
} data_info; /* constant pools information */
# endif
/* Note that this field is somewhat hackish, but required by most
* ways to implement jit, unless implementing a pure one function
* per jit, as most times it needs to start the jit buffer with a
* jump where the "main" prolog starts, and because the initial
* code is in "arm mode", need to make an "arm mode" patch on that
* jump. A good example is the test suite assembler, where most
* test cases start with a "jmpi main" call. */
jit_uword_t thumb;
struct {
jit_uint8_t *data; /* pointer to code */
jit_word_t size; /* size data */
jit_word_t offset; /* pending patches */
jit_word_t length; /* number of pending constants */
jit_int32_t values[1024]; /* pending constants */
jit_word_t patches[2048];
} consts;
#endif
};
#define _jitc _jit->comp
struct jit_state {
union {
jit_uint8_t *uc;
jit_uint16_t *us;
jit_uint32_t *ui;
jit_uint64_t *ul;
jit_word_t w;
} pc;
struct {
jit_uint8_t *ptr;
jit_word_t length;
} code;
struct {
jit_uint8_t *ptr;
jit_word_t length;
} data;
struct {
jit_note_t *ptr;
jit_word_t length;
} note;
jit_compiler_t *comp;
};
struct jit_register {
jit_reg_t spec;
char *name;
};
/*
* Prototypes
*/
extern void jit_get_cpu(void);
#define jit_init() _jit_init(_jit)
extern void _jit_init(jit_state_t*);
#define jit_new_node_no_link(u) _jit_new_node_no_link(_jit, u)
extern jit_node_t *_jit_new_node_no_link(jit_state_t*, jit_code_t);
#define jit_link_node(u) _jit_link_node(_jit, u)
extern void _jit_link_node(jit_state_t*, jit_node_t*);
#define jit_link_label(l) _jit_link_label(_jit,l)
extern void
_jit_link_label(jit_state_t*,jit_node_t*);
#define jit_reglive(node) _jit_reglive(_jit, node)
extern void
_jit_reglive(jit_state_t*, jit_node_t*);
#define jit_regarg_set(n,v) _jit_regarg_set(_jit,n,v)
extern void
_jit_regarg_set(jit_state_t*, jit_node_t*, jit_int32_t);
#define jit_regarg_clr(n,v) _jit_regarg_clr(_jit,n,v)
extern void
_jit_regarg_clr(jit_state_t*, jit_node_t*, jit_int32_t);
#define jit_get_reg(s) _jit_get_reg(_jit,s)
extern jit_int32_t
_jit_get_reg(jit_state_t*, jit_int32_t);
#define jit_unget_reg(r) _jit_unget_reg(_jit,r)
extern void
_jit_unget_reg(jit_state_t*, jit_int32_t);
#define jit_save(reg) _jit_save(_jit, reg)
extern void
_jit_save(jit_state_t*, jit_int32_t);
#define jit_load(reg) _jit_load(_jit, reg)
extern void
_jit_load(jit_state_t*, jit_int32_t);
#define jit_optimize() _jit_optimize(_jit)
extern void
_jit_optimize(jit_state_t*);
#define jit_classify(code) _jit_classify(_jit, code)
extern jit_int32_t
_jit_classify(jit_state_t*, jit_code_t);
#define jit_regarg_p(n, r) _jit_regarg_p(_jit, n, r)
extern jit_bool_t
_jit_regarg_p(jit_state_t*, jit_node_t*, jit_int32_t);
#define emit_code() _emit_code(_jit)
extern jit_pointer_t
_emit_code(jit_state_t*);
#define emit_ldxi(r0, r1, i0) _emit_ldxi(_jit, r0, r1, i0)
extern void
_emit_ldxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
#define emit_stxi(i0, r0, r1) _emit_stxi(_jit, i0, r0, r1)
extern void
_emit_stxi(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
#define emit_ldxi_d(r0, r1, i0) _emit_ldxi_d(_jit, r0, r1, i0)
extern void
_emit_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
#define emit_stxi_d(i0, r0, r1) _emit_stxi_d(_jit, i0, r0, r1)
extern void
_emit_stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
extern void jit_init_debug(void);
extern void jit_finish_debug(void);
extern void jit_init_note(void);
extern void jit_finish_note(void);
#define jit_set_note(n,u,v,w) _jit_set_note(_jit, n, u, v, w)
extern void _jit_set_note(jit_state_t*, jit_note_t*, char*, int, jit_int32_t);
#define jit_get_note(n,u,v,w) _jit_get_note(_jit, n, u, v, w)
extern jit_bool_t _jit_get_note(jit_state_t*,jit_uint8_t*,char**,char**,int*);
#define jit_annotate() _jit_annotate(_jit)
extern void _jit_annotate(jit_state_t*);
/*
* Externs
*/
extern jit_register_t _rvs[];
extern const char *jit_progname;
#endif /* _jit_private_h */