view release on metacpan or search on metacpan
libjit/ChangeLog view on Meta::CPAN
* jit/jit-dump.c (jit_dump_insn): Print the destination value for
the address_of_label opcode.
2010-11-07 Klaus Treichel <ktreichel@web.de>
* jit/jit-cache.h: Fix comment for _jit_cache_get_end_method.
2010-10-24 Klaus Treichel <ktreichel@web.de>
* jit/jit-reg-alloc.c (_jit_regs_alloc_global): Set in_global_register
on global register assignment.
2010-10-04 Klaus Treichel <ktreichel@web.de>
* jit/jit-internal.h: Add missing typedef in the declaration of the
_jit_intrinsic_signature enumaeration. (Really Noah Lavine)
2010-09-21 Klaus Treichel <ktreichel@web.de>
* config/jit-opcodes.ops: Add definitions for the opcode's
intrinsics.
libjit/ChangeLog view on Meta::CPAN
2008-07-06 Klaus Treichel <ktreichel@web.de>
* jit/jit-rules-x86-64.ins: Replace the check if an immediate value
is a signed 32bit value by using an if clause the new imms32 clause.
Flag rules for branch opcodes with the branch option and add the
commutative option where appropriate.
2008-07-06 Juan Jesus Garcia de Soria <juanj.g_soria@grupobbva.com>
* jit/jit-reg-alloc.c (choose_input_order): take into account global
registers to see if it is suitable to exchange input values. This
fixes a problem that took place when a commutative op is applied to
a value that resides in a global register and is both the dest and
the second source value of the op.
2008-05-30 Aleksey Demakov <ademakov@gmail.com>
* include/jit/jit-common.h: remove unused jit_function_compiled_t
type.
* include/jit/jit-except.h, include/jit/jit-common.h: move
JIT_NO_OFFSET from jit-except.h to jit-common.h.
libjit/ChangeLog view on Meta::CPAN
register class which means all registers in the class are clobbered.
Remove "only", "spill_before", "unary", and "binary" keywords.
Replace "unary_note" and "binary_note" with "note". Also replace
"unary_branch" and "binary_branch" with "branch".
* jit/jit-rules-alpha.ins, jit/jit-rules-x86.ins: update according
to the new rule syntax.
2006-12-20 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-thread.h, jit/jit-thread.c: add _jit_global_lock mutex.
* jit/jit-init.c (jit_init): make sure that initialization is done
only once.
2006-12-17 Klaus Treichel <ktreichel@web.de>
* include/jit/jit-function.h, jit/jit-function.c: Add the function
jit_function_from_vtable_pointer to convert a vtable pointer back to
the jit_function_t.
2006-11-29 Aleksey Demakov <ademakov@gmail.com>
libjit/ChangeLog view on Meta::CPAN
(JIT_OP_THROW, JIT_OP_LOAD_PC): add position_independent check and
stub missing cases.
2006-11-26 Kirill Kononenko <Kirill.Kononenko@gmail.com>
* jit/jit-rules-x86.ins: if JIT_USE_SIGNALS is defined do not emit
explicit division by zero check (patch #5278).
2006-11-26 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (choose_output_register): fix global register
use cost computation.
* jit/jit-rules-x86.ins: mark as commutative JIT_OP_IADD,
JIT_OP_IMUL, JIT_OP_LADD, JIT_OP_IAND, JIT_OP_IOR, JIT_OP_IXOR,
JIT_OP_LAND, JIT_OP_LOR, JIT_OP_XOR rules.
2006-11-25 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (exch_stack_top, free_value): fix freeing
stack registers.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-rules-alpha.c jit/jit-rules-alpha.ins Properly handle
fixups on alpha. Implement JIT_OP_CALL_EXTERNAL for alpha.
2006-07-29 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (use_cheapest_register): allow a register that
contains an input value to be used as a scratch register. The input
value in this case is copied to another register. This resolves the
problem with JIT_OP_IREM rule that failed to allocate a scratch reg
in a very specific case (all EBX, ESI, EDI regs are used as global,
dividend is initially in ECX and copied to EAX:EDX pair where x86
idiv expects it to be).
* jit/jit-reg-alloc.c (set_regdesc_flags): fix a bug.
2006-07-23 Thomas Cort <linuxgeek@gmail.com>
* jit/jit-apply-alpha.c jit/jit-apply-alpha.h jit/jit-apply-func.h
jit/jit-gen-alpha.h jit/jit-rules-alpha.c jit/jit-rules-alpha.h
jit/jit-rules-alpha.ins Implement the redirector for alpha.
libjit/ChangeLog view on Meta::CPAN
block.
* jit/jit-reg-alloc.c (_jit_regs_begin, _jit_regs_end): add
convenience functions.
* tools/gen-rules-parser.y (gensel_output_clauses): make generated
code more readable by using _jit_regs_begin() and _jit_regs_end()
where appropriate.
* jit/jit-reg-alloc.c: allow to load the second part of a register
pair to a global register. This is because x86 long arithmetics
use 4 registers at once: EAX:EDX and ECX:EBX. At the same time
EBX is the global register candidate. If the instruction clobbers
the global register, the new allocator automatically pushes it on
the stack before and pops after the instruction.
* jit/jit-function.c (compile_block): modify trace messages.
2006-05-28 Klaus Treichel <ktreichel@web.de>
* jit/jit-insn.c: Add a code_label in initialize_setjmp_block just
before the end_label that is moved with the block to the start of
the function as jump target to the code. Otherwise other blocks
moved to the start after this block will never be executed.
2006-05-27 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (free_value, save_value): the value that has
a global register and is also associated with a local register
needs to be unbound from the local one.
* jit/jit-reg-alloc.c (compute_spill_cost): assume that the spill
cost for clean values is not zero. This keeps them in registers
as long as there are free registers and thus reduces the number of
loads.
2006-05-25 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (use_cheapest_register): fix cost calculation
again for 'spill_before' rules. The last patch did not work for
values stored in global registers. Now both global and non-global
values should be copied to EAX.
2006-05-25 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (use_cheapest_register): fix cost calculation
that sometimes caused overlooking free registers. This was a serious
problem as there are some 'spill_before' rules that assume that the
allocator will always choose EAX as the first free register.
2006-05-21 Aleksey Demakov <ademakov@gmail.com>
libjit/ChangeLog view on Meta::CPAN
_jit_regs_assign() time. Uniformly save input values that need to
in _jit_regs_gen(), do not save them in _jit_regs_commit(). This
simplifies handling of stack registers. Remove initial_stack_top,
exchanges, num_exchages fields from the _jit_regs_t struct. Add
save and kill bit fields to the _jit_regdesc_t struct. Refactor
and clean up code.
2006-05-10 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (use_cheapest_register): check if the other
part of a register pair clobbers global registers.
* jit/jit-reg-alloc.c (exch_stack_top): run value exchange loop
for all values in both registers.
* jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: delete on_stack field
from the _jit_regdesc_t struct.
* jit/jit-reg-alloc.c (_jit_regs_gen): handle instructions that have
both stack and flat registers.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-internal.h (struct _jit_builder):
* jit/jit-function.c (compile_block, jit_function_compile): add
some tracing.
* jit/jit-rules.h:
* jit/jit-rules-arm.c:
* jit/jit-rules-interp.c:
* jit/jit-rules-x86.c: add _jit_gen_exch_top and _jit_gen_spill_top
functions used by new allocator to handle stack registers. Add reg
argument to _jit_gen_spill_global and_jit_gen_load_global
functions.
2006-04-11 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-insn.c (jit_insn_start_catcher): initialize
thrown_exception (the problem was found by Klaus).
2006-04-08 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-opcode.c: add jump table into jit_opcodes array.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-rules-x86.c (_jit_create_call_return_insns): fix return
code in case of no return value or struct returned via pointer.
2006-02-19 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.h:
* jit/jit-reg-alloc.c: Initial version of new local register
allocator.
* jit/jit-rules.h:
* jit/jit-rules-arm.c (_jit_gen_spill_global):
* jit/jit-rules-interp.c (_jit_gen_spill_global):
* jit/jit-rules-x86.c (_jit_gen_spill_global): add function for
spilling global registers. Used by the new allocator. Only x86
version is really implemented.
2006-02-13 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-internal.h (struct _jit_value): add index field.
* jit/jit-value.c (alloc_value): initialize index field;
* jit/Makefile.am (libjit_la_SOURCES): add jit-bitset.c and jit-cfg.c.
2006-02-12 Aleksey Demakov <ademakov@gmail.com>
libjit/ChangeLog view on Meta::CPAN
* doc/libjit.texi, jit/jit-insn.c, jit/jit-internal.h,
jit/jit-reg-alloc.c, jit/jit-rules-arm.c, jit/jit-rules-arm.sel,
jit/jit-rules-interp.c, jit/jit-rules-x86.c, jit/jit-rules-x86.sel,
jit/jit-rules.h, jit/jit-value.c, tutorial/Makefile.am,
tutorial/t2.c, tutorial/t5.c: implement tail calls from a
function to itself.
* jit/jit-function.c, jit/jit-reg-alloc.c, jit/jit-rules-arm.c,
jit/jit-rules-interp.c, jit/jit-rules-x86.c, jit/jit-rules.h:
implement global register allocation for parameters in stack slots.
* jit/jit-rules-x86.c, jit/jit-rules-x86.sel, jit/jit-rules.h:
optimize the x86 function epilog when we are certain that the
stack height doesn't change between entry and exit (i.e. the
function is a leaf and there are no alloca's).
2004-06-10 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-apply-arm.c, jit/jit-gen-arm.c, jit/jit-gen-arm.h,
jit/jit-rules-arm.c, jit/jit-rules-arm.h, jit/jit-rules-arm.sel,
libjit/ChangeLog view on Meta::CPAN
include/jit/jit-plus.h, jit/jit-insn.c, jit/jit-internal.h,
jit/jit-interp.c, jit/jit-opcode.c, jit/jit-rules-arm.c,
jit/jit-rules-arm.sel, jitplus/jit-plus-function.cpp:
add support for outgoing parameter areas, which should reduce
the overhead of function calls that involve stacked arguments
on non-x86 platforms; use parameter areas in the ARM back end.
* include/jit/jit-plus.h, include/jit/jit-value.h, jit/jit-insn.c,
jit/jit-internal.h, jit/jit-reg-alloc.c, jit/jit-rules-x86.c,
jit/jit-value.c: don't over-allocate x86 stack frames if
EBX, ESI, and EDI don't need to be saved; don't perform global
register allocation on stacked parameters because it confuses
the register spill logic.
* jit/jit-reg-alloc.c (_jit_regs_load_value): avoid unnecessary
spills if a temporary value won't be used again in the current block.
2004-06-09 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-rules-arm.c (flush_constants): update the instruction
location after flushing the constant table.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-gen-arm.h (arm_call): use a more efficient form of
call for offsets beyond the simple target range.
* jit/jit-rules-arm.sel, tools/gen-sel-parser.y,
tools/gen-sel-scanner.l: introduce conditional rules into "gen-sel"
so that we can disable certain rules on ARM platforms that lack
floating-point support.
* jit/jit-rules-arm.c (_jit_gen_spill_reg): spill properly to
global registers for ARM.
* jit/jit-reg-alloc.c, jit/jit-rules-arm.c, jit/jit-rules-arm.sel,
jit/jit-rules-x86.sel: minor register assignment bugs.
* jit/jit-rules-arm.c: ARM parameters cannot be split between
registers and the stack.
* jit/jit-gen-arm.c, jit/jit-gen-arm.h, jit/jit-rules-arm.c,
jit/jit-rules-arm.h, jit/jit-rules-arm.sel: implement a
constant pool for ARM, which gets complicated constants out
libjit/ChangeLog view on Meta::CPAN
jit/jit-rules-arm.sel, jit/jit-rules-x86.c, jit/jit-rules-x86.sel:
add some more instructions to the ARM back end; split some x86
back end code out into common code for ARM to use as well.
2004-06-02 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-function.c, jit/jit-insn.c, jit/jit-internal.h,
jit/jit-reg-alloc.c, jit/jit-reg-alloc.h, jit/jit-rules-arm.c,
jit/jit-rules-arm.h, jit/jit-rules-interp.c, jit/jit-rules-interp.h,
jit/jit-rules-x86.c, jit/jit-rules-x86.h, jit/jit-rules.h,
jit/jit-value.c, tools/gen-sel-parser.y: implement a simple global
register allocation policy, based on usage counts.
* jit/jit-reg-alloc.c (_jit_regs_load_value): if a value is in a
global register and it is not going to be destroyed by an instruction,
then use the global register as the operand.
* jit/jit-insn.c: recognise "t = a op b; a = t" and turn it
into "a = a op b" to make it easier for back ends to recognise
special idioms such as increments and decrements.
2004-06-01 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-cache.c, jit/jit-elf-read.c, tools/gen-apply.c:
fix some gcc 3.x compile warnings.
libjit/ChangeLog view on Meta::CPAN
2004-05-11 Rhys Weatherley <rweather@southern-storm.com.au>
* include/jit/jit-insn.h, jit/jit-insn.c, jit/jit-interp.cpp,
jit/jit-interp.h, jit/jit-opcode.c, jit/jit-rules-interp.c:
round out the function call handling opcodes for the interpreter.
* jit/jit-rules-interp.c, jit/jit-rules-interp.h: implement
the exception-handling opcodes for the interpreter.
* dpas/dpas-parser.y, dpas/dpas-scope.c, dpas/dpas-scope.h:
fix a bug that caused global variables in Dynamic Pascal
to be incorrectly allocated as locals.
* jit/jit-reg-alloc.c (_jit_regs_load_to_top_two): handle the
case where the second value is on the stack but not the first.
* dpas/dpas-parser.y, dpas/dpas-types.c, dpas/dpas-types.h:
report errors for unimplemented expressions and statements,
so that users are not "surprised" when things silently fail.
* .cvsignore, auto_gen.sh, configure.in, doc/.cvsignore,
libjit/NEWS view on Meta::CPAN
* Add jit_insn_mark_breakpoint_variable function (Radek Polak).
* Add signal handlers (Kirill Kononenko).
* Add JIT_OPTION_POSITION_INDEPENDENT context option (not supported
by the backends yet) (Aleksey Demakov).
* Add function indirectors (Klaus Treichel).
* Allocate function redirectors and indirectors in the code cache
(Aleksey Demakov).
* Use mmap to allocate executable memory where available
(Klaus Treichel).
* Now can dump to any stream not just stdout and stderr (Radek Polak).
* Use a global lock during context initialization (Aleksey Demakov).
* Fix problems that take place after compilation is restarted on cache
page overflow (Aleksey Demakov).
Register allocation/instruction selection improvements (Aleksey Demakov):
* Completely rewrite register allocator. The new allocator works with
three-value intermediate instructions rather than with individual
values. This allows to fully analyze the effect of the instruction
and makes it possible to optimize commutative instructions and
eliminate in some cases redundant register spills and loads.
* Support three-address architectures.
* Add register classes.
* The allocator may now allocate scratch registers for instructions.
* The allocator now automatically handles cases when a global register
is clobbered by the instruction (which may happen on the register
constrained x86 architecture).
* Implement value coalescing for copy instructions.
* Provide for efficient handling of x87 floating point stack.
* Add gen-rules program that supersedes gen-sel. It generates code for
new register allocator and extends the syntax of instruction selection
rules to make use of new features such as register classes, scratch
registers, etc.
Alpha:
libjit/NEWS view on Meta::CPAN
* Don't allow conditional branches to jump out of exception contexts.
* Block movement to allow initialization code to be moved to the start
of a function, or loop condition code to be moved to the end.
* Rewrite the exception region routines to make them easier to use.
* Add the "gen-sel" program, for creating instruction selectors.
* Write instruction selectors for x86 and ARM (only x86 is enabled).
* Portability fixes for ARM, PPC, Alpha, IA64, and amd64.
* Clarify the description of LLVM, at the request of LLVM's author.
* Deferred argument popping after function calls.
* Add "--enable-interpreter" to force the interpreter to be used.
* Implement a simple global register allocator based on usage counts.
* Recognise increment and decrement idioms.
* Align cache flushes properly (Miroslaw Dobrzanski-Neumann).
* Querying of x86 cpuid where necessary.
* Add a constant pool for ARM, to make constant loads more efficient.
* Handle register pairs for 64-bit values properly.
* Support for parameter areas on the stack, to reduce push/pop overhead.
* Avoid unnecessary register spills if a value won't be used again.
* Implement tail calls from a function to itself.
* Optimize x86 prologs and epilogs to avoid doing unnecessry work.
* Centralise the code that handles parameter passing.
libjit/TODO view on Meta::CPAN
Target release: 0.1.4
=====================
* CFG-based liveness analysis and dead code elimination
* global copy and constant propagation
* jitruby (in case copyright issues are resolved)
* sync jitplus with jit (jump tables, compile driver, debug)
* fix catch/throw within finally
* get rid of manual rules
* add direct conversion opcodes to/from float32 and float64
* add rounding towards zero
* try to be smarter with %rax for variadic functions on x86-64
Target Release: 0.2.0
=====================
libjit/attic/jit-apply-alpha.c view on Meta::CPAN
#include "jit-internal.h"
#if defined(__alpha) || defined(__alpha__)
#include "jit-gen-alpha.h"
void _jit_create_closure(unsigned char *buf, void *func, void *closure, void *_type) {
alpha_inst inst = (alpha_inst) buf;
/* Compute and load the global pointer (2 instructions) */
alpha_ldah(inst,ALPHA_GP,ALPHA_PV,0);
alpha_lda( inst,ALPHA_GP,ALPHA_GP,0);
/* Allocate space for a new stack frame. (1 instruction) */
alpha_lda(inst,ALPHA_SP,ALPHA_SP,-(13*8));
/* Save the return address. (1 instruction) */
alpha_stq(inst,ALPHA_RA,ALPHA_SP,0*8);
/* Save integer register arguments as local variables (6 instructions) */
libjit/attic/jit-apply-alpha.c view on Meta::CPAN
alpha_stt(inst,ALPHA_FS2,ALPHA_SP,10*8);
alpha_stt(inst,ALPHA_FS3,ALPHA_SP,11*8);
alpha_stt(inst,ALPHA_FS4,ALPHA_SP,12*8);
alpha_stt(inst,ALPHA_FS5,ALPHA_SP,13*8);
alpha_stt(inst,ALPHA_FS6,ALPHA_SP,14*8);
alpha_stt(inst,ALPHA_FS7,ALPHA_SP,15*8);
/* Set the frame pointer (1 instruction) */
alpha_mov(inst,ALPHA_SP,ALPHA_FP);
/* Compute and load the global pointer (2 instructions) */
alpha_ldah(inst,ALPHA_GP,ALPHA_PV,0);
alpha_lda( inst,ALPHA_GP,ALPHA_GP,0);
/* Force any pending hardware exceptions to be raised. (1 instruction) */
alpha_trapb(inst);
/* Call the redirector handling function (6 instruction) */
alpha_call(inst, func);
/* Restore the return address. (1 instruction) */
libjit/attic/jit-rules-alpha.c view on Meta::CPAN
*
* This function is called at the end of the code generation process,
* not the beginning. At this point, it is known which callee save
* registers must be preserved, allowing the back end to output the
* most compact prolog possible.
*/
void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf) {
unsigned int prolog[JIT_PROLOG_SIZE];
alpha_inst inst = prolog;
/* Compute and load the global pointer (2 instruction) */
alpha_ldah(inst,ALPHA_GP,ALPHA_PV,0);
alpha_lda( inst,ALPHA_GP,ALPHA_GP,0);
/* Allocate space for a new stack frame. (1 instruction) */
alpha_lda(inst,ALPHA_SP,ALPHA_SP,-(2*8));
/* Save the return address. (1 instruction) */
alpha_stq(inst,ALPHA_RA,ALPHA_SP,0*8);
/* Save the frame pointer. (1 instruction) */
libjit/attic/jit-rules-alpha.c view on Meta::CPAN
}
void _jit_gen_move_top(jit_gencode_t gen, int reg) {
/* not used by alpha */;
}
void _jit_gen_spill_top(jit_gencode_t gen, int reg, jit_value_t value, int pop) {
/* not used by alpha */;
}
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value) {
/* not used by alpha */;
}
/*
* Generate instructions to spill a pseudo register to the local variable frame. If
* other_reg is not -1, then it indicates the second register in a 64-bit register pair.
*
* This function will typically call _jit_gen_fix_value to fix the value's frame
* position, and will then generate the appropriate spill instructions.
*/
void _jit_gen_spill_reg(jit_gencode_t gen, int reg, int other_reg, jit_value_t value) {
int offset;
/* Make sure that we have sufficient space */
jit_cache_setup_output(32);
/* If the value is associated with a global register, then copy to that */
if (value->has_global_register) {
alpha_mov(inst,_jit_reg_info[reg].cpu_reg,_jit_reg_info[value->global_reg].cpu_reg);
jit_cache_end_output();
return;
}
/* Fix the value in place within the local variable frame */
_jit_gen_fix_value(value);
/* Output an appropriate instruction to spill the value */
offset = (int)(value->frame_offset);
libjit/attic/jit-rules-alpha.c view on Meta::CPAN
switch(opcode) {
#define JIT_INCLUDE_SUPPORTED
#include "jit-rules-alpha.inc"
#undef JIT_INCLUDE_SUPPORTED
}
return 0;
}
/*
* Determine if type is a candidate for allocation within global registers.
*/
int _jit_gen_is_global_candidate(jit_type_t type) {
switch(jit_type_remove_tags(type)->kind) {
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_NINT:
case JIT_TYPE_NUINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE:
return 1;
}
libjit/attic/jit-rules-alpha.c view on Meta::CPAN
case JIT_TYPE_FLOAT32:
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
break;
*/
default:
break;
}
} else if (value->in_register || value->in_global_register) {
/* mov from value->reg to _jit_reg_info[reg].cpu_reg */
alpha_mov(inst,value->reg,_jit_reg_info[reg].cpu_reg);
} else {
/* Fix the position of the value in the stack frame */
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
libjit/attic/jit-rules-alpha.c view on Meta::CPAN
case JIT_TYPE_FLOAT32:
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
break;
}
}
jit_cache_end_output();
}
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value) {
TODO();
}
/*
* Generate code for a redirector, which makes an indirect jump to the contents of
* func->entry_point. Redirectors are used on recompilable functions in place of the
* regular entry point. This allows libjit to redirect existing calls to the new
* version after recompilation.
*/
libjit/attic/jit-rules-alpha.h view on Meta::CPAN
{ "fe5", 27, -1, JIT_REG_FIXED}, \
{ "fe6", 28, -1, JIT_REG_FIXED}, \
{ "fe7", 29, -1, JIT_REG_FIXED}, \
{ "fe8", 30, -1, JIT_REG_FIXED}, \
{"fzero", 31, -1, JIT_REG_FIXED},
/* 32 floating-point registers + 32 integer registers */
#define JIT_NUM_REGS 64
/*
* The number of registers that are used for global register
* allocation. Set to zero if global register allocation should not be
* used.
*/
#define JIT_NUM_GLOBAL_REGS 14
/*
* Define to 1 if we should always load values into registers
* before operating on them. i.e. the CPU does not have reg-mem
* and mem-reg addressing modes.
*
* The maximum number of operands for an alpha instruction is 3,
libjit/doc/mangling_rules.txt view on Meta::CPAN
GCC 2.95.3 name mangling grammar (intuited from gcc sources):
------------------------------------------------------------
<global-function> ::= <name> '__F' <func-params>
<member-function> ::= <name> '__' <class-name> <func-params>
<ctor-function> ::= '__' <class-name> <func-params>
<dtor-function> ::= '_' <joiner> '_' <class-name> <func-params>
<joiner> ::= '.' | '$' # system-dependent joiner
<class-name> ::= <qualified-name>
libjit/doc/mangling_rules.txt view on Meta::CPAN
<pointer-to-member-type> ::= M </class/ type> </member/ type>
<template-param> ::= T </parameter/ number> _
<template-template-param> ::= <template-param>
::= <substitution>
MSVC 6.0 name mangling rules (determined by trial and error):
------------------------------------------------------------
<global-function> ::= '?' <name> '@@Y' <callconv> <return-type> <parameters>
<member-function> ::= '?' <name> '@' <class-name> '@@' <access>
[<const>] <callconv> <return-type> <parameters>
<ctor-function> ::= '??0' <class-name> '@@' <access> <const> <callconv>
'@' <parameters>
<dtor-function> ::= '??1' <class-name> '@@' <access> <const> <callconv>
'@' <parameters>
libjit/dpas/dpas-internal.h view on Meta::CPAN
void dpas_error_on_line(const char *filename, long linenum,
const char *format, ...);
/*
* Get the JIT context that we are using to compile functions.
*/
jit_context_t dpas_current_context(void);
/*
* Get the current function that is being compiled. Returns NULL
* if we are currently at the global level.
*/
jit_function_t dpas_current_function(void);
/*
* Create a new function and push it onto the context stack.
* The function is initialized to read parameters that are
* compatible with the supplied signature.
*/
jit_function_t dpas_new_function(jit_type_t signature);
libjit/dpas/dpas-parser.y view on Meta::CPAN
{
dpas_out_of_memory();
}
dpas_scope_add(dpas_scope_current(),
$1.list[posn], $3,
DPAS_ITEM_VARIABLE, value, 0,
dpas_filename, dpas_linenum);
}
else
{
/* Allocate some memory to hold the global data */
void *space = jit_calloc(1, jit_type_get_size($3));
if(!space)
{
dpas_out_of_memory();
}
dpas_scope_add(dpas_scope_current(),
$1.list[posn], $3,
DPAS_ITEM_GLOBAL_VARIABLE, space, 0,
dpas_filename, dpas_linenum);
}
libjit/dpas/dpas-scope.c view on Meta::CPAN
{
/* Search through the "with" items for a field match */
if(check_with)
{
item = scope->first_with;
if(!item)
{
/* We are exiting from the top-most "with" scope
in the current procedure. Ignore the rest of
the "with" scopes on the stack because we only
care about local/global variables from now on */
check_with = 0;
}
while(item != 0)
{
if(dpas_type_find_name(item->type, name) != JIT_INVALID_NAME)
{
return item;
}
item = item->next;
}
libjit/dpas/dpas-scope.c view on Meta::CPAN
{
return item->linenum;
}
int dpas_scope_level(dpas_scope_t scope)
{
return scope->level;
}
/*
* The global and current scopes.
*/
static dpas_scope_t global_scope = 0;
static dpas_scope_t current_scope = 0;
dpas_scope_t dpas_scope_current(void)
{
if(!current_scope)
{
/* Create the global scope for the first time */
global_scope = dpas_scope_create(0);
/* Create a wrapper around the global scope to contain
the program-private definitions. This allows the
program to override the global scope if it wants to */
current_scope = dpas_scope_create(global_scope);
}
return current_scope;
}
dpas_scope_t dpas_scope_global(void)
{
if(!current_scope)
{
dpas_scope_current();
}
return global_scope;
}
dpas_scope_t dpas_scope_push(void)
{
current_scope = dpas_scope_create(dpas_scope_current());
return current_scope;
}
void dpas_scope_pop(void)
{
dpas_scope_t scope = dpas_scope_current();
if(scope->parent && scope->parent != global_scope)
{
current_scope = scope->parent;
dpas_scope_destroy(scope);
}
}
int dpas_scope_is_module(void)
{
return (dpas_scope_current()->parent == dpas_scope_global());
}
libjit/dpas/dpas-scope.h view on Meta::CPAN
*/
typedef struct dpas_scope *dpas_scope_t;
/*
* Opaque type that represents a scope item.
*/
typedef struct dpas_scope_item *dpas_scope_item_t;
/*
* Create a new scope, with a specified parent scope. If the parent
* scope is NULL, then this creates the global scope.
*/
dpas_scope_t dpas_scope_create(dpas_scope_t parent);
/*
* Destroy a scope that is no longer required.
*/
void dpas_scope_destroy(dpas_scope_t scope);
/*
* Look up a name within a scope. If "up" is non-zero, then also
libjit/dpas/dpas-scope.h view on Meta::CPAN
* Get the filename associated with a scope item.
*/
const char *dpas_scope_item_filename(dpas_scope_item_t item);
/*
* Get the line number associated with a scope item.
*/
long dpas_scope_item_linenum(dpas_scope_item_t item);
/*
* Get the level associated with the current scope (global is zero).
*/
int dpas_scope_level(dpas_scope_t scope);
/*
* Get the current scope.
*/
dpas_scope_t dpas_scope_current(void);
/*
* Get the global scope.
*/
dpas_scope_t dpas_scope_global(void);
/*
* Create a new scope and push into it.
*/
dpas_scope_t dpas_scope_push(void);
/*
* Pop the current scope level and destroy it.
*/
void dpas_scope_pop(void);
/*
* Determine if the current scope is the module-global scope.
*/
int dpas_scope_is_module(void);
#ifdef __cplusplus
};
#endif
#endif /* _DPAS_SCOPE_H */
libjit/dpas/dpas-types.c view on Meta::CPAN
jit_type_t dpas_type_boolean;
jit_type_t dpas_type_cboolean;
jit_type_t dpas_type_char;
jit_type_t dpas_type_string;
jit_type_t dpas_type_address;
jit_type_t dpas_type_nil;
jit_type_t dpas_type_size_t;
jit_type_t dpas_type_ptrdiff_t;
/*
* Register a predefined type within the global scope.
*/
static void register_type(const char *name, jit_type_t type)
{
dpas_scope_add(dpas_scope_global(), name, type, DPAS_ITEM_TYPE, 0, 0,
"(builtin)", 1);
}
/*
* Get an integer type of a specific size.
*/
static jit_type_t get_int_type(unsigned int size)
{
if(size == sizeof(jit_int))
{
libjit/dpas/dpas-types.c view on Meta::CPAN
register_type("SysLongestInt", jit_type_sys_longlong);
register_type("SysLongestCard", jit_type_sys_ulonglong);
register_type("SysLongestWord", jit_type_sys_ulonglong);
/*
* Register the "True" and "False" constants.
*/
value.type = dpas_type_boolean;
value.un.int_value = 1;
dpas_scope_add_const(dpas_scope_global(), "True", &value, "(builtin)", 1);
value.type = dpas_type_boolean;
value.un.int_value = 0;
dpas_scope_add_const(dpas_scope_global(), "False", &value, "(builtin)", 1);
}
unsigned int dpas_type_find_name(jit_type_t type, const char *name)
{
unsigned int field = jit_type_num_fields(type);
const char *fname;
while(field > 0)
{
--field;
fname = jit_type_get_name(type, field);
libjit/include/jit/jit-dynamic.h view on Meta::CPAN
#define JIT_MANGLE_PUBLIC 0x0001
#define JIT_MANGLE_PROTECTED 0x0002
#define JIT_MANGLE_PRIVATE 0x0003
#define JIT_MANGLE_STATIC 0x0008
#define JIT_MANGLE_VIRTUAL 0x0010
#define JIT_MANGLE_CONST 0x0020
#define JIT_MANGLE_EXPLICIT_THIS 0x0040
#define JIT_MANGLE_IS_CTOR 0x0080
#define JIT_MANGLE_IS_DTOR 0x0100
#define JIT_MANGLE_BASE 0x0200
char *jit_mangle_global_function
(const char *name, jit_type_t signature, int form) JIT_NOTHROW;
char *jit_mangle_member_function
(const char *class_name, const char *name,
jit_type_t signature, int form, int flags) JIT_NOTHROW;
#ifdef __cplusplus
};
#endif
#endif /* _JIT_DYNAMIC_H */
libjit/jit/jit-cfg.c view on Meta::CPAN
}
}
}
}
}
return 1;
}
static int
compute_global_live_sets(_jit_cfg_t cfg)
{
int change;
int index, succ_index;
_jit_node_t node;
_jit_node_t succ;
_jit_bitset_t bitset;
if(!_jit_bitset_allocate(&bitset, cfg->num_values))
{
return 0;
libjit/jit/jit-cfg.c view on Meta::CPAN
}
return cfg;
}
int
_jit_cfg_compute_liveness(_jit_cfg_t cfg)
{
return (create_value_entries(cfg)
&& compute_local_live_sets(cfg)
&& compute_global_live_sets(cfg));
}
libjit/jit/jit-compile.c view on Meta::CPAN
/* Generate code for the instruction with the back end */
_jit_gen_insn(gen, func, block, insn);
break;
#endif
case JIT_OP_INCOMING_FRAME_POSN:
/* Set the frame position for an incoming value */
insn->value1->frame_offset = jit_value_get_nint_constant(insn->value2);
insn->value1->in_register = 0;
insn->value1->has_frame_offset = 1;
if(insn->value1->has_global_register)
{
insn->value1->in_global_register = 1;
_jit_gen_load_global(gen, insn->value1->global_reg, insn->value1);
}
else
{
insn->value1->in_frame = 1;
}
break;
#ifndef JIT_BACKEND_INTERP
case JIT_OP_OUTGOING_REG:
/* Copy a value into an outgoing register */
_jit_regs_set_outgoing(gen,
(int)jit_value_get_nint_constant(insn->value2),
insn->value1);
break;
#endif
case JIT_OP_OUTGOING_FRAME_POSN:
/* Set the frame position for an outgoing value */
insn->value1->frame_offset = jit_value_get_nint_constant(insn->value2);
insn->value1->in_register = 0;
insn->value1->in_global_register = 0;
insn->value1->in_frame = 0;
insn->value1->has_frame_offset = 1;
insn->value1->has_global_register = 0;
break;
#ifndef JIT_BACKEND_INTERP
case JIT_OP_RETURN_REG:
/* Assign a register to a return value */
_jit_regs_set_incoming(gen,
(int)jit_value_get_nint_constant(insn->value2),
insn->value1);
/* Generate code for the instruction with the back end */
_jit_gen_insn(gen, func, block, insn);
libjit/jit/jit-compile.c view on Meta::CPAN
}
/*
* Reset value on codegen restart.
*/
static void
reset_value(jit_value_t value)
{
value->reg = -1;
value->in_register = 0;
value->in_global_register = 0;
value->in_frame = 0;
}
/*
* Clean up the compilation state on codegen restart.
*/
static void
cleanup_on_restart(jit_gencode_t gen, jit_function_t func)
{
jit_block_t block;
libjit/jit/jit-compile.c view on Meta::CPAN
if(func->builder->parent_frame)
{
reset_value(func->builder->parent_frame);
}
/* Reset the "touched" registers mask. The first time compilation
might have followed wrong code paths and thus allocated wrong
registers. */
if(func->builder->has_tail_call)
{
/* For functions with tail calls _jit_regs_alloc_global()
does not allocate any global registers. The "permanent"
mask has all global registers set to prevent their use. */
gen->touched = jit_regused_init;
}
else
{
gen->touched = gen->permanent;
}
/* Reset the epilog fixup list */
gen->epilog_fixup = 0;
}
libjit/jit/jit-compile.c view on Meta::CPAN
state->func->no_throw = 1;
}
if(!state->func->builder->ordinary_return)
{
state->func->no_return = 1;
}
/* Compute liveness and "next use" information for this function */
_jit_function_compute_liveness(state->func);
/* Allocate global registers to variables within the function */
#ifndef JIT_BACKEND_INTERP
_jit_regs_alloc_global(&state->gen, state->func);
#endif
}
/*
* Run codegen.
*/
static void
codegen(_jit_compile_t *state)
{
jit_function_t func = state->func;
libjit/jit/jit-elf-defs.h view on Meta::CPAN
#define VER_DEF_NONE 0 /* No version */
#define VER_DEF_CURRENT 1 /* Current version */
#define VER_DEF_NUM 2 /* Given version number */
/* Legal values for vd_flags (version information flags). */
#define VER_FLG_BASE 0x1 /* Version definition of file itself */
#define VER_FLG_WEAK 0x2 /* Weak version identifier */
/* Versym symbol index values. */
#define VER_NDX_LOCAL 0 /* Symbol is local. */
#define VER_NDX_GLOBAL 1 /* Symbol is global. */
#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
/* Auxialiary version information. */
typedef struct
{
Elf32_Word vda_name; /* Version or dependency names */
Elf32_Word vda_next; /* Offset in bytes to next verdaux
entry */
libjit/jit/jit-elf-defs.h view on Meta::CPAN
#define SHT_MIPS_PIXIE 0x70000023
#define SHT_MIPS_XLATE 0x70000024
#define SHT_MIPS_XLATE_DEBUG 0x70000025
#define SHT_MIPS_WHIRL 0x70000026
#define SHT_MIPS_EH_REGION 0x70000027
#define SHT_MIPS_XLATE_OLD 0x70000028
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
/* Legal values for sh_flags field of Elf32_Shdr. */
#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */
#define SHF_MIPS_MERGE 0x20000000
#define SHF_MIPS_ADDR 0x40000000
#define SHF_MIPS_STRINGS 0x80000000
#define SHF_MIPS_NOSTRIP 0x08000000
#define SHF_MIPS_LOCAL 0x04000000
#define SHF_MIPS_NAMES 0x02000000
#define SHF_MIPS_NODUPE 0x01000000
/* Symbol tables. */
libjit/jit/jit-elf-defs.h view on Meta::CPAN
} Elf32_RegInfo;
/* Entries found in sections of type SHT_MIPS_OPTIONS. */
typedef struct
{
unsigned char kind; /* Determines interpretation of the
variable part of descriptor. */
unsigned char size; /* Size of descriptor, including header. */
Elf32_Section section; /* Section header index of section affected,
0 for global options. */
Elf32_Word info; /* Kind-specific information. */
} Elf_Options;
/* Values for `kind' field in Elf_Options. */
#define ODK_NULL 0 /* Undefined. */
#define ODK_REGINFO 1 /* Register usage information. */
#define ODK_EXCEPTIONS 2 /* Exception processing options. */
#define ODK_PAD 3 /* Section padding options. */
#define ODK_HWPATCH 4 /* Hardware workarounds performed */
libjit/jit/jit-init.c view on Meta::CPAN
@*/
void
jit_init(void)
{
static int init_done = 0;
/* Make sure that the thread subsystem is initialized */
_jit_thread_init();
/* Make sure that the initialization is done only once
(requires the global lock initialized above) */
jit_mutex_lock(&_jit_global_lock);
if(init_done)
{
goto done;
}
init_done = 1;
#ifdef JIT_USE_SIGNALS
/* Initialize the signal handlers */
_jit_signal_init();
#endif
/* Initialize the virtual memory system */
jit_vmem_init();
/* Initialize the backend */
_jit_init_backend();
done:
jit_mutex_unlock(&_jit_global_lock);
}
/*@
* @deftypefun int jit_uses_interpreter (void)
* Determine if the JIT uses a fall-back interpreter to execute code
* rather than generating and executing native code. This can be
* called prior to @code{jit_init}.
* @end deftypefun
@*/
int
libjit/jit/jit-insn.c view on Meta::CPAN
pointer. Adjust the current offset accordingly */
offset += jit_value_get_nint_constant(insn->value2);
value = insn->value1;
insn = find_base_insn(func, iter, value, &last);
last = 0;
}
if(insn && insn->opcode == JIT_OP_ADDRESS_OF && !last)
{
/* Shift the "address_of" instruction down, to make
it easier for the code generator to handle field
accesses within local and global variables */
value = jit_insn_address_of(func, insn->value1);
if(!value)
{
return 0;
}
}
return apply_binary
(func, _jit_load_opcode(JIT_OP_LOAD_RELATIVE_SBYTE, type, 0, 0), value,
jit_value_create_nint_constant(func, jit_type_nint, offset), type);
}
libjit/jit/jit-insn.c view on Meta::CPAN
pointer. Adjust the current offset accordingly */
offset += jit_value_get_nint_constant(insn->value2);
dest = insn->value1;
insn = find_base_insn(func, iter, value, &last);
last = 0;
}
if(insn && insn->opcode == JIT_OP_ADDRESS_OF && !last)
{
/* Shift the "address_of" instruction down, to make
it easier for the code generator to handle field
accesses within local and global variables */
dest = jit_insn_address_of(func, insn->value1);
if(!dest)
{
return 0;
}
}
offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
if(!offset_value)
{
libjit/jit/jit-internal.h view on Meta::CPAN
unsigned is_volatile : 1;
unsigned is_addressable : 1;
unsigned is_constant : 1;
unsigned is_nint_constant : 1;
unsigned is_parameter : 1;
unsigned is_reg_parameter : 1;
unsigned has_address : 1;
unsigned free_address : 1;
unsigned in_register : 1;
unsigned in_frame : 1;
unsigned in_global_register : 1;
unsigned live : 1;
unsigned next_use : 1;
unsigned has_frame_offset : 1;
unsigned global_candidate : 1;
unsigned has_global_register : 1;
short reg;
short global_reg;
jit_nint address;
jit_nint frame_offset;
jit_nuint usage_count;
int index;
};
#define JIT_INVALID_FRAME_OFFSET ((jit_nint)0x7FFFFFFF)
/*
* Free the structures that are associated with a value.
*/
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
@*/
/*
* Dump debug information about the register allocation state.
*/
#undef JIT_REG_DEBUG
/*
* Minimum number of times a candidate must be used before it
* is considered worthy of putting in a global register.
*/
#define JIT_MIN_USED 3
/*
* Use is_register_occupied() function.
*/
#undef IS_REGISTER_OCCUPIED
/*
* Check if the register is on the register stack.
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
static int
is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg)
{
int index, usage;
if(reg < 0)
{
return 0;
}
/* Assume that a global register is always alive unless it is to be
computed right away. */
if(jit_reg_is_used(gen->permanent, reg))
{
if(!regs->ternary
&& regs->descs[0].value
&& regs->descs[0].value->has_global_register
&& regs->descs[0].value->global_reg == reg)
{
return 0;
}
return 1;
}
if(gen->contents[reg].is_long_end)
{
reg = get_long_pair_start(reg);
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
* that may need to be evicted from it.
*/
static int
is_register_occupied(jit_gencode_t gen, _jit_regs_t *regs, int reg)
{
if(reg < 0)
{
return 0;
}
/* Assume that a global register is always occupied. */
if(jit_reg_is_used(gen->permanent, reg))
{
return 1;
}
if(gen->contents[reg].is_long_end)
{
reg = get_long_pair_start(reg);
}
if(gen->contents[reg].num_values)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
flags = CLOBBER_INPUT_VALUE;
}
else
{
flags = CLOBBER_NONE;
}
if(flags == CLOBBER_NONE)
{
if(regs->descs[index].value->has_global_register
&& regs->descs[index].value->global_reg == reg)
{
return CLOBBER_NONE;
}
if(regs->descs[index].value->in_register
&& regs->descs[index].value->reg == reg)
{
return CLOBBER_NONE;
}
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
if(desc->thrash)
{
reg = -1;
other_reg = -1;
}
}
/* See if the value needs to be loaded or copied or none. */
if(reg != desc->reg)
{
if(desc->value->has_global_register)
{
desc->copy = (desc->value->global_reg != desc->reg);
}
else if(reg < 0)
{
desc->load = 1;
}
else
{
desc->copy = 1;
}
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
++(regs->wanted_stack_count);
if(!desc->load && !desc->copy)
{
++(regs->loaded_stack_count);
}
}
#endif
}
/* See if the value clobbers a global register. In this case the global
register is pushed onto stack before the instruction and popped back
after it. */
if(!desc->copy
&& (!desc->value->has_global_register || desc->value->global_reg != desc->reg)
&& (jit_reg_is_used(gen->permanent, desc->reg)
|| (desc->other_reg >= 0 && jit_reg_is_used(gen->permanent, desc->other_reg))))
{
desc->kill = 1;
}
/* Set clobber flags (this indicates registers to be spilled). */
if((clobber & CLOBBER_REG) != 0)
{
jit_reg_set_used(regs->clobber, desc->reg);
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
jit_reg_set_used(regs->clobber, desc->other_reg);
}
#ifdef JIT_REG_DEBUG
printf("value = ");
jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
printf("\n");
printf("value->in_register = %d\n", desc->value->in_register);
printf("value->reg = %d\n", desc->value->reg);
printf("value->has_global_register = %d\n", desc->value->has_global_register);
printf("value->in_global_register = %d\n", desc->value->in_global_register);
printf("value->global_reg = %d\n", desc->value->global_reg);
printf("value->in_frame = %d\n", desc->value->in_frame);
printf("reg = %d\n", desc->reg);
printf("other_reg = %d\n", desc->other_reg);
printf("live = %d\n", desc->live);
printf("used = %d\n", desc->used);
printf("clobber = %d\n", desc->clobber);
printf("early_clobber = %d\n", desc->early_clobber);
printf("duplicate = %d\n", desc->duplicate);
printf("thrash = %d\n", desc->thrash);
printf("store = %d\n", desc->store);
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
#endif
}
/*
* Compute the register spill cost. The register spill cost is computed as
* the sum of spill costs of individual values the register contains. The
* spill cost of a value depends on the following factors:
*
* 1. Values that are not used after the current instruction may be safely
* discareded so their spill cost is taken to be zero.
* 2. Values that are spilled to global registers are cheaper than values
* that are spilled into stack frame.
* 3. Clean values are cheaper than dirty values.
*
* NOTE: A value is clean if it was loaded from the stack frame or from a
* global register and has not changed since then. Otherwise it is dirty.
* There is no need to spill clean values. However their spill cost is
* considered to be non-zero so that the register allocator will choose
* those registers that do not contain live values over those that contain
* live albeit clean values.
*
* For global registers this function returns the cost of zero. So global
* registers have to be handled separately.
*/
static int
compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg)
{
int cost, index, usage;
jit_value_t value;
if(gen->contents[reg].is_long_end)
{
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
usage = value_usage(regs, value);
if((usage & VALUE_DEAD) != 0)
{
/* the value is not spilled */
continue;
}
if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
{
/* the value has to be spilled anyway */
/* NOTE: This is true for local register allocation,
review for future global allocator. */
continue;
}
if(value->has_global_register)
{
if(value->in_global_register)
{
cost += COST_SPILL_CLEAN_GLOBAL;
}
else
{
cost += COST_SPILL_DIRTY_GLOBAL;
}
}
else
{
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
usage = value_usage(regs, value);
if((usage & VALUE_DEAD) != 0)
{
/* the value is not spilled */
continue;
}
if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
{
/* the value has to be spilled anyway */
/* NOTE: This is true for local register allocation,
review for future global allocator. */
continue;
}
if(value->has_global_register)
{
if(value->in_global_register)
{
cost += COST_SPILL_CLEAN_GLOBAL;
}
else
{
cost += COST_SPILL_DIRTY_GLOBAL;
}
}
else
{
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
}
static int
thrashes_value(jit_gencode_t gen,
_jit_regdesc_t *desc, int reg, int other_reg,
_jit_regdesc_t *desc2)
{
int reg2, other_reg2;
#if ALLOW_CLOBBER_GLOBAL
if(desc2->value->has_global_register)
{
if(desc2->value->global_reg == reg)
{
if(desc && desc2->value == desc->value)
{
return 0;
}
return 1;
}
if(desc2->value->global_reg == other_reg)
{
return 1;
}
}
#endif
if(desc2->value->in_register)
{
reg2 = desc2->value->reg;
if(reg2 == reg)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
}
other_reg = jit_reg_get_pair(regs->descs[0].value->type, reg);
if(other_reg >= 0 && jit_reg_is_used(gen->inhibit, other_reg))
{
continue;
}
if(jit_reg_is_used(gen->permanent, reg))
{
if(!regs->descs[0].value->has_global_register
|| regs->descs[0].value->global_reg != reg)
{
/* It is not allowed to assign an output value to a global
register unless it is the very value the global register
contains. */
continue;
}
if(regs->free_dest)
{
if(regs->descs[0].early_clobber
&& regs->descs[0].value->in_global_register)
{
if(regs->descs[0].value == regs->descs[1].value)
{
continue;
}
if(regs->descs[0].value == regs->descs[2].value)
{
continue;
}
}
use_cost = 0;
}
else if(regs->descs[0].value->in_global_register)
{
if(regs->descs[0].value == regs->descs[1].value)
{
use_cost = 0;
}
else if(regs->descs[0].value == regs->descs[2].value)
{
if(regs->commutative)
{
/* This depends on choose_input_order()
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
#endif
else
{
use_cost = COST_THRASH;
}
}
else
{
use_cost = COST_COPY;
}
if(regs->descs[0].value->has_global_register)
{
use_cost += COST_GLOBAL_BIAS;
}
}
if(!jit_reg_is_used(regs->clobber, reg)
&& !(other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
{
use_cost += compute_spill_cost(gen, regs, reg, other_reg);
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
*/
static void
choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
{
jit_value_t value;
value = regs->descs[2].value;
if(value && value != regs->descs[1].value
&& ((value->in_register
&& value->reg == regs->descs[0].reg)
|| (value->in_global_register
&& value->global_reg == regs->descs[0].reg)))
{
#ifdef JIT_REG_STACK
if(regs->reversible && regs->no_pop)
{
regs->dest_input_index = 2;
}
else
#endif
{
if(regs->commutative)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
continue;
}
other_reg = jit_reg_get_pair(desc->value->type, reg);
if(other_reg >= 0 && jit_reg_is_used(regs->assigned, other_reg))
{
continue;
}
if((desc->value->in_global_register && desc->value->global_reg == reg)
|| (desc->value->in_register && desc->value->reg == reg))
{
use_cost = 0;
}
else
{
use_cost = COST_COPY;
}
if(desc2->value->has_global_register && desc2->value->global_reg != reg)
{
use_cost += COST_GLOBAL_BIAS;
}
if(index != 0 && regs->ternary && regs->descs[0].value
&& thrashes_value(gen, desc, reg, other_reg, ®s->descs[0]))
{
use_cost += COST_THRASH;
}
else if(index != 1 && regs->descs[1].value
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
static void
bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int still_in_frame)
{
#ifdef JIT_REG_DEBUG
printf("bind_value(value = ");
jit_dump_value(stdout, jit_value_get_function(value), value, 0);
printf(", reg = %d, other_reg = %d, still_in_frame = %d)\n",
reg, other_reg, still_in_frame);
#endif
if(value->has_global_register && value->global_reg == reg)
{
value->in_register = 0;
value->in_global_register = 1;
return;
}
if(value->is_constant)
{
still_in_frame = 0;
}
#ifdef JIT_REG_DEBUG
if(gen->contents[reg].num_values == JIT_MAX_REG_VALUES)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
gen->contents[other_reg].num_values = 0;
gen->contents[other_reg].age = gen->current_age;
gen->contents[other_reg].used_for_temp = 0;
gen->contents[other_reg].is_long_start = 0;
gen->contents[other_reg].is_long_end = 1;
}
++(gen->current_age);
/* Adjust the value to reflect that it is in "reg", and maybe the frame */
value->in_register = 1;
if(value->has_global_register)
{
value->in_global_register = still_in_frame;
}
else
{
value->in_frame = still_in_frame;
}
value->reg = reg;
}
/*
* Disassociate value with register.
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
*/
static void
free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int temp)
{
#ifdef JIT_REG_DEBUG
printf("free_value(value = ");
jit_dump_value(stdout, jit_value_get_function(value), value, 0);
printf(", reg = %d, other_reg = %d, temp = %d)\n", reg, other_reg, temp);
#endif
/* Never free global registers. */
if(value->has_global_register && value->global_reg == reg)
{
return;
}
if(gen->contents[reg].num_values == 1)
{
if(temp)
{
unbind_value(gen, value, reg, other_reg);
bind_temporary(gen, reg, other_reg);
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
* the free option still applies to them.
*/
static void
save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int free)
{
#ifdef JIT_REG_DEBUG
printf("save_value(value = ");
jit_dump_value(stdout, jit_value_get_function(value), value, 0);
printf(", reg = %d, other_reg = %d, free=%d)\n", reg, other_reg, free);
#endif
/* First take care of values that reside in global registers. */
if(value->has_global_register)
{
/* Never free global registers. */
if(value->global_reg == reg)
{
return;
}
if(!value->in_global_register)
{
_jit_gen_spill_reg(gen, reg, other_reg, value);
value->in_global_register = 1;
}
if(free)
{
unbind_value(gen, value, reg, other_reg);
}
return;
}
/* Take care of constants and values that are already in frame. */
if(value->is_constant || value->in_frame)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
#ifdef JIT_REG_DEBUG
printf("load_input_value(%d)\n", index);
#endif
desc = ®s->descs[index];
if(!desc->value || desc->duplicate)
{
return;
}
if(desc->value->has_global_register)
{
if(desc->value->in_global_register && desc->value->global_reg == desc->reg)
{
return;
}
if(desc->value->in_register && desc->value->reg == desc->reg)
{
update_age(gen, desc);
return;
}
_jit_gen_load_value(gen, desc->reg, desc->other_reg, desc->value);
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
}
free_value(gen, desc->value, reg, other_reg, 0);
}
#ifdef JIT_REG_DEBUG
printf("value = ");
jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
printf("\n");
printf("value->in_register = %d\n", desc->value->in_register);
printf("value->reg = %d\n", desc->value->reg);
printf("value->in_global_register = %d\n", desc->value->in_global_register);
printf("value->global_reg = %d\n", desc->value->global_reg);
printf("value->in_frame = %d\n", desc->value->in_frame);
#endif
}
static void
commit_output_value(jit_gencode_t gen, _jit_regs_t *regs, int push_stack_top)
{
_jit_regdesc_t *desc;
#ifdef JIT_REG_DEBUG
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
}
#ifdef JIT_REG_DEBUG
printf("value = ");
jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
printf("\n");
printf("value->in_register = %d\n", desc->value->in_register);
printf("value->reg = %d\n", desc->value->reg);
printf("value->in_global_register = %d\n", desc->value->in_global_register);
printf("value->global_reg = %d\n", desc->value->global_reg);
printf("value->in_frame = %d\n", desc->value->in_frame);
#endif
}
/*@
* @deftypefun void _jit_regs_lookup (char *name)
* Get the pseudo register by its name.
* @end deftypefun
@*/
int
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
if(strcmp(jit_reg_name(reg), name) == 0)
{
return reg;
}
}
}
return -1;
}
/*@
* @deftypefun void _jit_regs_alloc_global (jit_gencode_t gen, jit_function_t func)
* Perform global register allocation on the values in @code{func}.
* This is called during function compilation just after variable
* liveness has been computed.
* @end deftypefun
@*/
void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func)
{
#if JIT_NUM_GLOBAL_REGS != 0
jit_value_t candidates[JIT_NUM_GLOBAL_REGS];
int num_candidates = 0;
int index, reg, posn, num;
jit_pool_block_t block;
jit_value_t value, temp;
/* If the function has a "try" block, then don't do global allocation
as the "longjmp" for exception throws will wipe out global registers */
if(func->has_try)
{
return;
}
/* If the current function involves a tail call, then we don't do
global register allocation and we also prevent the code generator
from using any of the callee-saved registers. This simplifies
tail calls, which don't have to worry about restoring such registers */
if(func->builder->has_tail_call)
{
for(reg = 0; reg < JIT_NUM_REGS; ++reg)
{
if((jit_reg_flags(reg) & (JIT_REG_FIXED|JIT_REG_CALL_USED)) == 0)
{
jit_reg_set_used(gen->permanent, reg);
}
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
num = (int)(func->builder->value_pool.elems_per_block);
while(block != 0)
{
if(!(block->next))
{
num = (int)(func->builder->value_pool.elems_in_last);
}
for(posn = 0; posn < num; ++posn)
{
value = (jit_value_t)(block->data + posn * sizeof(struct _jit_value));
if(value->global_candidate && value->usage_count >= JIT_MIN_USED &&
!(value->is_addressable) && !(value->is_volatile))
{
/* Insert this candidate into the list, ordered on count */
index = 0;
while(index < num_candidates &&
value->usage_count <= candidates[index]->usage_count)
{
++index;
}
while(index < num_candidates)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
{
candidates[num_candidates++] = value;
}
}
}
block = block->next;
}
/* Allocate registers to the candidates. We allocate from the top-most
register in the allocation order, because some architectures like
PPC require global registers to be saved top-down for efficiency */
reg = JIT_NUM_REGS - 1;
for(index = 0; index < num_candidates; ++index)
{
while(reg >= 0 && (jit_reg_flags(reg) & JIT_REG_GLOBAL) == 0)
{
--reg;
}
candidates[index]->has_global_register = 1;
candidates[index]->in_global_register = 1;
candidates[index]->global_reg = (short)reg;
jit_reg_set_used(gen->touched, reg);
jit_reg_set_used(gen->permanent, reg);
--reg;
}
#endif
}
/*@
* @deftypefun void _jit_regs_init_for_block (jit_gencode_t gen)
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
}
}
#else
other_reg = jit_reg_get_pair(value->type, reg);
#endif
if(value->in_register && value->reg == reg)
{
/* The value is already in the register, but we may need to spill
if the frame copy is not up to date with the register */
if(!(value->in_global_register || value->in_frame))
{
save_value(gen, value, reg, other_reg, 0);
}
/* The value is no longer "really" in the register. A copy is
left behind, but the value itself reverts to the frame copy
as we are about to kill the registers in a function call */
free_value(gen, value, reg, other_reg, 1);
}
else
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
int
_jit_regs_load_value(jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
{
int type;
int reg, other_reg;
int spill_cost;
int suitable_reg, suitable_other_reg;
int suitable_cost;
int suitable_age;
/* If the value is in a global register, and we are not going
to destroy the value, then use the global register itself.
This will avoid a redundant register copy operation */
if(value->in_global_register && !destroy)
{
return value->global_reg;
}
/* If the value is already in a register, then try to use that register */
if(value->in_register && (!destroy || !used_again))
{
reg = value->reg;
if(!used_again)
{
other_reg = jit_reg_get_pair(value->type, reg);
free_value(gen, value, reg, other_reg, 1);
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
continue;
}
if(!jit_reg_is_used(regs->clobber, reg))
{
continue;
}
if(jit_reg_is_used(gen->permanent, reg))
{
#ifdef IS_REGISTER_OCCUPIED
/* If the op computes the value assigned to the global
register then it is not really clobbered. */
if(!regs->ternary
&& regs->descs[0].value
&& regs->descs[0].value->has_global_register
&& regs->descs[0].value->global_reg == reg)
{
continue;
}
#endif
/* Oops, the global register is going to be clobbered. Save
it on the stack in order to restore after the op. */
#ifdef JIT_REG_DEBUG
printf("*** Spill global register: %d ***\n", reg);
#endif
if(regs->branch)
{
/* After the branch is taken there is no way
to load the global register back. */
jit_exception_builtin(JIT_RESULT_COMPILE_ERROR);
}
_jit_gen_spill_global(gen, reg, 0);
continue;
}
#ifdef JIT_REG_STACK
/* If this is a stack register, then we need to find the
register that contains the top-most stack position,
because we must spill stack registers from top down.
As we spill each one, something else will become the top */
if(IS_STACK_REG(reg))
{
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
commit_output_value(gen, regs, 0);
}
#endif
else
{
commit_input_value(gen, regs, 2, 0);
commit_input_value(gen, regs, 1, 0);
commit_output_value(gen, regs, 1);
}
/* Load clobbered global registers. */
for(reg = JIT_NUM_REGS - 1; reg >= 0; reg--)
{
if(jit_reg_is_used(regs->clobber, reg) && jit_reg_is_used(gen->permanent, reg))
{
#ifdef IS_REGISTER_OCCUPIED
if(!regs->ternary
&& regs->descs[0].value
&& regs->descs[0].value->has_global_register
&& regs->descs[0].value->global_reg == reg)
{
continue;
}
#endif
_jit_gen_load_global(gen, reg, 0);
}
}
#ifdef JIT_REG_DEBUG
dump_regs(gen, "leave _jit_regs_commit");
#endif
}
void
_jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space)
libjit/jit/jit-reg-alloc.h view on Meta::CPAN
jit_regused_t clobber;
#ifdef JIT_REG_STACK
int wanted_stack_count;
int loaded_stack_count;
#endif
} _jit_regs_t;
int _jit_regs_lookup(char *name);
void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func);
void _jit_regs_init_for_block(jit_gencode_t gen);
void _jit_regs_spill_all(jit_gencode_t gen);
void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value);
void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value);
void _jit_regs_clear_all_outgoing(jit_gencode_t gen);
void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest);
int _jit_regs_load_value(jit_gencode_t gen, jit_value_t value, int destroy, int used_again);
void _jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags);
libjit/jit/jit-rules-arm.c view on Meta::CPAN
* Setup or teardown the ARM code output process.
*/
#define jit_cache_setup_output(needed) \
arm_inst_buf inst; \
jit_gen_load_inst_ptr(gen, inst)
#define jit_cache_end_output() \
jit_gen_save_inst_ptr(gen, inst)
/**
* Spill the content of register "reg" (and "other_reg", if it's different from -1)
* into the global register or the memory area associated with "value"
* NB: it doesn't set value->in_global_register or value->in_frame. The caller has to
* take care of that.
*/
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value)
{
int offset;
/* Make sure that we have sufficient space */
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
jit_gen_load_inst_ptr(gen, inst);
}
/* Output an appropriate instruction to spill the value */
if(value->has_global_register)
{
if (IS_FLOAT_REG(reg))
{
printf("TODO:Copy from float reg to global reg is not handled properly in %s\n", __FILE__);
abort();
}
else
{
arm_mov_reg_reg(inst, _jit_reg_info[value->global_reg].cpu_reg, _jit_reg_info[reg].cpu_reg);
}
}
else
{
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
if(IS_WORD_REG(reg))
{
arm_store_membase(inst, reg, ARM_FP, offset);
if(other_reg != -1)
libjit/jit/jit-rules-arm.c view on Meta::CPAN
{
mov_freg_imm_64
(gen, &inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0],
((int *)&float64_value)[1]);
}
}
break;
}
}
else if(value->in_global_register)
{
/* Load the value out of a global register */
if(IS_FLOAT_REG(reg))
{
/* Load into a floating point register */
#ifdef JIT_ARM_HAS_VFP
/* Vector Floating Point instructions */
if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
{
arm_mov_float_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
else
{
//JIT_TYPE_FLOAT64 or JIT_TYPE_NFLOAT
arm_mov_double_reg_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg + 1);
}
#endif
#ifdef JIT_ARM_HAS_FPA
/* Floating Point Architecture instructions */
TODO();
abort();
#endif
}
else
{
/* Load into a general-purpose register */
arm_mov_reg_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
}
else if(value->in_register)
{
/* The value is already in another register. Move it */
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
libjit/jit/jit-rules-arm.c view on Meta::CPAN
TODO();
abort();
#endif
}
break;
}
}
else
{
/* Load from the stack */
assert(!value->in_global_register && !value->is_constant && !value->in_register);
/* Fix the position of the value in the stack frame */
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
{
arm_load_membase_sbyte(inst, _jit_reg_info[reg].cpu_reg,
libjit/jit/jit-rules-arm.c view on Meta::CPAN
if(flush_if_too_far(gen))
{
jit_gen_load_inst_ptr(gen, inst);
}
if(value->is_constant)
{
TODO();
abort();
}
else if(value->has_global_register)
{
/*
* This value has been assinged a global register. This means
* that it can use that register, but not necessarily that it's
* already in it!!
*/
/* Ensure that the value is already in the global_register */
if (!value->in_global_register)
{
/* Find the other register in a long pair */
int reg = value->reg;
int other_reg = jit_reg_current_other_reg(gen,reg);
//Spill to the global register
_jit_gen_spill_reg(gen, reg, other_reg, value);
value->in_global_register=1;
/* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
jit_gen_load_inst_ptr(gen, inst);
}
/* Load the value out of a global register */
arm_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
else
{
/* Fix the position of the value in the stack frame */
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
/* Ensure that the value is already in the stack frame */
if(value->in_register)
{
libjit/jit/jit-rules-arm.c view on Meta::CPAN
TODO();
abort();
}
}
/* End the code output process */
jit_cache_end_output();
}
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
/* TODO: Implement if ARM needs it. */
}
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(32);
arm_load_membase(inst, _jit_reg_info[value->global_reg].cpu_reg,
ARM_FP, value->frame_offset);
jit_cache_end_output();
}
void _jit_gen_fix_value(jit_value_t value)
{
if(!(value->has_frame_offset) && !(value->is_constant))
{
jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
value->block->func->builder->frame_size += size;
libjit/jit/jit-rules-arm.c view on Meta::CPAN
fixup = next;
}
block->fixup_list = 0;
}
void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
/* Nothing to do here for ARM */
}
int _jit_gen_is_global_candidate(jit_type_t type)
{
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_NINT:
case JIT_TYPE_NUINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE: return 1;
}
libjit/jit/jit-rules-arm.h view on Meta::CPAN
/*
* Determine if this ARM core uses floating point registers available
*/
#if defined(JIT_ARM_HAS_FPA) || defined(JIT_ARM_HAS_VFP)
# define JIT_ARM_HAS_FLOAT_REGS 1
#endif
/*
* Information about all of the registers, in allocation order.
* We use r0-r5 for general-purpose values and r6-r8 for globals.
*
* The floating-point registers are only present on some ARM cores.
*
* The definitions of the used flags are in jit-rules.h
*/
#define JIT_REG_INFO \
{"r0", 0, 1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
{"r1", 1, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
{"r2", 2, 3, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
{"r3", 3, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
libjit/jit/jit-rules-arm.h view on Meta::CPAN
{"d12", 12, -1, JIT_REG_ARM_FLOAT64}, \
{"d13", 13, -1, JIT_REG_ARM_FLOAT64}, \
{"d14", 14, -1, JIT_REG_ARM_FLOAT64}, \
{"d15", 15, -1, JIT_REG_ARM_FLOAT64},
/* JIT_NUM_REGS is the total number of registers (general purpose+floating point) */
#define JIT_NUM_REGS 40
#endif
/* The number of global registers */
#define JIT_NUM_GLOBAL_REGS 3
//Floating point registers are NOT handled like a stack
#undef JIT_REG_STACK
/*
* Define to 1 if we should always load values into registers
* before operating on them. i.e. the CPU does not have reg-mem
* and mem-reg addressing modes.
*/
libjit/jit/jit-rules-interp.c view on Meta::CPAN
@item JIT_REG_FIXED
This register has a fixed meaning and cannot be used for general allocation.
@item JIT_REG_CALL_USED
This register will be destroyed by a function call.
@item JIT_REG_IN_STACK
This register is in a stack-like arrangement.
@item JIT_REG_GLOBAL
This register is a candidate for global register allocation.
@end table
A CPU may have some registers arranged into a stack. In this case
operations can typically only occur at the top of the stack, and
may automatically pop values as a side-effect of the operation.
An example of such architecture is x87 floating point unit. Such
CPU requires three additional macros.
@table @code
libjit/jit/jit-rules-interp.c view on Meta::CPAN
up to @code{JIT_REG_STACK_END} must also have the @code{JIT_REG_IN_STACK}
flag set.
@subsection Other architecture macros
@noindent
The rule file may also have definitions of the following macros:
@table @code
@item JIT_NUM_GLOBAL_REGS
The number of registers that are used for global register allocation.
Set to zero if global register allocation should not be used.
@item JIT_ALWAYS_REG_REG
Define this to 1 if arithmetic operations must always be performed
on registers. Define this to 0 if register/memory and memory/register
operations are possible.
@item JIT_PROLOG_SIZE
If defined, this indicates the maximum size of the function prolog.
@item JIT_FUNCTION_ALIGNMENT
libjit/jit/jit-rules-interp.c view on Meta::CPAN
* with @code{_jit_gen_fix_value}.
* @end deftypefun
@*/
void _jit_gen_load_value
(jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
{
/* Registers are not used in the interpreted back end */
}
/*@
* @deftypefun void _jit_gen_spill_global (jit_gencode_t @var{gen}, int @var{reg}, jit_value_t @var{value})
* Spill the contents of @var{value} from its corresponding global register.
* This is used in rare cases when a machine instruction requires its operand
* to be in the specific register that happens to be global. In such cases the
* register is spilled just before the instruction and loaded back immediately
* after it.
* @end deftypefun
@*/
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
/* Global registers are not used in the interpreted back end */
}
/*@
* @deftypefun void _jit_gen_load_global (jit_gencode_t @var{gen}, int @var{reg}, jit_value_t @var{value})
* Load the contents of @var{value} into its corresponding global register.
* This is used at the head of a function to pull parameters out of stack
* slots into their global register copies.
* @end deftypefun
@*/
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
/* Global registers are not used in the interpreted back end */
}
/*@
* @deftypefun void _jit_gen_exch_top (jit_gencode_t @var{gen}, int @var{reg})
* Generate instructions to exchange the contents of the top stack register
* with a stack register specified by the @var{reg} argument.
*
* It needs to be implemented only by backends that support stack registers.
libjit/jit/jit-rules-interp.c view on Meta::CPAN
* has been reached.
* @end deftypefun
@*/
void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
/* Reset the working area size to zero for the next block */
gen->working_area = 0;
}
/*@
* @deftypefun int _jit_gen_is_global_candidate (jit_type_t @var{type})
* Determine if @var{type} is a candidate for allocation within
* global registers.
* @end deftypefun
@*/
int _jit_gen_is_global_candidate(jit_type_t type)
{
/* Global register allocation is not used by the interpreter */
return 0;
}
/*@
* @deftypefun int _jit_reg_get_pair (jit_type_t @var{type}, int @var{reg})
* Determine if a type requires a register pair. If so then for the specified
* register @var{reg} return the other register of the corresponding pair.
* Return -1 if no pair is required.
libjit/jit/jit-rules-x86-64.c view on Meta::CPAN
/* Align the new frame_size for the value */
frame_size = (frame_size + (alignment - 1)) & ~(alignment - 1);
value->block->func->builder->frame_size = frame_size;
value->frame_offset = -frame_size;
value->has_frame_offset = 1;
}
}
void
_jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(16);
if(value)
{
jit_type_t type = jit_type_normalize(value->type);
_jit_gen_fix_value(value);
_spill_reg(&inst, type, value->global_reg, value->frame_offset);
}
else
{
x86_64_push_reg_size(inst, _jit_reg_info[reg].cpu_reg, 8);
}
jit_cache_end_output();
}
void
_jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(16);
if(value)
{
x86_64_mov_reg_membase_size(inst,
_jit_reg_info[value->global_reg].cpu_reg,
X86_64_RBP, value->frame_offset, 8);
}
else
{
x86_64_pop_reg_size(inst, _jit_reg_info[reg].cpu_reg, 8);
}
jit_cache_end_output();
}
void
_jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value)
{
jit_type_t type;
/* Make sure that we have sufficient space */
jit_cache_setup_output(16);
/* If the value is associated with a global register, then copy to that */
if(value->has_global_register)
{
reg = _jit_reg_info[reg].cpu_reg;
other_reg = _jit_reg_info[value->global_reg].cpu_reg;
x86_64_mov_reg_reg_size(inst, other_reg, reg, sizeof(void *));
jit_cache_end_output();
return;
}
/* Fix the value in place within the local variable frame */
_jit_gen_fix_value(value);
/* Get the normalized type */
type = jit_type_normalize(value->type);
libjit/jit/jit-rules-x86-64.c view on Meta::CPAN
{
/* We have to use an extra general register */
TODO();
}
}
}
}
break;
}
}
else if(value->in_register || value->in_global_register)
{
if(value->in_register)
{
src_reg = value->reg;
other_src_reg = -1;
}
else
{
src_reg = value->global_reg;
other_src_reg = -1;
}
switch(type->kind)
{
#if 0
case JIT_TYPE_SBYTE:
{
x86_widen_reg(inst, _jit_reg_info[reg].cpu_reg,
_jit_reg_info[src_reg].cpu_reg, 1, 0);
libjit/jit/jit-rules-x86-64.c view on Meta::CPAN
block->fixup_absolute_list = 0;
}
void
_jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
/* Nothing to do here for x86 */
}
int
_jit_gen_is_global_candidate(jit_type_t type)
{
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_LONG:
libjit/jit/jit-rules-x86.c view on Meta::CPAN
}
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value)
{
int offset;
/* Make sure that we have sufficient space */
jit_cache_setup_output(16);
/* If the value is associated with a global register, then copy to that */
if(value->has_global_register)
{
reg = _jit_reg_info[reg].cpu_reg;
other_reg = _jit_reg_info[value->global_reg].cpu_reg;
x86_mov_reg_reg(inst, other_reg, reg, sizeof(void *));
jit_cache_end_output();
return;
}
/* Fix the value in place within the local variable frame */
_jit_gen_fix_value(value);
/* Output an appropriate instruction to spill the value */
offset = (int)(value->frame_offset);
libjit/jit/jit-rules-x86.c view on Meta::CPAN
else
{
x86_fld80_mem(inst, ptr);
}
}
}
}
break;
}
}
else if(value->in_register || value->in_global_register)
{
if(value->in_register)
{
src_reg = value->reg;
if(other_reg >= 0)
{
other_src_reg = jit_reg_other_reg(src_reg);
}
else
{
other_src_reg = -1;
}
}
else
{
src_reg = value->global_reg;
other_src_reg = -1;
}
switch(type->kind)
{
#if 0
case JIT_TYPE_SBYTE:
{
x86_widen_reg(inst, _jit_reg_info[reg].cpu_reg,
_jit_reg_info[src_reg].cpu_reg, 1, 0);
libjit/jit/jit-rules-x86.c view on Meta::CPAN
}
}
break;
}
}
/* End the code output process */
jit_cache_end_output();
}
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(16);
if(value)
{
_jit_gen_fix_value(value);
x86_mov_membase_reg(inst,
X86_EBP, value->frame_offset,
_jit_reg_info[value->global_reg].cpu_reg, sizeof(void *));
}
else
{
x86_push_reg(inst, _jit_reg_info[reg].cpu_reg);
}
jit_cache_end_output();
}
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(16);
if(value)
{
x86_mov_reg_membase(inst,
_jit_reg_info[value->global_reg].cpu_reg,
X86_EBP, value->frame_offset, sizeof(void *));
}
else
{
x86_pop_reg(inst, _jit_reg_info[reg].cpu_reg);
}
jit_cache_end_output();
}
void _jit_gen_fix_value(jit_value_t value)
libjit/jit/jit-rules-x86.c view on Meta::CPAN
fixup = next;
}
block->fixup_absolute_list = 0;
}
void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
/* Nothing to do here for x86 */
}
int _jit_gen_is_global_candidate(jit_type_t type)
{
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_NINT:
case JIT_TYPE_NUINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE: return 1;
}
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
{
cpu_reg = _jit_reg_info[nest_reg].cpu_reg;
}
parent = func->builder->parent_frame;
if(parent->in_register)
{
x86_mov_reg_reg(inst, cpu_reg,
_jit_reg_info[parent->reg].cpu_reg,
sizeof(void *));
}
else if(parent->in_global_register)
{
x86_mov_reg_reg(inst, cpu_reg,
_jit_reg_info[parent->global_reg].cpu_reg,
sizeof(void *));
}
else
{
_jit_gen_fix_value(parent);
x86_mov_reg_membase(inst, cpu_reg, X86_EBP,
parent->frame_offset, sizeof(void *));
}
while(level > 0)
{
libjit/jit/jit-rules.h view on Meta::CPAN
#define JIT_REG_WORD (1 << 0) /* Can be used for word values */
#define JIT_REG_LONG (1 << 1) /* Can be used for long values */
#define JIT_REG_FLOAT32 (1 << 2) /* Can be used for float32 values */
#define JIT_REG_FLOAT64 (1 << 3) /* Can be used for float64 values */
#define JIT_REG_NFLOAT (1 << 4) /* Can be used for nfloat values */
#define JIT_REG_FRAME (1 << 5) /* Contains frame pointer */
#define JIT_REG_STACK_PTR (1 << 6) /* Contains CPU stack pointer */
#define JIT_REG_FIXED (1 << 7) /* Fixed use; not for allocation */
#define JIT_REG_CALL_USED (1 << 8) /* Destroyed by a call */
#define JIT_REG_IN_STACK (1 << 9) /* Middle of stack-like allocation */
#define JIT_REG_GLOBAL (1 << 10) /* Candidate for global allocation */
#define JIT_REG_ALL (JIT_REG_WORD | JIT_REG_LONG \
| JIT_REG_FLOAT32 | JIT_REG_FLOAT64 \
| JIT_REG_NFLOAT)
/*
* Include definitions that are specific to the backend.
*/
#if defined(JIT_BACKEND_INTERP)
# include "jit-rules-interp.h"
#elif defined(JIT_BACKEND_ALPHA)
libjit/jit/jit-rules.h view on Meta::CPAN
*/
typedef struct jit_gencode *jit_gencode_t;
struct jit_gencode
{
jit_context_t context; /* Context this position is attached to */
unsigned char *ptr; /* Current code pointer */
unsigned char *mem_start; /* Available space start */
unsigned char *mem_limit; /* Available space limit */
unsigned char *code_start; /* Real code start */
unsigned char *code_end; /* Real code end */
jit_regused_t permanent; /* Permanently allocated global regs */
jit_regused_t touched; /* All registers that were touched */
jit_regused_t inhibit; /* Temporarily inhibited registers */
jit_regcontents_t contents[JIT_NUM_REGS]; /* Contents of each register */
int current_age; /* Current age value for registers */
#ifdef JIT_REG_STACK
int reg_stack_top; /* Current register stack top */
#endif
#ifdef jit_extra_gen_state
jit_extra_gen_state; /* CPU-specific extra information */
#endif
libjit/jit/jit-rules.h view on Meta::CPAN
int _jit_opcode_is_supported(int opcode);
void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf);
void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func);
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func);
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value);
void _jit_gen_free_reg(jit_gencode_t gen, int reg,
int other_reg, int value_used);
void _jit_gen_load_value
(jit_gencode_t gen, int reg, int other_reg, jit_value_t value);
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value);
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value);
void _jit_gen_exch_top(jit_gencode_t gen, int reg);
void _jit_gen_move_top(jit_gencode_t gen, int reg);
void _jit_gen_spill_top(jit_gencode_t gen, int reg, jit_value_t value, int pop);
void _jit_gen_fix_value(jit_value_t value);
void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
jit_block_t block, jit_insn_t insn);
void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block);
void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block);
int _jit_gen_is_global_candidate(jit_type_t type);
#if defined(JIT_NATIVE_INT32) && !defined(JIT_BACKEND_INTERP)
int _jit_reg_get_pair(jit_type_t type, int reg);
#endif
/*
* Determine the byte number within a "jit_int" where the low
* order byte can be found.
*/
int _jit_int_lowest_byte(void);
libjit/jit/jit-thread.c view on Meta::CPAN
#elif !defined(__palmos__)
#include <time.h>
#endif
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <errno.h>
/*
* Mutex that synchronizes global data initialization.
*/
jit_mutex_t _jit_global_lock;
#if defined(JIT_THREADS_PTHREAD)
/*
* The thread-specific key to use to fetch the control object.
*/
static pthread_key_t control_key;
/*
* Initialize the pthread support routines. Only called once.
*/
static void init_pthread(void)
{
jit_mutex_create(&_jit_global_lock);
/* Allocate a thread-specific variable for the JIT's thread
control object, and arrange for it to be freed when the
thread exits or is otherwise terminated */
pthread_key_create(&control_key, jit_free);
}
#elif defined(JIT_THREADS_WIN32)
/*
* The thread-specific key to use to fetch the control object.
*/
static DWORD control_key;
/*
* Initialize the Win32 thread support routines. Only called once.
*/
static void init_win32_thread(void)
{
jit_mutex_create(&_jit_global_lock);
control_key = TlsAlloc();
}
jit_thread_id_t _jit_thread_self(void)
{
HANDLE new_handle;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &new_handle,
0, 0, DUPLICATE_SAME_ACCESS);
libjit/jit/jit-thread.h view on Meta::CPAN
typedef int jit_mutex_t;
#define jit_mutex_create(mutex) do { ; } while (0)
#define jit_mutex_destroy(mutex) do { ; } while (0)
#define jit_mutex_lock(mutex) do { ; } while (0)
#define jit_mutex_unlock(mutex) do { ; } while (0)
#endif
/*
* Mutex that synchronizes global data initialization.
*/
extern jit_mutex_t _jit_global_lock;
/*
* Define the primitive monitor operations.
*/
#if defined(JIT_THREADS_PTHREAD)
typedef struct
{
pthread_mutex_t _mutex;