TCG code generator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3943 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
56abbcfff3
commit
c896fe29d6
3
tcg/LICENSE
Normal file
3
tcg/LICENSE
Normal file
@ -0,0 +1,3 @@
|
||||
All the files in this directory and subdirectories are released under
|
||||
a BSD like license (see header in each file). No other license is
|
||||
accepted.
|
420
tcg/README
Normal file
420
tcg/README
Normal file
@ -0,0 +1,420 @@
|
||||
Tiny Code Generator - Fabrice Bellard.
|
||||
|
||||
1) Introduction
|
||||
|
||||
TCG (Tiny Code Generator) began as a generic backend for a C
|
||||
compiler. It was simplified to be used in QEMU. It also has its roots
|
||||
in the QOP code generator written by Paul Brook.
|
||||
|
||||
2) Definitions
|
||||
|
||||
The TCG "target" is the architecture for which we generate the
|
||||
code. It is of course not the same as the "target" of QEMU which is
|
||||
the emulated architecture. As TCG started as a generic C backend used
|
||||
for cross compiling, it is assumed that the TCG target is different
|
||||
from the host, although it is never the case for QEMU.
|
||||
|
||||
A TCG "function" corresponds to a QEMU Translated Block (TB).
|
||||
|
||||
A TCG "temporary" is a variable only live in a given
|
||||
function. Temporaries are allocated explicitely in each function.
|
||||
|
||||
A TCG "global" is a variable which is live in all the functions. They
|
||||
are defined before the functions defined. A TCG global can be a memory
|
||||
location (e.g. a QEMU CPU register), a fixed host register (e.g. the
|
||||
QEMU CPU state pointer) or a memory location which is stored in a
|
||||
register outside QEMU TBs (not implemented yet).
|
||||
|
||||
A TCG "basic block" corresponds to a list of instructions terminated
|
||||
by a branch instruction.
|
||||
|
||||
3) Intermediate representation
|
||||
|
||||
3.1) Introduction
|
||||
|
||||
TCG instructions operate on variables which are temporaries or
|
||||
globals. TCG instructions and variables are strongly typed. Two types
|
||||
are supported: 32 bit integers and 64 bit integers. Pointers are
|
||||
defined as an alias to 32 bit or 64 bit integers depending on the TCG
|
||||
target word size.
|
||||
|
||||
Each instruction has a fixed number of output variable operands, input
|
||||
variable operands and always constant operands.
|
||||
|
||||
The notable exception is the call instruction which has a variable
|
||||
number of outputs and inputs.
|
||||
|
||||
In the textual form, output operands come first, followed by input
|
||||
operands, followed by constant operands. The output type is included
|
||||
in the instruction name. Constants are prefixed with a '$'.
|
||||
|
||||
add_i32 t0, t1, t2 (t0 <- t1 + t2)
|
||||
|
||||
sub_i64 t2, t3, $4 (t2 <- t3 - 4)
|
||||
|
||||
3.2) Assumptions
|
||||
|
||||
* Basic blocks
|
||||
|
||||
- Basic blocks end after branches (e.g. brcond_i32 instruction),
|
||||
goto_tb and exit_tb instructions.
|
||||
- Basic blocks end before legacy dyngen operations.
|
||||
- Basic blocks start after the end of a previous basic block, at a
|
||||
set_label instruction or after a legacy dyngen operation.
|
||||
|
||||
After the end of a basic block, temporaries at destroyed and globals
|
||||
are stored at their initial storage (register or memory place
|
||||
depending on their declarations).
|
||||
|
||||
* Floating point types are not supported yet
|
||||
|
||||
* Pointers: depending on the TCG target, pointer size is 32 bit or 64
|
||||
bit. The type TCG_TYPE_PTR is an alias to TCG_TYPE_I32 or
|
||||
TCG_TYPE_I64.
|
||||
|
||||
* Helpers:
|
||||
|
||||
Using the tcg_gen_helper_x_y it is possible to call any function
|
||||
taking i32, i64 or pointer types types. Before calling an helper, all
|
||||
globals are stored at their canonical location and it is assumed that
|
||||
the function can modify them. In the future, function modifiers will
|
||||
be allowed to tell that the helper does not read or write some globals.
|
||||
|
||||
On some TCG targets (e.g. x86), several calling conventions are
|
||||
supported.
|
||||
|
||||
* Branches:
|
||||
|
||||
Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an
|
||||
explicit address. Conditional branches can only jump to labels.
|
||||
|
||||
3.3) Code Optimizations
|
||||
|
||||
When generating instructions, you can count on at least the following
|
||||
optimizations:
|
||||
|
||||
- Single instructions are simplified, e.g.
|
||||
|
||||
and_i32 t0, t0, $0xffffffff
|
||||
|
||||
is suppressed.
|
||||
|
||||
- A liveness analysis is done at the basic block level. The
|
||||
information is used to suppress moves from a dead temporary to
|
||||
another one. It is also used to remove instructions which compute
|
||||
dead results. The later is especially useful for condition code
|
||||
optimisation in QEMU.
|
||||
|
||||
In the following example:
|
||||
|
||||
add_i32 t0, t1, t2
|
||||
add_i32 t0, t0, $1
|
||||
mov_i32 t0, $1
|
||||
|
||||
only the last instruction is kept.
|
||||
|
||||
- A macro system is supported (may get closer to function inlining
|
||||
some day). It is useful if the liveness analysis is likely to prove
|
||||
that some results of a computation are indeed not useful. With the
|
||||
macro system, the user can provide several alternative
|
||||
implementations which are used depending on the used results. It is
|
||||
especially useful for condition code optimisation in QEMU.
|
||||
|
||||
Here is an example:
|
||||
|
||||
macro_2 t0, t1, $1
|
||||
mov_i32 t0, $0x1234
|
||||
|
||||
The macro identified by the ID "$1" normally returns the values t0
|
||||
and t1. Suppose its implementation is:
|
||||
|
||||
macro_start
|
||||
brcond_i32 t2, $0, $TCG_COND_EQ, $1
|
||||
mov_i32 t0, $2
|
||||
br $2
|
||||
set_label $1
|
||||
mov_i32 t0, $3
|
||||
set_label $2
|
||||
add_i32 t1, t3, t4
|
||||
macro_end
|
||||
|
||||
If t0 is not used after the macro, the user can provide a simpler
|
||||
implementation:
|
||||
|
||||
macro_start
|
||||
add_i32 t1, t2, t4
|
||||
macro_end
|
||||
|
||||
TCG automatically chooses the right implementation depending on
|
||||
which macro outputs are used after it.
|
||||
|
||||
Note that if TCG did more expensive optimizations, macros would be
|
||||
less useful. In the previous example a macro is useful because the
|
||||
liveness analysis is done on each basic block separately. Hence TCG
|
||||
cannot remove the code computing 't0' even if it is not used after
|
||||
the first macro implementation.
|
||||
|
||||
3.4) Instruction Reference
|
||||
|
||||
********* Function call
|
||||
|
||||
* call <ret> <params> ptr
|
||||
|
||||
call function 'ptr' (pointer type)
|
||||
|
||||
<ret> optional 32 bit or 64 bit return value
|
||||
<params> optional 32 bit or 64 bit parameters
|
||||
|
||||
********* Jumps/Labels
|
||||
|
||||
* jmp t0
|
||||
|
||||
Absolute jump to address t0 (pointer type).
|
||||
|
||||
* set_label $label
|
||||
|
||||
Define label 'label' at the current program point.
|
||||
|
||||
* br $label
|
||||
|
||||
Jump to label.
|
||||
|
||||
* brcond_i32/i64 cond, t0, t1, label
|
||||
|
||||
Conditional jump if t0 cond t1 is true. cond can be:
|
||||
TCG_COND_EQ
|
||||
TCG_COND_NE
|
||||
TCG_COND_LT /* signed */
|
||||
TCG_COND_GE /* signed */
|
||||
TCG_COND_LE /* signed */
|
||||
TCG_COND_GT /* signed */
|
||||
TCG_COND_LTU /* unsigned */
|
||||
TCG_COND_GEU /* unsigned */
|
||||
TCG_COND_LEU /* unsigned */
|
||||
TCG_COND_GTU /* unsigned */
|
||||
|
||||
********* Arithmetic
|
||||
|
||||
* add_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1+t2
|
||||
|
||||
* sub_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1-t2
|
||||
|
||||
* mul_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1*t2
|
||||
|
||||
* div_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1/t2 (signed). Undefined behavior if division by zero or overflow.
|
||||
|
||||
* divu_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1/t2 (unsigned). Undefined behavior if division by zero.
|
||||
|
||||
* rem_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1%t2 (signed). Undefined behavior if division by zero or overflow.
|
||||
|
||||
* remu_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1%t2 (unsigned). Undefined behavior if division by zero.
|
||||
|
||||
* and_i32/i64 t0, t1, t2
|
||||
|
||||
********* Logical
|
||||
|
||||
t0=t1&t2
|
||||
|
||||
* or_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1|t2
|
||||
|
||||
* xor_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1^t2
|
||||
|
||||
* shl_i32/i64 t0, t1, t2
|
||||
|
||||
********* Shifts
|
||||
|
||||
* shl_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1 << t2. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
|
||||
|
||||
* shr_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1 >> t2 (unsigned). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
|
||||
|
||||
* sar_i32/i64 t0, t1, t2
|
||||
|
||||
t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
|
||||
|
||||
********* Misc
|
||||
|
||||
* mov_i32/i64 t0, t1
|
||||
|
||||
t0 = t1
|
||||
|
||||
Move t1 to t0 (both operands must have the same type).
|
||||
|
||||
* ext8s_i32/i64 t0, t1
|
||||
ext16s_i32/i64 t0, t1
|
||||
ext32s_i64 t0, t1
|
||||
|
||||
8, 16 or 32 bit sign extension (both operands must have the same type)
|
||||
|
||||
* bswap16_i32 t0, t1
|
||||
|
||||
16 bit byte swap on a 32 bit value. The two high order bytes must be set
|
||||
to zero.
|
||||
|
||||
* bswap_i32 t0, t1
|
||||
|
||||
32 bit byte swap
|
||||
|
||||
* bswap_i64 t0, t1
|
||||
|
||||
64 bit byte swap
|
||||
|
||||
********* Type conversions
|
||||
|
||||
* ext_i32_i64 t0, t1
|
||||
Convert t1 (32 bit) to t0 (64 bit) and does sign extension
|
||||
|
||||
* extu_i32_i64 t0, t1
|
||||
Convert t1 (32 bit) to t0 (64 bit) and does zero extension
|
||||
|
||||
* trunc_i64_i32 t0, t1
|
||||
Truncate t1 (64 bit) to t0 (32 bit)
|
||||
|
||||
********* Load/Store
|
||||
|
||||
* ld_i32/i64 t0, t1, offset
|
||||
ld8s_i32/i64 t0, t1, offset
|
||||
ld8u_i32/i64 t0, t1, offset
|
||||
ld16s_i32/i64 t0, t1, offset
|
||||
ld16u_i32/i64 t0, t1, offset
|
||||
ld32s_i64 t0, t1, offset
|
||||
ld32u_i64 t0, t1, offset
|
||||
|
||||
t0 = read(t1 + offset)
|
||||
Load 8, 16, 32 or 64 bits with or without sign extension from host memory.
|
||||
offset must be a constant.
|
||||
|
||||
* st_i32/i64 t0, t1, offset
|
||||
st8_i32/i64 t0, t1, offset
|
||||
st16_i32/i64 t0, t1, offset
|
||||
st32_i64 t0, t1, offset
|
||||
|
||||
write(t0, t1 + offset)
|
||||
Write 8, 16, 32 or 64 bits to host memory.
|
||||
|
||||
********* QEMU specific operations
|
||||
|
||||
* tb_exit t0
|
||||
|
||||
Exit the current TB and return the value t0 (word type).
|
||||
|
||||
* goto_tb index
|
||||
|
||||
Exit the current TB and jump to the TB index 'index' (constant) if the
|
||||
current TB was linked to this TB. Otherwise execute the next
|
||||
instructions.
|
||||
|
||||
* qemu_ld_i32/i64 t0, t1, flags
|
||||
qemu_ld8u_i32/i64 t0, t1, flags
|
||||
qemu_ld8s_i32/i64 t0, t1, flags
|
||||
qemu_ld16u_i32/i64 t0, t1, flags
|
||||
qemu_ld16s_i32/i64 t0, t1, flags
|
||||
qemu_ld32u_i64 t0, t1, flags
|
||||
qemu_ld32s_i64 t0, t1, flags
|
||||
|
||||
Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU
|
||||
address type. 'flags' contains the QEMU memory index (selects user or
|
||||
kernel access) for example.
|
||||
|
||||
* qemu_st_i32/i64 t0, t1, flags
|
||||
qemu_st8_i32/i64 t0, t1, flags
|
||||
qemu_st16_i32/i64 t0, t1, flags
|
||||
qemu_st32_i64 t0, t1, flags
|
||||
|
||||
Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU
|
||||
address type. 'flags' contains the QEMU memory index (selects user or
|
||||
kernel access) for example.
|
||||
|
||||
Note 1: Some shortcuts are defined when the last operand is known to be
|
||||
a constant (e.g. addi for add, movi for mov).
|
||||
|
||||
Note 2: When using TCG, the opcodes must never be generated directly
|
||||
as some of them may not be available as "real" opcodes. Always use the
|
||||
function tcg_gen_xxx(args).
|
||||
|
||||
4) Backend
|
||||
|
||||
tcg-target.h contains the target specific definitions. tcg-target.c
|
||||
contains the target specific code.
|
||||
|
||||
4.1) Assumptions
|
||||
|
||||
The target word size (TCG_TARGET_REG_BITS) is expected to be 32 bit or
|
||||
64 bit. It is expected that the pointer has the same size as the word.
|
||||
|
||||
On a 32 bit target, all 64 bit operations are converted to 32 bits. A
|
||||
few specific operations must be implemented to allow it (see add2_i32,
|
||||
sub2_i32, brcond2_i32).
|
||||
|
||||
Floating point operations are not supported in this version. A
|
||||
previous incarnation of the code generator had full support of them,
|
||||
but it is better to concentrate on integer operations first.
|
||||
|
||||
On a 64 bit target, no assumption is made in TCG about the storage of
|
||||
the 32 bit values in 64 bit registers.
|
||||
|
||||
4.2) Constraints
|
||||
|
||||
GCC like constraints are used to define the constraints of every
|
||||
instruction. Memory constraints are not supported in this
|
||||
version. Aliases are specified in the input operands as for GCC.
|
||||
|
||||
A target can define specific register or constant constraints. If an
|
||||
operation uses a constant input constraint which does not allow all
|
||||
constants, it must also accept registers in order to have a fallback.
|
||||
|
||||
The movi_i32 and movi_i64 operations must accept any constants.
|
||||
|
||||
The mov_i32 and mov_i64 operations must accept any registers of the
|
||||
same type.
|
||||
|
||||
The ld/st instructions must accept signed 32 bit constant offsets. It
|
||||
can be implemented by reserving a specific register to compute the
|
||||
address if the offset is too big.
|
||||
|
||||
The ld/st instructions must accept any destination (ld) or source (st)
|
||||
register.
|
||||
|
||||
4.3) Function call assumptions
|
||||
|
||||
- The only supported types for parameters and return value are: 32 and
|
||||
64 bit integers and pointer.
|
||||
- The stack grows downwards.
|
||||
- The first N parameters are passed in registers.
|
||||
- The next parameters are passed on the stack by storing them as words.
|
||||
- Some registers are clobbered during the call.
|
||||
- The function can return 0 or 1 value in registers. On a 32 bit
|
||||
target, functions must be able to return 2 values in registers for
|
||||
64 bit return type.
|
||||
|
||||
5) Migration from dyngen to TCG
|
||||
|
||||
TCG is backward compatible with QEMU "dyngen" operations. It means
|
||||
that TCG instructions can be freely mixed with dyngen operations. It
|
||||
is expected that QEMU targets will be progressively fully converted to
|
||||
TCG. Once a target is fully converted to dyngen, it will be possible
|
||||
to apply more optimizations because more registers will be free for
|
||||
the generated code.
|
||||
|
||||
The exception model is the same as the dyngen one.
|
32
tcg/TODO
Normal file
32
tcg/TODO
Normal file
@ -0,0 +1,32 @@
|
||||
- test macro system
|
||||
|
||||
- test conditional jumps
|
||||
|
||||
- test mul, div, ext8s, ext16s, bswap
|
||||
|
||||
- generate a global TB prologue and epilogue to save/restore registers
|
||||
to/from the CPU state and to reserve a stack frame to optimize
|
||||
helper calls. Modify cpu-exec.c so that it does not use global
|
||||
register variables (except maybe for 'env').
|
||||
|
||||
- fully convert the x86 target. The minimal amount of work includes:
|
||||
- add cc_src, cc_dst and cc_op as globals
|
||||
- disable its eflags optimization (the liveness analysis should
|
||||
suffice)
|
||||
- move complicated operations to helpers (in particular FPU, SSE, MMX).
|
||||
|
||||
- optimize the x86 target:
|
||||
- move some or all the registers as globals
|
||||
- use the TB prologue and epilogue to have QEMU target registers in
|
||||
pre assigned host registers.
|
||||
|
||||
Ideas:
|
||||
|
||||
- Move the slow part of the qemu_ld/st ops after the end of the TB.
|
||||
|
||||
- Experiment: change instruction storage to simplify macro handling
|
||||
and to handle dynamic allocation and see if the translation speed is
|
||||
OK.
|
||||
|
||||
- change exception syntax to get closer to QOP system (exception
|
||||
parameters given with a specific instruction).
|
1163
tcg/i386/tcg-target.c
Normal file
1163
tcg/i386/tcg-target.c
Normal file
File diff suppressed because it is too large
Load Diff
54
tcg/i386/tcg-target.h
Normal file
54
tcg/i386/tcg-target.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#define TCG_TARGET_I386 1
|
||||
|
||||
#define TCG_TARGET_REG_BITS 32
|
||||
//#define TCG_TARGET_WORDS_BIGENDIAN
|
||||
|
||||
#define TCG_TARGET_NB_REGS 8
|
||||
|
||||
enum {
|
||||
TCG_REG_EAX = 0,
|
||||
TCG_REG_ECX,
|
||||
TCG_REG_EDX,
|
||||
TCG_REG_EBX,
|
||||
TCG_REG_ESP,
|
||||
TCG_REG_EBP,
|
||||
TCG_REG_ESI,
|
||||
TCG_REG_EDI,
|
||||
};
|
||||
|
||||
/* used for function call generation */
|
||||
#define TCG_REG_CALL_STACK TCG_REG_ESP
|
||||
#define TCG_TARGET_STACK_ALIGN 16
|
||||
|
||||
/* Note: must be synced with dyngen-exec.h */
|
||||
#define TCG_AREG0 TCG_REG_EBP
|
||||
#define TCG_AREG1 TCG_REG_EBX
|
||||
#define TCG_AREG2 TCG_REG_ESI
|
||||
#define TCG_AREG3 TCG_REG_EDI
|
||||
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
482
tcg/tcg-dyngen.c
Normal file
482
tcg/tcg-dyngen.c
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "osdep.h"
|
||||
|
||||
#include "tcg.h"
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
#if defined(__sparc__) || defined(__arm__)
|
||||
void __op_gen_label1(){}
|
||||
void __op_gen_label2(){}
|
||||
void __op_gen_label3(){}
|
||||
#else
|
||||
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
||||
#endif
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#if 0
|
||||
#if defined(__s390__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#elif defined(__ia64__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
while (start < stop) {
|
||||
asm volatile ("fc %0" :: "r"(start));
|
||||
start += 32;
|
||||
}
|
||||
asm volatile (";;sync.i;;srlz.i;;");
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
start &= ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
register unsigned long _end __asm ("a2") = stop;
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#elif defined(__mc68000)
|
||||
|
||||
# include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#elif defined(__mips__)
|
||||
|
||||
#include <sys/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
_flush_cache ((void *)start, stop - start, BCACHE);
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define ARM_LDR_TABLE_SIZE 1024
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
unsigned type:2;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
uint32_t mask;
|
||||
|
||||
data_size = (data_end - data_start) << 2;
|
||||
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
if (offset < 0) {
|
||||
fprintf(stderr, "Negative constant pool offset\n");
|
||||
tcg_abort();
|
||||
}
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
mask = ~0x00800fff;
|
||||
if (offset >= 4096) {
|
||||
fprintf(stderr, "Bad ldr offset\n");
|
||||
tcg_abort();
|
||||
}
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
mask = ~0x008000ff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad ldc offset\n");
|
||||
tcg_abort();
|
||||
}
|
||||
break;
|
||||
case 2: /* add */
|
||||
mask = ~0xfff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad add offset\n");
|
||||
tcg_abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad pc relative fixup\n");
|
||||
tcg_abort();
|
||||
}
|
||||
insn = *ptr & mask;
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
insn |= offset | 0x00800000;
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
insn |= (offset >> 2) | 0x00800000;
|
||||
break;
|
||||
case 2: /* add */
|
||||
insn |= (offset >> 2) | 0xf00;
|
||||
break;
|
||||
}
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifdef __ia64
|
||||
|
||||
/* Patch instruction with "val" where "mask" has 1 bits. */
|
||||
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
|
||||
{
|
||||
uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
|
||||
# define insn_mask ((1UL << 41) - 1)
|
||||
unsigned long shift;
|
||||
|
||||
b0 = b[0]; b1 = b[1];
|
||||
shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
|
||||
if (shift >= 64) {
|
||||
m1 = mask << (shift - 64);
|
||||
v1 = val << (shift - 64);
|
||||
} else {
|
||||
m0 = mask << shift; m1 = mask >> (64 - shift);
|
||||
v0 = val << shift; v1 = val >> (64 - shift);
|
||||
b[0] = (b0 & ~m0) | (v0 & m0);
|
||||
}
|
||||
b[1] = (b1 & ~m1) | (v1 & m1);
|
||||
}
|
||||
|
||||
static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
|
||||
{
|
||||
ia64_patch(insn_addr,
|
||||
0x011ffffe000UL,
|
||||
( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
|
||||
| ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
|
||||
ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
|
||||
}
|
||||
|
||||
static inline void ia64_imm64 (void *insn, uint64_t val)
|
||||
{
|
||||
/* Ignore the slot number of the relocation; GCC and Intel
|
||||
toolchains differed for some time on whether IMM64 relocs are
|
||||
against slot 1 (Intel) or slot 2 (GCC). */
|
||||
uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
||||
|
||||
ia64_patch(insn_addr + 2,
|
||||
0x01fffefe000UL,
|
||||
( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
|
||||
| ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */
|
||||
| ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)
|
||||
);
|
||||
ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
|
||||
}
|
||||
|
||||
static inline void ia64_imm60b (void *insn, uint64_t val)
|
||||
{
|
||||
/* Ignore the slot number of the relocation; GCC and Intel
|
||||
toolchains differed for some time on whether IMM64 relocs are
|
||||
against slot 1 (Intel) or slot 2 (GCC). */
|
||||
uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
||||
|
||||
if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
|
||||
fprintf(stderr, "%s: value %ld out of IMM60 range\n",
|
||||
__FUNCTION__, (int64_t) val);
|
||||
ia64_patch_imm60(insn_addr + 2, val);
|
||||
}
|
||||
|
||||
static inline void ia64_imm22 (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) >= (1 << 22))
|
||||
fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
|
||||
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
|
||||
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
|
||||
the effect of turning "addl rX=imm22,rY" into "addl
|
||||
rX=imm22,r0". */
|
||||
static inline void ia64_imm22_r0 (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) >= (1 << 22))
|
||||
fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
|
||||
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
|
||||
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
static inline void ia64_imm21b (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 20) >= (1 << 21))
|
||||
fprintf(stderr, "%s: value %li out of IMM21b range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x11ffffe000UL,
|
||||
( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
|
||||
| ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
static inline void ia64_nop_b (void *insn)
|
||||
{
|
||||
ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
|
||||
}
|
||||
|
||||
static inline void ia64_ldxmov(void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) < (1 << 22))
|
||||
ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
|
||||
}
|
||||
|
||||
static inline int ia64_patch_ltoff(void *insn, uint64_t val,
|
||||
int relaxable)
|
||||
{
|
||||
if (relaxable && (val + (1 << 21) < (1 << 22))) {
|
||||
ia64_imm22_r0(insn, val);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ia64_fixup {
|
||||
struct ia64_fixup *next;
|
||||
void *addr; /* address that needs to be patched */
|
||||
long value;
|
||||
};
|
||||
|
||||
#define IA64_PLT(insn, plt_index) \
|
||||
do { \
|
||||
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
|
||||
fixup->next = plt_fixes; \
|
||||
plt_fixes = fixup; \
|
||||
fixup->addr = (insn); \
|
||||
fixup->value = (plt_index); \
|
||||
plt_offset[(plt_index)] = 1; \
|
||||
} while (0)
|
||||
|
||||
#define IA64_LTOFF(insn, val, relaxable) \
|
||||
do { \
|
||||
if (ia64_patch_ltoff(insn, val, relaxable)) { \
|
||||
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
|
||||
fixup->next = ltoff_fixes; \
|
||||
ltoff_fixes = fixup; \
|
||||
fixup->addr = (insn); \
|
||||
fixup->value = (val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
|
||||
struct ia64_fixup *ltoff_fixes,
|
||||
uint64_t gp,
|
||||
struct ia64_fixup *plt_fixes,
|
||||
int num_plts,
|
||||
unsigned long *plt_target,
|
||||
unsigned int *plt_offset)
|
||||
{
|
||||
static const uint8_t plt_bundle[] = {
|
||||
0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
|
||||
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
|
||||
};
|
||||
uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start;
|
||||
uint64_t *vp;
|
||||
struct ia64_fixup *fixup;
|
||||
unsigned int offset = 0;
|
||||
struct fdesc {
|
||||
long ip;
|
||||
long gp;
|
||||
} *fdesc;
|
||||
int i;
|
||||
|
||||
if (plt_fixes) {
|
||||
plt_start = gen_code_ptr;
|
||||
|
||||
for (i = 0; i < num_plts; ++i) {
|
||||
if (plt_offset[i]) {
|
||||
plt_offset[i] = offset;
|
||||
offset += sizeof(plt_bundle);
|
||||
|
||||
fdesc = (struct fdesc *) plt_target[i];
|
||||
memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
|
||||
ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
|
||||
ia64_imm60b(gen_code_ptr + 0x12,
|
||||
(fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
|
||||
gen_code_ptr += sizeof(plt_bundle);
|
||||
}
|
||||
}
|
||||
|
||||
for (fixup = plt_fixes; fixup; fixup = fixup->next)
|
||||
ia64_imm21b(fixup->addr,
|
||||
((long) plt_start + plt_offset[fixup->value]
|
||||
- ((long) fixup->addr & ~0xf)) >> 4);
|
||||
}
|
||||
|
||||
got_start = gen_code_ptr;
|
||||
|
||||
/* First, create the GOT: */
|
||||
for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
|
||||
/* first check if we already have this value in the GOT: */
|
||||
for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
|
||||
if (*vp == fixup->value)
|
||||
break;
|
||||
if (vp == (uint64_t *) gen_code_ptr) {
|
||||
/* Nope, we need to put the value in the GOT: */
|
||||
*vp = fixup->value;
|
||||
gen_code_ptr += 8;
|
||||
}
|
||||
ia64_imm22(fixup->addr, (long) vp - gp);
|
||||
}
|
||||
/* Keep code ptr aligned. */
|
||||
if ((long) gen_code_ptr & 15)
|
||||
gen_code_ptr += 8;
|
||||
*gen_code_pp = gen_code_ptr;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr)
|
||||
{
|
||||
uint8_t *gen_code_ptr;
|
||||
|
||||
gen_code_ptr = s->code_ptr;
|
||||
switch(opc) {
|
||||
|
||||
/* op.h is dynamically generated by dyngen.c from op.c */
|
||||
#include "op.h"
|
||||
|
||||
default:
|
||||
tcg_abort();
|
||||
}
|
||||
s->code_ptr = gen_code_ptr;
|
||||
return opparam_ptr;
|
||||
}
|
1175
tcg/tcg-op.h
Normal file
1175
tcg/tcg-op.h
Normal file
File diff suppressed because it is too large
Load Diff
228
tcg/tcg-opc.h
Normal file
228
tcg/tcg-opc.h
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "dyngen-opc.h"
|
||||
|
||||
#ifndef DEF2
|
||||
#define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0)
|
||||
#endif
|
||||
|
||||
/* predefined ops */
|
||||
DEF2(end, 0, 0, 0, 0) /* must be kept first */
|
||||
DEF2(nop, 0, 0, 0, 0)
|
||||
DEF2(nop1, 0, 0, 1, 0)
|
||||
DEF2(nop2, 0, 0, 2, 0)
|
||||
DEF2(nop3, 0, 0, 3, 0)
|
||||
DEF2(nopn, 0, 0, 1, 0) /* variable number of parameters */
|
||||
/* macro handling */
|
||||
DEF2(macro_2, 2, 0, 1, 0)
|
||||
DEF2(macro_start, 0, 0, 2, 0)
|
||||
DEF2(macro_end, 0, 0, 2, 0)
|
||||
DEF2(macro_goto, 0, 0, 3, 0)
|
||||
|
||||
DEF2(set_label, 0, 0, 1, 0)
|
||||
DEF2(call, 0, 1, 2, 0) /* variable number of parameters */
|
||||
DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END)
|
||||
DEF2(br, 0, 0, 1, TCG_OPF_BB_END)
|
||||
|
||||
DEF2(mov_i32, 1, 1, 0, 0)
|
||||
DEF2(movi_i32, 1, 0, 1, 0)
|
||||
/* load/store */
|
||||
DEF2(ld8u_i32, 1, 1, 1, 0)
|
||||
DEF2(ld8s_i32, 1, 1, 1, 0)
|
||||
DEF2(ld16u_i32, 1, 1, 1, 0)
|
||||
DEF2(ld16s_i32, 1, 1, 1, 0)
|
||||
DEF2(ld_i32, 1, 1, 1, 0)
|
||||
DEF2(st8_i32, 0, 2, 1, 0)
|
||||
DEF2(st16_i32, 0, 2, 1, 0)
|
||||
DEF2(st_i32, 0, 2, 1, 0)
|
||||
/* arith */
|
||||
DEF2(add_i32, 1, 2, 0, 0)
|
||||
DEF2(sub_i32, 1, 2, 0, 0)
|
||||
DEF2(mul_i32, 1, 2, 0, 0)
|
||||
#ifdef TCG_TARGET_HAS_div_i32
|
||||
DEF2(div_i32, 1, 2, 0, 0)
|
||||
DEF2(divu_i32, 1, 2, 0, 0)
|
||||
DEF2(rem_i32, 1, 2, 0, 0)
|
||||
DEF2(remu_i32, 1, 2, 0, 0)
|
||||
#else
|
||||
DEF2(div2_i32, 2, 3, 0, 0)
|
||||
DEF2(divu2_i32, 2, 3, 0, 0)
|
||||
#endif
|
||||
DEF2(and_i32, 1, 2, 0, 0)
|
||||
DEF2(or_i32, 1, 2, 0, 0)
|
||||
DEF2(xor_i32, 1, 2, 0, 0)
|
||||
/* shifts */
|
||||
DEF2(shl_i32, 1, 2, 0, 0)
|
||||
DEF2(shr_i32, 1, 2, 0, 0)
|
||||
DEF2(sar_i32, 1, 2, 0, 0)
|
||||
|
||||
DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
DEF2(add2_i32, 2, 4, 0, 0)
|
||||
DEF2(sub2_i32, 2, 4, 0, 0)
|
||||
DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END)
|
||||
DEF2(mulu2_i32, 2, 2, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_ext8s_i32
|
||||
DEF2(ext8s_i32, 1, 1, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_ext16s_i32
|
||||
DEF2(ext16s_i32, 1, 1, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_bswap_i32
|
||||
DEF2(bswap_i32, 1, 1, 0, 0)
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
DEF2(mov_i64, 1, 1, 0, 0)
|
||||
DEF2(movi_i64, 1, 0, 1, 0)
|
||||
/* load/store */
|
||||
DEF2(ld8u_i64, 1, 1, 1, 0)
|
||||
DEF2(ld8s_i64, 1, 1, 1, 0)
|
||||
DEF2(ld16u_i64, 1, 1, 1, 0)
|
||||
DEF2(ld16s_i64, 1, 1, 1, 0)
|
||||
DEF2(ld32u_i64, 1, 1, 1, 0)
|
||||
DEF2(ld32s_i64, 1, 1, 1, 0)
|
||||
DEF2(ld_i64, 1, 1, 1, 0)
|
||||
DEF2(st8_i64, 0, 2, 1, 0)
|
||||
DEF2(st16_i64, 0, 2, 1, 0)
|
||||
DEF2(st32_i64, 0, 2, 1, 0)
|
||||
DEF2(st_i64, 0, 2, 1, 0)
|
||||
/* arith */
|
||||
DEF2(add_i64, 1, 2, 0, 0)
|
||||
DEF2(sub_i64, 1, 2, 0, 0)
|
||||
DEF2(mul_i64, 1, 2, 0, 0)
|
||||
#ifdef TCG_TARGET_HAS_div_i64
|
||||
DEF2(div_i64, 1, 2, 0, 0)
|
||||
DEF2(divu_i64, 1, 2, 0, 0)
|
||||
DEF2(rem_i64, 1, 2, 0, 0)
|
||||
DEF2(remu_i64, 1, 2, 0, 0)
|
||||
#else
|
||||
DEF2(div2_i64, 2, 3, 0, 0)
|
||||
DEF2(divu2_i64, 2, 3, 0, 0)
|
||||
#endif
|
||||
DEF2(and_i64, 1, 2, 0, 0)
|
||||
DEF2(or_i64, 1, 2, 0, 0)
|
||||
DEF2(xor_i64, 1, 2, 0, 0)
|
||||
/* shifts */
|
||||
DEF2(shl_i64, 1, 2, 0, 0)
|
||||
DEF2(shr_i64, 1, 2, 0, 0)
|
||||
DEF2(sar_i64, 1, 2, 0, 0)
|
||||
|
||||
DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END)
|
||||
#ifdef TCG_TARGET_HAS_ext8s_i64
|
||||
DEF2(ext8s_i64, 1, 1, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_ext16s_i64
|
||||
DEF2(ext16s_i64, 1, 1, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_ext32s_i64
|
||||
DEF2(ext32s_i64, 1, 1, 0, 0)
|
||||
#endif
|
||||
#ifdef TCG_TARGET_HAS_bswap_i64
|
||||
DEF2(bswap_i64, 1, 1, 0, 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* QEMU specific */
|
||||
DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END)
|
||||
DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END)
|
||||
/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op
|
||||
constants must be defined */
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 32
|
||||
DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#else
|
||||
DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER)
|
||||
#endif
|
||||
|
||||
#else /* TCG_TARGET_REG_BITS == 32 */
|
||||
|
||||
DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER)
|
||||
|
||||
DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER)
|
||||
|
||||
#endif /* TCG_TARGET_REG_BITS != 32 */
|
||||
|
||||
#undef DEF2
|
68
tcg/tcg-runtime.c
Normal file
68
tcg/tcg-runtime.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "osdep.h"
|
||||
#include "tcg.h"
|
||||
|
||||
int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2)
|
||||
{
|
||||
return arg1 << arg2;
|
||||
}
|
||||
|
||||
int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2)
|
||||
{
|
||||
return (uint64_t)arg1 >> arg2;
|
||||
}
|
||||
|
||||
int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2)
|
||||
{
|
||||
return arg1 >> arg2;
|
||||
}
|
||||
|
||||
int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2)
|
||||
{
|
||||
return arg1 / arg2;
|
||||
}
|
||||
|
||||
int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2)
|
||||
{
|
||||
return arg1 / arg2;
|
||||
}
|
||||
|
||||
uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2)
|
||||
{
|
||||
return arg1 / arg2;
|
||||
}
|
||||
|
||||
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2)
|
||||
{
|
||||
return arg1 / arg2;
|
||||
}
|
||||
|
324
tcg/tcg.h
Normal file
324
tcg/tcg.h
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "tcg-target.h"
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
typedef int32_t tcg_target_long;
|
||||
typedef uint32_t tcg_target_ulong;
|
||||
#define TCG_PRIlx PRIx32
|
||||
#define TCG_PRIld PRId32
|
||||
#elif TCG_TARGET_REG_BITS == 64
|
||||
typedef int64_t tcg_target_long;
|
||||
typedef uint64_t tcg_target_ulong;
|
||||
#define TCG_PRIlx PRIx64
|
||||
#define TCG_PRIld PRId64
|
||||
#else
|
||||
#error unsupported
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_NB_REGS <= 32
|
||||
typedef uint32_t TCGRegSet;
|
||||
#elif TCG_TARGET_NB_REGS <= 64
|
||||
typedef uint64_t TCGRegSet;
|
||||
#else
|
||||
#error unsupported
|
||||
#endif
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "tcg-opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#define tcg_regset_clear(d) (d) = 0
|
||||
#define tcg_regset_set(d, s) (d) = (s)
|
||||
#define tcg_regset_set32(d, reg, val32) (d) |= (val32) << (reg)
|
||||
#define tcg_regset_set_reg(d, r) (d) |= 1 << (r)
|
||||
#define tcg_regset_reset_reg(d, r) (d) &= ~(1 << (r))
|
||||
#define tcg_regset_test_reg(d, r) (((d) >> (r)) & 1)
|
||||
#define tcg_regset_or(d, a, b) (d) = (a) | (b)
|
||||
#define tcg_regset_and(d, a, b) (d) = (a) & (b)
|
||||
#define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b)
|
||||
#define tcg_regset_not(d, a) (d) = ~(a)
|
||||
|
||||
typedef struct TCGRelocation {
|
||||
struct TCGRelocation *next;
|
||||
int type;
|
||||
uint8_t *ptr;
|
||||
tcg_target_long addend;
|
||||
} TCGRelocation;
|
||||
|
||||
typedef struct TCGLabel {
|
||||
int has_value;
|
||||
union {
|
||||
tcg_target_ulong value;
|
||||
TCGRelocation *first_reloc;
|
||||
} u;
|
||||
} TCGLabel;
|
||||
|
||||
typedef struct TCGPool {
|
||||
struct TCGPool *next;
|
||||
int size;
|
||||
uint8_t data[0];
|
||||
} TCGPool;
|
||||
|
||||
#define TCG_POOL_CHUNK_SIZE 32768
|
||||
|
||||
#define TCG_MAX_LABELS 512
|
||||
|
||||
#define TCG_MAX_TEMPS 256
|
||||
|
||||
typedef int TCGType;
|
||||
|
||||
#define TCG_TYPE_I32 0
|
||||
#define TCG_TYPE_I64 1
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#define TCG_TYPE_PTR TCG_TYPE_I32
|
||||
#else
|
||||
#define TCG_TYPE_PTR TCG_TYPE_I64
|
||||
#endif
|
||||
|
||||
typedef tcg_target_ulong TCGArg;
|
||||
|
||||
/* call flags */
|
||||
#define TCG_CALL_TYPE_MASK 0x000f
|
||||
#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */
|
||||
#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
|
||||
#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
|
||||
#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */
|
||||
|
||||
typedef enum {
|
||||
TCG_COND_EQ,
|
||||
TCG_COND_NE,
|
||||
TCG_COND_LT,
|
||||
TCG_COND_GE,
|
||||
TCG_COND_LE,
|
||||
TCG_COND_GT,
|
||||
/* unsigned */
|
||||
TCG_COND_LTU,
|
||||
TCG_COND_GEU,
|
||||
TCG_COND_LEU,
|
||||
TCG_COND_GTU,
|
||||
} TCGCond;
|
||||
|
||||
#define TEMP_VAL_DEAD 0
|
||||
#define TEMP_VAL_REG 1
|
||||
#define TEMP_VAL_MEM 2
|
||||
#define TEMP_VAL_CONST 3
|
||||
|
||||
/* XXX: optimize memory layout */
|
||||
typedef struct TCGTemp {
|
||||
TCGType base_type;
|
||||
TCGType type;
|
||||
int val_type;
|
||||
int reg;
|
||||
tcg_target_long val;
|
||||
int mem_reg;
|
||||
tcg_target_long mem_offset;
|
||||
unsigned int fixed_reg:1;
|
||||
unsigned int mem_coherent:1;
|
||||
unsigned int mem_allocated:1;
|
||||
const char *name;
|
||||
} TCGTemp;
|
||||
|
||||
typedef struct TCGHelperInfo {
|
||||
void *func;
|
||||
const char *name;
|
||||
} TCGHelperInfo;
|
||||
|
||||
typedef struct TCGContext TCGContext;
|
||||
|
||||
typedef void TCGMacroFunc(TCGContext *s, int macro_id, const int *dead_args);
|
||||
|
||||
struct TCGContext {
|
||||
uint8_t *pool_cur, *pool_end;
|
||||
TCGPool *pool_first, *pool_current;
|
||||
TCGLabel *labels;
|
||||
int nb_labels;
|
||||
TCGTemp *temps; /* globals first, temps after */
|
||||
int nb_globals;
|
||||
int nb_temps;
|
||||
/* constant indexes (end of temp array) */
|
||||
int const_start;
|
||||
int const_end;
|
||||
|
||||
/* goto_tb support */
|
||||
uint8_t *code_buf;
|
||||
unsigned long *tb_next;
|
||||
uint16_t *tb_next_offset;
|
||||
uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */
|
||||
|
||||
uint16_t *op_dead_iargs; /* for each operation, each bit tells if the
|
||||
corresponding input argument is dead */
|
||||
/* tells in which temporary a given register is. It does not take
|
||||
into account fixed registers */
|
||||
int reg_to_temp[TCG_TARGET_NB_REGS];
|
||||
TCGRegSet reserved_regs;
|
||||
tcg_target_long current_frame_offset;
|
||||
tcg_target_long frame_start;
|
||||
tcg_target_long frame_end;
|
||||
int frame_reg;
|
||||
|
||||
uint8_t *code_ptr;
|
||||
TCGTemp static_temps[TCG_MAX_TEMPS];
|
||||
|
||||
TCGMacroFunc *macro_func;
|
||||
TCGHelperInfo *helpers;
|
||||
int nb_helpers;
|
||||
int allocated_helpers;
|
||||
};
|
||||
|
||||
extern TCGContext tcg_ctx;
|
||||
extern uint16_t *gen_opc_ptr;
|
||||
extern TCGArg *gen_opparam_ptr;
|
||||
extern uint16_t gen_opc_buf[];
|
||||
extern TCGArg gen_opparam_buf[];
|
||||
|
||||
/* pool based memory allocation */
|
||||
|
||||
void *tcg_malloc_internal(TCGContext *s, int size);
|
||||
void tcg_pool_reset(TCGContext *s);
|
||||
void tcg_pool_delete(TCGContext *s);
|
||||
|
||||
static inline void *tcg_malloc(int size)
|
||||
{
|
||||
TCGContext *s = &tcg_ctx;
|
||||
uint8_t *ptr, *ptr_end;
|
||||
size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
ptr = s->pool_cur;
|
||||
ptr_end = ptr + size;
|
||||
if (unlikely(ptr_end > s->pool_end)) {
|
||||
return tcg_malloc_internal(&tcg_ctx, size);
|
||||
} else {
|
||||
s->pool_cur = ptr_end;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_context_init(TCGContext *s);
|
||||
void tcg_func_start(TCGContext *s);
|
||||
|
||||
int dyngen_code(TCGContext *s, uint8_t *gen_code_buf);
|
||||
int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf,
|
||||
const uint8_t *searched_pc);
|
||||
|
||||
void tcg_set_frame(TCGContext *s, int reg,
|
||||
tcg_target_long start, tcg_target_long size);
|
||||
void tcg_set_macro_func(TCGContext *s, TCGMacroFunc *func);
|
||||
int tcg_global_reg_new(TCGType type, int reg, const char *name);
|
||||
int tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
|
||||
const char *name);
|
||||
int tcg_temp_new(TCGType type);
|
||||
char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGArg arg);
|
||||
|
||||
#define TCG_CT_ALIAS 0x80
|
||||
#define TCG_CT_IALIAS 0x40
|
||||
#define TCG_CT_REG 0x01
|
||||
#define TCG_CT_CONST 0x02 /* any constant of register size */
|
||||
|
||||
typedef struct TCGArgConstraint {
|
||||
uint32_t ct;
|
||||
union {
|
||||
TCGRegSet regs;
|
||||
} u;
|
||||
} TCGArgConstraint;
|
||||
|
||||
#define TCG_MAX_OP_ARGS 16
|
||||
|
||||
#define TCG_OPF_BB_END 0x01 /* instruction defines the end of a basic
|
||||
block */
|
||||
#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */
|
||||
|
||||
typedef struct TCGOpDef {
|
||||
const char *name;
|
||||
uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
|
||||
uint8_t flags;
|
||||
uint16_t copy_size;
|
||||
TCGArgConstraint *args_ct;
|
||||
int *sorted_args;
|
||||
} TCGOpDef;
|
||||
|
||||
typedef struct TCGTargetOpDef {
|
||||
int op;
|
||||
const char *args_ct_str[TCG_MAX_OP_ARGS];
|
||||
} TCGTargetOpDef;
|
||||
|
||||
extern TCGOpDef tcg_op_defs[];
|
||||
|
||||
void tcg_target_init(TCGContext *s);
|
||||
|
||||
#define tcg_abort() \
|
||||
do {\
|
||||
fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\
|
||||
abort();\
|
||||
} while (0)
|
||||
|
||||
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
|
||||
|
||||
void tcg_gen_call(TCGContext *s, TCGArg func, unsigned int flags,
|
||||
unsigned int nb_rets, const TCGArg *rets,
|
||||
unsigned int nb_params, const TCGArg *args1);
|
||||
void tcg_gen_shifti_i64(TCGArg ret, TCGArg arg1,
|
||||
int c, int right, int arith);
|
||||
|
||||
/* only used for debugging purposes */
|
||||
void tcg_register_helper(void *func, const char *name);
|
||||
#define TCG_HELPER(func) tcg_register_helper(func, #func)
|
||||
const char *tcg_helper_get_name(TCGContext *s, void *func);
|
||||
void tcg_dump_ops(TCGContext *s, FILE *outfile);
|
||||
|
||||
void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
|
||||
int tcg_const_i32(int32_t val);
|
||||
int tcg_const_i64(int64_t val);
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#define tcg_const_ptr tcg_const_i32
|
||||
#define tcg_add_ptr tcg_add_i32
|
||||
#define tcg_sub_ptr tcg_sub_i32
|
||||
#else
|
||||
#define tcg_const_ptr tcg_const_i64
|
||||
#define tcg_add_ptr tcg_add_i64
|
||||
#define tcg_sub_ptr tcg_sub_i64
|
||||
#endif
|
||||
|
||||
void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
|
||||
int label_index, long addend);
|
||||
void tcg_reg_alloc_start(TCGContext *s);
|
||||
void tcg_reg_alloc_bb_end(TCGContext *s);
|
||||
void tcg_liveness_analysis(TCGContext *s);
|
||||
const TCGArg *tcg_gen_code_op(TCGContext *s, int opc, const TCGArg *args1,
|
||||
unsigned int dead_iargs);
|
||||
|
||||
const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr);
|
||||
|
||||
/* tcg-runtime.c */
|
||||
int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2);
|
||||
int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
|
||||
int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2);
|
||||
int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
|
||||
int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
|
||||
uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
|
||||
uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
|
1227
tcg/x86_64/tcg-target.c
Normal file
1227
tcg/x86_64/tcg-target.c
Normal file
File diff suppressed because it is too large
Load Diff
69
tcg/x86_64/tcg-target.h
Normal file
69
tcg/x86_64/tcg-target.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#define TCG_TARGET_X86_64 1
|
||||
|
||||
#define TCG_TARGET_REG_BITS 64
|
||||
//#define TCG_TARGET_WORDS_BIGENDIAN
|
||||
|
||||
#define TCG_TARGET_NB_REGS 16
|
||||
|
||||
enum {
|
||||
TCG_REG_RAX = 0,
|
||||
TCG_REG_RCX,
|
||||
TCG_REG_RDX,
|
||||
TCG_REG_RBX,
|
||||
TCG_REG_RSP,
|
||||
TCG_REG_RBP,
|
||||
TCG_REG_RSI,
|
||||
TCG_REG_RDI,
|
||||
TCG_REG_R8,
|
||||
TCG_REG_R9,
|
||||
TCG_REG_R10,
|
||||
TCG_REG_R11,
|
||||
TCG_REG_R12,
|
||||
TCG_REG_R13,
|
||||
TCG_REG_R14,
|
||||
TCG_REG_R15,
|
||||
};
|
||||
|
||||
#define TCG_CT_CONST_S32 0x100
|
||||
#define TCG_CT_CONST_U32 0x200
|
||||
|
||||
/* used for function call generation */
|
||||
#define TCG_REG_CALL_STACK TCG_REG_RSP
|
||||
#define TCG_TARGET_STACK_ALIGN 16
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_bswap_i32
|
||||
#define TCG_TARGET_HAS_bswap_i64
|
||||
|
||||
/* Note: must be synced with dyngen-exec.h */
|
||||
#define TCG_AREG0 TCG_REG_R14
|
||||
#define TCG_AREG1 TCG_REG_R15
|
||||
#define TCG_AREG2 TCG_REG_R12
|
||||
#define TCG_AREG3 TCG_REG_R13
|
||||
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user