mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 04:10:18 +02:00
* 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.
478 lines
13 KiB
C
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 */
|