summaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2011-06-24 13:49:54 -0700
committerRobert Mustacchi <rm@joyent.com>2011-06-24 13:49:54 -0700
commit68396ea9c0fe4f75ce30b1eba2c44c43c13344bb (patch)
tree802587d411d9db461e6500c5b635043315f81c27 /tcg
downloadillumos-kvm-cmd-68396ea9c0fe4f75ce30b1eba2c44c43c13344bb.tar.gz
Initial commit of d32e8d0b8d9e0ef7cf7ab2e74548982972789dfc from qemu-kvm
Diffstat (limited to 'tcg')
-rw-r--r--tcg/LICENSE3
-rw-r--r--tcg/README511
-rw-r--r--tcg/TODO14
-rw-r--r--tcg/arm/tcg-target.c1843
-rw-r--r--tcg/arm/tcg-target.h93
-rw-r--r--tcg/hppa/tcg-target.c1683
-rw-r--r--tcg/hppa/tcg-target.h119
-rw-r--r--tcg/i386/tcg-target.c1982
-rw-r--r--tcg/i386/tcg-target.h126
-rw-r--r--tcg/ia64/tcg-target.c2390
-rw-r--r--tcg/ia64/tcg-target.h156
-rw-r--r--tcg/mips/tcg-target.c1533
-rw-r--r--tcg/mips/tcg-target.h110
-rw-r--r--tcg/ppc/tcg-target.c1922
-rw-r--r--tcg/ppc/tcg-target.h98
-rw-r--r--tcg/ppc64/tcg-target.c1699
-rw-r--r--tcg/ppc64/tcg-target.h109
-rw-r--r--tcg/s390/tcg-target.c2324
-rw-r--r--tcg/s390/tcg-target.h109
-rw-r--r--tcg/sparc/tcg-target.c1569
-rw-r--r--tcg/sparc/tcg-target.h150
-rw-r--r--tcg/tcg-op.h2533
-rw-r--r--tcg/tcg-opc.h310
-rw-r--r--tcg/tcg-runtime.h18
-rw-r--r--tcg/tcg.c2175
-rw-r--r--tcg/tcg.h489
26 files changed, 24068 insertions, 0 deletions
diff --git a/tcg/LICENSE b/tcg/LICENSE
new file mode 100644
index 0000000..be817fa
--- /dev/null
+++ b/tcg/LICENSE
@@ -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.
diff --git a/tcg/README b/tcg/README
new file mode 100644
index 0000000..6600122
--- /dev/null
+++ b/tcg/README
@@ -0,0 +1,511 @@
+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 basic
+block. Temporaries are allocated explicitly in each function.
+
+A TCG "local temporary" is a variable only live in a function. Local
+temporaries are allocated explicitly in each function.
+
+A TCG "global" is a variable which is live in all the functions
+(equivalent of a C global variable). 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, local
+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 usually 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)
+
+3.2) Assumptions
+
+* Basic blocks
+
+- Basic blocks end after branches (e.g. brcond_i32 instruction),
+ goto_tb and exit_tb instructions.
+- Basic blocks start after the end of a previous basic block, or at a
+ set_label instruction.
+
+After the end of a basic block, the content of temporaries is
+destroyed, but local temporaries and globals are preserved.
+
+* 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. By default, before calling a helper,
+all globals are stored at their canonical location and it is assumed
+that the function can modify them. This can be overridden by the
+TCG_CALL_CONST function modifier. By default, the helper is allowed to
+modify the CPU state or raise an exception. This can be overridden by
+the TCG_CALL_PURE function modifier, in which case the call to the
+function is removed if the return value is not used.
+
+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 variable to
+ another one. It is also used to remove instructions which compute
+ dead results. The later is especially useful for condition code
+ optimization 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.
+
+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
+
+* neg_i32/i64 t0, t1
+
+t0=-t1 (two's complement)
+
+* 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.
+
+********* Logical
+
+* and_i32/i64 t0, t1, t2
+
+t0=t1&t2
+
+* or_i32/i64 t0, t1, t2
+
+t0=t1|t2
+
+* xor_i32/i64 t0, t1, t2
+
+t0=t1^t2
+
+* not_i32/i64 t0, t1
+
+t0=~t1
+
+* andc_i32/i64 t0, t1, t2
+
+t0=t1&~t2
+
+* eqv_i32/i64 t0, t1, t2
+
+t0=~(t1^t2), or equivalently, t0=t1^~t2
+
+* nand_i32/i64 t0, t1, t2
+
+t0=~(t1&t2)
+
+* nor_i32/i64 t0, t1, t2
+
+t0=~(t1|t2)
+
+* orc_i32/i64 t0, t1, t2
+
+t0=t1|~t2
+
+********* Shifts/Rotates
+
+* 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)
+
+* rotl_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* rotr_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the right. 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
+ext8u_i32/i64 t0, t1
+ext16s_i32/i64 t0, t1
+ext16u_i32/i64 t0, t1
+ext32s_i64 t0, t1
+ext32u_i64 t0, t1
+
+8, 16 or 32 bit sign/zero extension (both operands must have the same type)
+
+* bswap16_i32/i64 t0, t1
+
+16 bit byte swap on a 32/64 bit value. It assumes that the two/six high order
+bytes are set to zero.
+
+* bswap32_i32/i64 t0, t1
+
+32 bit byte swap on a 32/64 bit value. With a 64 bit value, it assumes that
+the four high order bytes are set to zero.
+
+* bswap64_i64 t0, t1
+
+64 bit byte swap
+
+* discard_i32/i64 t0
+
+Indicate that the value of t0 won't be used later. It is useful to
+force dead code elimination.
+
+* deposit_i32/i64 dest, t1, t2, pos, len
+
+Deposit T2 as a bitfield into T1, placing the result in DEST.
+The bitfield is described by POS/LEN, which are immediate values:
+
+ LEN - the length of the bitfield
+ POS - the position of the first bit, counting from the LSB
+
+For example, pos=8, len=4 indicates a 4-bit field at bit 8.
+This operation would be equivalent to
+
+ dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
+
+
+********* Conditional moves
+
+* setcond_i32/i64 cond, dest, t1, t2
+
+dest = (t1 cond t2)
+
+Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0.
+
+********* 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)
+
+* concat_i32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half
+from t2 (32 bit).
+
+* concat32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half
+from t2 (64 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.
+
+********* 64-bit target on 32-bit host support
+
+The following opcodes are internal to TCG. Thus they are to be implemented by
+32-bit host code generators, but are not to be emitted by guest translators.
+They are emitted as needed by inline functions within "tcg-op.h".
+
+* brcond2_i32 cond, t0_low, t0_high, t1_low, t1_high, label
+
+Similar to brcond, except that the 64-bit values T0 and T1
+are formed from two 32-bit arguments.
+
+* add2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+* sub2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high
+
+Similar to add/sub, except that the 64-bit inputs T1 and T2 are
+formed from two 32-bit arguments, and the 64-bit output T0
+is returned in two 32-bit outputs.
+
+* mulu2_i32 t0_low, t0_high, t1, t2
+
+Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding
+the full 64-bit product T0. The later is returned in two 32-bit outputs.
+
+* setcond2_i32 cond, dest, t1_low, t1_high, t2_low, t2_high
+
+Similar to setcond, except that the 64-bit values T1 and T2 are
+formed from two 32-bit arguments. The result is a 32-bit value.
+
+********* QEMU specific operations
+
+* exit_tb 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_ld8u t0, t1, flags
+qemu_ld8s t0, t1, flags
+qemu_ld16u t0, t1, flags
+qemu_ld16s t0, t1, flags
+qemu_ld32 t0, t1, flags
+qemu_ld32u t0, t1, flags
+qemu_ld32s t0, t1, flags
+qemu_ld64 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.
+
+Note that "qemu_ld32" implies a 32-bit result, while "qemu_ld32u" and
+"qemu_ld32s" imply a 64-bit result appropriately extended from 32 bits.
+
+* qemu_st8 t0, t1, flags
+qemu_st16 t0, t1, flags
+qemu_st32 t0, t1, flags
+qemu_st64 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.
+
+The same register may be used for both an input and an output, even when
+they are not explicitly aliased. If an op expands to multiple target
+instructions then care must be taken to avoid clobbering input values.
+GCC style "early clobber" outputs are not currently supported.
+
+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) Recommended coding rules for best performance
+
+- Use globals to represent the parts of the QEMU CPU state which are
+ often modified, e.g. the integer registers and the condition
+ codes. TCG will be able to use host registers to store them.
+
+- Avoid globals stored in fixed registers. They must be used only to
+ store the pointer to the CPU state and possibly to store a pointer
+ to a register window.
+
+- Use temporaries. Use local temporaries only when really needed,
+ e.g. when you need to use a value after a jump. Local temporaries
+ introduce a performance hit in the current TCG implementation: their
+ content is saved to memory at end of each basic block.
+
+- Free temporaries and local temporaries when they are no longer used
+ (tcg_temp_free). Since tcg_const_x() also creates a temporary, you
+ should free it after it is used. Freeing temporaries does not yield
+ a better generated code, but it reduces the memory usage of TCG and
+ the speed of the translation.
+
+- Don't hesitate to use helpers for complicated or seldom used target
+ instructions. There is little performance advantage in using TCG to
+ implement target instructions taking more than about twenty TCG
+ instructions.
+
+- Use the 'discard' instruction if you know that TCG won't be able to
+ prove that a given global is "dead" at a given program point. The
+ x86 target uses it to improve the condition codes optimisation.
diff --git a/tcg/TODO b/tcg/TODO
new file mode 100644
index 0000000..0747847
--- /dev/null
+++ b/tcg/TODO
@@ -0,0 +1,14 @@
+- Add new instructions such as: clz, ctz, popcnt.
+
+- See if it is worth exporting mul2, mulu2, div2, divu2.
+
+- Support of globals saved in fixed registers between TBs.
+
+Ideas:
+
+- Move the slow part of the qemu_ld/st ops after the end of the TB.
+
+- Change exception syntax to get closer to QOP system (exception
+ parameters given with a specific instruction).
+
+- Add float and vector support.
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
new file mode 100644
index 0000000..918e2f7
--- /dev/null
+++ b/tcg/arm/tcg-target.c
@@ -0,0 +1,1843 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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.
+ */
+
+#if defined(__ARM_ARCH_7__) || \
+ defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7EM__) || \
+ defined(__ARM_ARCH_7M__) || \
+ defined(__ARM_ARCH_7R__)
+#define USE_ARMV7_INSTRUCTIONS
+#endif
+
+#if defined(USE_ARMV7_INSTRUCTIONS) || \
+ defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6K__) || \
+ defined(__ARM_ARCH_6T2__) || \
+ defined(__ARM_ARCH_6Z__) || \
+ defined(__ARM_ARCH_6ZK__)
+#define USE_ARMV6_INSTRUCTIONS
+#endif
+
+#if defined(USE_ARMV6_INSTRUCTIONS) || \
+ defined(__ARM_ARCH_5T__) || \
+ defined(__ARM_ARCH_5TE__) || \
+ defined(__ARM_ARCH_5TEJ__)
+#define USE_ARMV5_INSTRUCTIONS
+#endif
+
+#ifdef USE_ARMV5_INSTRUCTIONS
+static const int use_armv5_instructions = 1;
+#else
+static const int use_armv5_instructions = 0;
+#endif
+#undef USE_ARMV5_INSTRUCTIONS
+
+#ifdef USE_ARMV6_INSTRUCTIONS
+static const int use_armv6_instructions = 1;
+#else
+static const int use_armv6_instructions = 0;
+#endif
+#undef USE_ARMV6_INSTRUCTIONS
+
+#ifdef USE_ARMV7_INSTRUCTIONS
+static const int use_armv7_instructions = 1;
+#else
+static const int use_armv7_instructions = 0;
+#endif
+#undef USE_ARMV7_INSTRUCTIONS
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "%r0",
+ "%r1",
+ "%r2",
+ "%r3",
+ "%r4",
+ "%r5",
+ "%r6",
+ "%r7",
+ "%r8",
+ "%r9",
+ "%r10",
+ "%r11",
+ "%r12",
+ "%r13",
+ "%r14",
+ "%pc",
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R13,
+ TCG_REG_R0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R12,
+ TCG_REG_R14,
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+ TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3
+};
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_R0, TCG_REG_R1
+};
+
+static inline void reloc_abs32(void *code_ptr, tcg_target_long target)
+{
+ *(uint32_t *) code_ptr = target;
+}
+
+static inline void reloc_pc24(void *code_ptr, tcg_target_long target)
+{
+ uint32_t offset = ((target - ((tcg_target_long) code_ptr + 8)) >> 2);
+
+ *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff)
+ | (offset & 0xffffff);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ switch (type) {
+ case R_ARM_ABS32:
+ reloc_abs32(code_ptr, value);
+ break;
+
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ default:
+ tcg_abort();
+
+ case R_ARM_PC24:
+ reloc_pc24(code_ptr, value);
+ break;
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch (ct_str[0]) {
+ case 'I':
+ ct->ct |= TCG_CT_CONST_ARM;
+ break;
+
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+ break;
+
+ /* qemu_ld address */
+ case 'l':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+#ifdef CONFIG_SOFTMMU
+ /* r0 and r1 will be overwritten when reading the tlb entry,
+ so don't use these. */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#endif
+ break;
+ case 'L':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+#ifdef CONFIG_SOFTMMU
+ /* r1 is still needed to load data_reg or data_reg2,
+ so don't use it. */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#endif
+ break;
+
+ /* qemu_st address & data_reg */
+ case 's':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+ /* r0 and r1 will be overwritten when reading the tlb entry
+ (softmmu only) and doing the byte swapping, so don't
+ use these. */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+ break;
+ /* qemu_st64 data_reg2 */
+ case 'S':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
+ /* r0 and r1 will be overwritten when reading the tlb entry
+ (softmmu only) and doing the byte swapping, so don't
+ use these. */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#ifdef CONFIG_SOFTMMU
+ /* r2 is still needed to load data_reg, so don't use it. */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#endif
+ break;
+
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+
+ return 0;
+}
+
+static inline uint32_t rotl(uint32_t val, int n)
+{
+ return (val << n) | (val >> (32 - n));
+}
+
+/* ARM immediates for ALU instructions are made of an unsigned 8-bit
+ right-rotated by an even amount between 0 and 30. */
+static inline int encode_imm(uint32_t imm)
+{
+ int shift;
+
+ /* simple case, only lower bits */
+ if ((imm & ~0xff) == 0)
+ return 0;
+ /* then try a simple even shift */
+ shift = ctz32(imm) & ~1;
+ if (((imm >> shift) & ~0xff) == 0)
+ return 32 - shift;
+ /* now try harder with rotations */
+ if ((rotl(imm, 2) & ~0xff) == 0)
+ return 2;
+ if ((rotl(imm, 4) & ~0xff) == 0)
+ return 4;
+ if ((rotl(imm, 6) & ~0xff) == 0)
+ return 6;
+ /* imm can't be encoded */
+ return -1;
+}
+
+static inline int check_fit_imm(uint32_t imm)
+{
+ return encode_imm(imm) >= 0;
+}
+
+/* Test if a constant matches the constraint.
+ * TODO: define constraints for:
+ *
+ * ldr/str offset: between -0xfff and 0xfff
+ * ldrh/strh offset: between -0xff and 0xff
+ * mov operand2: values represented with x << (2 * y), x < 0x100
+ * add, sub, eor...: ditto
+ */
+static inline int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val))
+ return 1;
+ else
+ return 0;
+}
+
+enum arm_data_opc_e {
+ ARITH_AND = 0x0,
+ ARITH_EOR = 0x1,
+ ARITH_SUB = 0x2,
+ ARITH_RSB = 0x3,
+ ARITH_ADD = 0x4,
+ ARITH_ADC = 0x5,
+ ARITH_SBC = 0x6,
+ ARITH_RSC = 0x7,
+ ARITH_TST = 0x8,
+ ARITH_CMP = 0xa,
+ ARITH_CMN = 0xb,
+ ARITH_ORR = 0xc,
+ ARITH_MOV = 0xd,
+ ARITH_BIC = 0xe,
+ ARITH_MVN = 0xf,
+};
+
+#define TO_CPSR(opc) \
+ ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20)
+
+#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00)
+#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20)
+#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40)
+#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60)
+#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10)
+#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30)
+#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50)
+#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70)
+
+enum arm_cond_code_e {
+ COND_EQ = 0x0,
+ COND_NE = 0x1,
+ COND_CS = 0x2, /* Unsigned greater or equal */
+ COND_CC = 0x3, /* Unsigned less than */
+ COND_MI = 0x4, /* Negative */
+ COND_PL = 0x5, /* Zero or greater */
+ COND_VS = 0x6, /* Overflow */
+ COND_VC = 0x7, /* No overflow */
+ COND_HI = 0x8, /* Unsigned greater than */
+ COND_LS = 0x9, /* Unsigned less or equal */
+ COND_GE = 0xa,
+ COND_LT = 0xb,
+ COND_GT = 0xc,
+ COND_LE = 0xd,
+ COND_AL = 0xe,
+};
+
+static const uint8_t tcg_cond_to_arm_cond[10] = {
+ [TCG_COND_EQ] = COND_EQ,
+ [TCG_COND_NE] = COND_NE,
+ [TCG_COND_LT] = COND_LT,
+ [TCG_COND_GE] = COND_GE,
+ [TCG_COND_LE] = COND_LE,
+ [TCG_COND_GT] = COND_GT,
+ /* unsigned */
+ [TCG_COND_LTU] = COND_CC,
+ [TCG_COND_GEU] = COND_CS,
+ [TCG_COND_LEU] = COND_LS,
+ [TCG_COND_GTU] = COND_HI,
+};
+
+static inline void tcg_out_bx(TCGContext *s, int cond, int rn)
+{
+ tcg_out32(s, (cond << 28) | 0x012fff10 | rn);
+}
+
+static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
+{
+ tcg_out32(s, (cond << 28) | 0x0a000000 |
+ (((offset - 8) >> 2) & 0x00ffffff));
+}
+
+static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
+{
+ /* We pay attention here to not modify the branch target by skipping
+ the corresponding bytes. This ensure that caches and memory are
+ kept coherent during retranslation. */
+#ifdef HOST_WORDS_BIGENDIAN
+ tcg_out8(s, (cond << 4) | 0x0a);
+ s->code_ptr += 3;
+#else
+ s->code_ptr += 3;
+ tcg_out8(s, (cond << 4) | 0x0a);
+#endif
+}
+
+static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset)
+{
+ tcg_out32(s, (cond << 28) | 0x0b000000 |
+ (((offset - 8) >> 2) & 0x00ffffff));
+}
+
+static inline void tcg_out_blx(TCGContext *s, int cond, int rn)
+{
+ tcg_out32(s, (cond << 28) | 0x012fff30 | rn);
+}
+
+static inline void tcg_out_dat_reg(TCGContext *s,
+ int cond, int opc, int rd, int rn, int rm, int shift)
+{
+ tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) |
+ (rn << 16) | (rd << 12) | shift | rm);
+}
+
+static inline void tcg_out_dat_reg2(TCGContext *s,
+ int cond, int opc0, int opc1, int rd0, int rd1,
+ int rn0, int rn1, int rm0, int rm1, int shift)
+{
+ if (rd0 == rn1 || rd0 == rm1) {
+ tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+ (rn0 << 16) | (8 << 12) | shift | rm0);
+ tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+ (rn1 << 16) | (rd1 << 12) | shift | rm1);
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
+ } else {
+ tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+ (rn0 << 16) | (rd0 << 12) | shift | rm0);
+ tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+ (rn1 << 16) | (rd1 << 12) | shift | rm1);
+ }
+}
+
+static inline void tcg_out_dat_imm(TCGContext *s,
+ int cond, int opc, int rd, int rn, int im)
+{
+ tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) |
+ (rn << 16) | (rd << 12) | im);
+}
+
+static inline void tcg_out_movi32(TCGContext *s,
+ int cond, int rd, uint32_t arg)
+{
+ /* TODO: This is very suboptimal, we can easily have a constant
+ * pool somewhere after all the instructions. */
+ if ((int)arg < 0 && (int)arg >= -0x100) {
+ tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
+ } else if (use_armv7_instructions) {
+ /* use movw/movt */
+ /* movw */
+ tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
+ | ((arg << 4) & 0x000f0000) | (arg & 0xfff));
+ if (arg & 0xffff0000) {
+ /* movt */
+ tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
+ | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
+ }
+ } else {
+ int opc = ARITH_MOV;
+ int rn = 0;
+
+ do {
+ int i, rot;
+
+ i = ctz32(arg) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+ tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot);
+ arg &= ~(0xff << i);
+
+ opc = ARITH_ORR;
+ rn = rd;
+ } while (arg);
+ }
+}
+
+static inline void tcg_out_mul32(TCGContext *s,
+ int cond, int rd, int rs, int rm)
+{
+ if (rd != rm)
+ tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
+ (rs << 8) | 0x90 | rm);
+ else if (rd != rs)
+ tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
+ (rm << 8) | 0x90 | rs);
+ else {
+ tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) |
+ (rs << 8) | 0x90 | rm);
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
+ }
+}
+
+static inline void tcg_out_umull32(TCGContext *s,
+ int cond, int rd0, int rd1, int rs, int rm)
+{
+ if (rd0 != rm && rd1 != rm)
+ tcg_out32(s, (cond << 28) | 0x800090 |
+ (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
+ else if (rd0 != rs && rd1 != rs)
+ tcg_out32(s, (cond << 28) | 0x800090 |
+ (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
+ else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
+ tcg_out32(s, (cond << 28) | 0x800098 |
+ (rd1 << 16) | (rd0 << 12) | (rs << 8));
+ }
+}
+
+static inline void tcg_out_smull32(TCGContext *s,
+ int cond, int rd0, int rd1, int rs, int rm)
+{
+ if (rd0 != rm && rd1 != rm)
+ tcg_out32(s, (cond << 28) | 0xc00090 |
+ (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
+ else if (rd0 != rs && rd1 != rs)
+ tcg_out32(s, (cond << 28) | 0xc00090 |
+ (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
+ else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
+ tcg_out32(s, (cond << 28) | 0xc00098 |
+ (rd1 << 16) | (rd0 << 12) | (rs << 8));
+ }
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int cond,
+ int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* sxtb */
+ tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rn, SHIFT_IMM_LSL(24));
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rd, SHIFT_IMM_ASR(24));
+ }
+}
+
+static inline void tcg_out_ext8u(TCGContext *s, int cond,
+ int rd, int rn)
+{
+ tcg_out_dat_imm(s, cond, ARITH_AND, rd, rn, 0xff);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int cond,
+ int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* sxth */
+ tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rn, SHIFT_IMM_LSL(16));
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rd, SHIFT_IMM_ASR(16));
+ }
+}
+
+static inline void tcg_out_ext16u(TCGContext *s, int cond,
+ int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* uxth */
+ tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rn, SHIFT_IMM_LSL(16));
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rd, SHIFT_IMM_LSR(16));
+ }
+}
+
+static inline void tcg_out_bswap16s(TCGContext *s, int cond, int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* revsh */
+ tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, rn, SHIFT_IMM_LSL(24));
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, TCG_REG_R8, SHIFT_IMM_ASR(16));
+ tcg_out_dat_reg(s, cond, ARITH_ORR,
+ rd, TCG_REG_R8, rn, SHIFT_IMM_LSR(8));
+ }
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, int cond, int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* rev16 */
+ tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, rn, SHIFT_IMM_LSL(24));
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ TCG_REG_R8, 0, TCG_REG_R8, SHIFT_IMM_LSR(16));
+ tcg_out_dat_reg(s, cond, ARITH_ORR,
+ rd, TCG_REG_R8, rn, SHIFT_IMM_LSR(8));
+ }
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int cond, int rd, int rn)
+{
+ if (use_armv6_instructions) {
+ /* rev */
+ tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_EOR,
+ TCG_REG_R8, rn, rn, SHIFT_IMM_ROR(16));
+ tcg_out_dat_imm(s, cond, ARITH_BIC,
+ TCG_REG_R8, TCG_REG_R8, 0xff | 0x800);
+ tcg_out_dat_reg(s, cond, ARITH_MOV,
+ rd, 0, rn, SHIFT_IMM_ROR(8));
+ tcg_out_dat_reg(s, cond, ARITH_EOR,
+ rd, rd, TCG_REG_R8, SHIFT_IMM_LSR(8));
+ }
+}
+
+static inline void tcg_out_ld32_12(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x05900000 |
+ (rn << 16) | (rd << 12) | (im & 0xfff));
+ else
+ tcg_out32(s, (cond << 28) | 0x05100000 |
+ (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_st32_12(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x05800000 |
+ (rn << 16) | (rd << 12) | (im & 0xfff));
+ else
+ tcg_out32(s, (cond << 28) | 0x05000000 |
+ (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_ld32_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07900000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st32_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07800000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+/* Register pre-increment with base writeback. */
+static inline void tcg_out_ld32_rwb(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07b00000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st32_rwb(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07a00000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld16u_8(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x01d000b0 |
+ (rn << 16) | (rd << 12) |
+ ((im & 0xf0) << 4) | (im & 0xf));
+ else
+ tcg_out32(s, (cond << 28) | 0x015000b0 |
+ (rn << 16) | (rd << 12) |
+ (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_st16_8(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x01c000b0 |
+ (rn << 16) | (rd << 12) |
+ ((im & 0xf0) << 4) | (im & 0xf));
+ else
+ tcg_out32(s, (cond << 28) | 0x014000b0 |
+ (rn << 16) | (rd << 12) |
+ (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld16u_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x019000b0 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st16_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x018000b0 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld16s_8(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x01d000f0 |
+ (rn << 16) | (rd << 12) |
+ ((im & 0xf0) << 4) | (im & 0xf));
+ else
+ tcg_out32(s, (cond << 28) | 0x015000f0 |
+ (rn << 16) | (rd << 12) |
+ (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld16s_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x019000f0 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld8_12(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x05d00000 |
+ (rn << 16) | (rd << 12) | (im & 0xfff));
+ else
+ tcg_out32(s, (cond << 28) | 0x05500000 |
+ (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_st8_12(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x05c00000 |
+ (rn << 16) | (rd << 12) | (im & 0xfff));
+ else
+ tcg_out32(s, (cond << 28) | 0x05400000 |
+ (rn << 16) | (rd << 12) | ((-im) & 0xfff));
+}
+
+static inline void tcg_out_ld8_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07d00000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_st8_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x07c00000 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld8s_8(TCGContext *s, int cond,
+ int rd, int rn, tcg_target_long im)
+{
+ if (im >= 0)
+ tcg_out32(s, (cond << 28) | 0x01d000d0 |
+ (rn << 16) | (rd << 12) |
+ ((im & 0xf0) << 4) | (im & 0xf));
+ else
+ tcg_out32(s, (cond << 28) | 0x015000d0 |
+ (rn << 16) | (rd << 12) |
+ (((-im) & 0xf0) << 4) | ((-im) & 0xf));
+}
+
+static inline void tcg_out_ld8s_r(TCGContext *s, int cond,
+ int rd, int rn, int rm)
+{
+ tcg_out32(s, (cond << 28) | 0x019000d0 |
+ (rn << 16) | (rd << 12) | rm);
+}
+
+static inline void tcg_out_ld32u(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xfff || offset < -0xfff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_ld32_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st32(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xfff || offset < -0xfff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_st32_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld16u(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xff || offset < -0xff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_ld16u_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld16s(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xff || offset < -0xff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_ld16s_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st16(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xff || offset < -0xff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_st16_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_st16_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld8u(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xfff || offset < -0xfff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_ld8_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_ld8s(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xff || offset < -0xff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_ld8s_8(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_st8(TCGContext *s, int cond,
+ int rd, int rn, int32_t offset)
+{
+ if (offset > 0xfff || offset < -0xfff) {
+ tcg_out_movi32(s, cond, TCG_REG_R8, offset);
+ tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8);
+ } else
+ tcg_out_st8_12(s, cond, rd, rn, offset);
+}
+
+static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
+{
+ int32_t val;
+
+ val = addr - (tcg_target_long) s->code_ptr;
+ if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
+ tcg_out_b(s, cond, val);
+ else {
+#if 1
+ tcg_abort();
+#else
+ if (cond == COND_AL) {
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+ tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
+ } else {
+ tcg_out_movi32(s, cond, TCG_REG_R8, val - 8);
+ tcg_out_dat_reg(s, cond, ARITH_ADD,
+ TCG_REG_PC, TCG_REG_PC,
+ TCG_REG_R8, SHIFT_IMM_LSL(0));
+ }
+#endif
+ }
+}
+
+static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr)
+{
+ int32_t val;
+
+ val = addr - (tcg_target_long) s->code_ptr;
+ if (val < 0x01fffffd && val > -0x01fffffd)
+ tcg_out_bl(s, cond, val);
+ else {
+#if 1
+ tcg_abort();
+#else
+ if (cond == COND_AL) {
+ tcg_out_dat_imm(s, cond, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4);
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+ tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
+ } else {
+ tcg_out_movi32(s, cond, TCG_REG_R9, addr);
+ tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
+ TCG_REG_PC, SHIFT_IMM_LSL(0));
+ tcg_out_bx(s, cond, TCG_REG_R9);
+ }
+#endif
+ }
+}
+
+static inline void tcg_out_callr(TCGContext *s, int cond, int arg)
+{
+ if (use_armv5_instructions) {
+ tcg_out_blx(s, cond, arg);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
+ TCG_REG_PC, SHIFT_IMM_LSL(0));
+ tcg_out_bx(s, cond, arg);
+ }
+}
+
+static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value)
+ tcg_out_goto(s, cond, l->u.value);
+ else if (cond == COND_AL) {
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+ tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337);
+ s->code_ptr += 4;
+ } else {
+ /* Probably this should be preferred even for COND_AL... */
+ tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337);
+ tcg_out_b_noaddr(s, cond);
+ }
+}
+
+#ifdef CONFIG_SOFTMMU
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+#endif
+
+#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, data_reg2, bswap;
+#ifdef CONFIG_SOFTMMU
+ int mem_index, s_bits;
+# if TARGET_LONG_BITS == 64
+ int addr_reg2;
+# endif
+ uint32_t *label_ptr;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+ data_reg = *args++;
+ if (opc == 3)
+ data_reg2 = *args++;
+ else
+ data_reg2 = 0; /* suppress warning */
+ addr_reg = *args++;
+#ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+ addr_reg2 = *args++;
+# endif
+ mem_index = *args;
+ s_bits = opc & 3;
+
+ /* Should generate something like the following:
+ * shr r8, addr_reg, #TARGET_PAGE_BITS
+ * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
+ * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
+ */
+# if CPU_TLB_BITS > 8
+# error
+# endif
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_R8,
+ 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
+ tcg_out_dat_imm(s, COND_AL, ARITH_AND,
+ TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
+ tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0,
+ TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
+ /* In the
+ * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))]
+ * below, the offset is likely to exceed 12 bits if mem_index != 0 and
+ * not exceed otherwise, so use an
+ * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
+ * before.
+ */
+ if (mem_index)
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
+ (mem_index << (TLB_SHIFT & 1)) |
+ ((16 - (TLB_SHIFT >> 1)) << 8));
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addr_read));
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
+ TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
+ /* Check alignment. */
+ if (s_bits)
+ tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
+ 0, addr_reg, (1 << s_bits) - 1);
+# if TARGET_LONG_BITS == 64
+ /* XXX: possibly we could use a block data load or writeback in
+ * the first access. */
+ tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addr_read) + 4);
+ tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+ TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
+# endif
+ tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addend));
+
+ switch (opc) {
+ case 0:
+ tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ break;
+ case 0 | 4:
+ tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ break;
+ case 1:
+ tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ if (bswap) {
+ tcg_out_bswap16(s, COND_EQ, data_reg, data_reg);
+ }
+ break;
+ case 1 | 4:
+ if (bswap) {
+ tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ tcg_out_bswap16s(s, COND_EQ, data_reg, data_reg);
+ } else {
+ tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ }
+ break;
+ case 2:
+ default:
+ tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ if (bswap) {
+ tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
+ }
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out_ld32_rwb(s, COND_EQ, data_reg2, TCG_REG_R1, addr_reg);
+ tcg_out_ld32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);
+ tcg_out_bswap32(s, COND_EQ, data_reg2, data_reg2);
+ tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
+ } else {
+ tcg_out_ld32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
+ tcg_out_ld32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
+ }
+ break;
+ }
+
+ label_ptr = (void *) s->code_ptr;
+ tcg_out_b_noaddr(s, COND_EQ);
+
+ /* TODO: move this code to where the constants pool will be */
+ if (addr_reg != TCG_REG_R0) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
+ }
+# if TARGET_LONG_BITS == 32
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
+# else
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+# endif
+ tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_ld_helpers[s_bits] -
+ (tcg_target_long) s->code_ptr);
+
+ switch (opc) {
+ case 0 | 4:
+ tcg_out_ext8s(s, COND_AL, data_reg, TCG_REG_R0);
+ break;
+ case 1 | 4:
+ tcg_out_ext16s(s, COND_AL, data_reg, TCG_REG_R0);
+ break;
+ case 0:
+ case 1:
+ case 2:
+ default:
+ if (data_reg != TCG_REG_R0) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
+ }
+ break;
+ case 3:
+ if (data_reg != TCG_REG_R0) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
+ }
+ if (data_reg2 != TCG_REG_R1) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0));
+ }
+ break;
+ }
+
+ reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
+#else /* !CONFIG_SOFTMMU */
+ if (GUEST_BASE) {
+ uint32_t offset = GUEST_BASE;
+ int i;
+ int rot;
+
+ while (offset) {
+ i = ctz32(offset) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R8, addr_reg,
+ ((offset >> i) & 0xff) | rot);
+ addr_reg = TCG_REG_R8;
+ offset &= ~(0xff << i);
+ }
+ }
+ switch (opc) {
+ case 0:
+ tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
+ break;
+ case 0 | 4:
+ tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0);
+ break;
+ case 1:
+ tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
+ if (bswap) {
+ tcg_out_bswap16(s, COND_AL, data_reg, data_reg);
+ }
+ break;
+ case 1 | 4:
+ if (bswap) {
+ tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
+ tcg_out_bswap16s(s, COND_AL, data_reg, data_reg);
+ } else {
+ tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0);
+ }
+ break;
+ case 2:
+ default:
+ tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
+ if (bswap) {
+ tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
+ }
+ break;
+ case 3:
+ /* TODO: use block load -
+ * check that data_reg2 > data_reg or the other way */
+ if (data_reg == addr_reg) {
+ tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
+ tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
+ } else {
+ tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
+ tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
+ }
+ if (bswap) {
+ tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
+ tcg_out_bswap32(s, COND_AL, data_reg2, data_reg2);
+ }
+ break;
+ }
+#endif
+}
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, data_reg2, bswap;
+#ifdef CONFIG_SOFTMMU
+ int mem_index, s_bits;
+# if TARGET_LONG_BITS == 64
+ int addr_reg2;
+# endif
+ uint32_t *label_ptr;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+ data_reg = *args++;
+ if (opc == 3)
+ data_reg2 = *args++;
+ else
+ data_reg2 = 0; /* suppress warning */
+ addr_reg = *args++;
+#ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+ addr_reg2 = *args++;
+# endif
+ mem_index = *args;
+ s_bits = opc & 3;
+
+ /* Should generate something like the following:
+ * shr r8, addr_reg, #TARGET_PAGE_BITS
+ * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
+ * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
+ */
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
+ tcg_out_dat_imm(s, COND_AL, ARITH_AND,
+ TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
+ tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0,
+ TCG_AREG0, TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
+ /* In the
+ * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))]
+ * below, the offset is likely to exceed 12 bits if mem_index != 0 and
+ * not exceed otherwise, so use an
+ * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
+ * before.
+ */
+ if (mem_index)
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
+ (mem_index << (TLB_SHIFT & 1)) |
+ ((16 - (TLB_SHIFT >> 1)) << 8));
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addr_write));
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
+ TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
+ /* Check alignment. */
+ if (s_bits)
+ tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
+ 0, addr_reg, (1 << s_bits) - 1);
+# if TARGET_LONG_BITS == 64
+ /* XXX: possibly we could use a block data load or writeback in
+ * the first access. */
+ tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addr_write) + 4);
+ tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+ TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
+# endif
+ tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
+ offsetof(CPUState, tlb_table[0][0].addend));
+
+ switch (opc) {
+ case 0:
+ tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ break;
+ case 1:
+ if (bswap) {
+ tcg_out_bswap16(s, COND_EQ, TCG_REG_R0, data_reg);
+ tcg_out_st16_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
+ } else {
+ tcg_out_st16_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ }
+ break;
+ case 2:
+ default:
+ if (bswap) {
+ tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
+ tcg_out_st32_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
+ } else {
+ tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
+ }
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2);
+ tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg);
+ tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
+ tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4);
+ } else {
+ tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
+ tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
+ }
+ break;
+ }
+
+ label_ptr = (void *) s->code_ptr;
+ tcg_out_b_noaddr(s, COND_EQ);
+
+ /* TODO: move this code to where the constants pool will be */
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
+# if TARGET_LONG_BITS == 32
+ switch (opc) {
+ case 0:
+ tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+ break;
+ case 1:
+ tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+ break;
+ case 2:
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
+ break;
+ case 3:
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
+ tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
+ if (data_reg != TCG_REG_R2) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+ }
+ if (data_reg2 != TCG_REG_R3) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
+ }
+ break;
+ }
+# else
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+ switch (opc) {
+ case 0:
+ tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ break;
+ case 1:
+ tcg_out_ext16u(s, COND_AL, TCG_REG_R2, data_reg);
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ break;
+ case 2:
+ if (data_reg != TCG_REG_R2) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+ }
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ break;
+ case 3:
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
+ tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
+ if (data_reg != TCG_REG_R2) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
+ }
+ if (data_reg2 != TCG_REG_R3) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
+ }
+ break;
+ }
+# endif
+
+ tcg_out_bl(s, COND_AL, (tcg_target_long) qemu_st_helpers[s_bits] -
+ (tcg_target_long) s->code_ptr);
+ if (opc == 3)
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+
+ reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
+#else /* !CONFIG_SOFTMMU */
+ if (GUEST_BASE) {
+ uint32_t offset = GUEST_BASE;
+ int i;
+ int rot;
+
+ while (offset) {
+ i = ctz32(offset) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R1, addr_reg,
+ ((offset >> i) & 0xff) | rot);
+ addr_reg = TCG_REG_R1;
+ offset &= ~(0xff << i);
+ }
+ }
+ switch (opc) {
+ case 0:
+ tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
+ break;
+ case 1:
+ if (bswap) {
+ tcg_out_bswap16(s, COND_AL, TCG_REG_R0, data_reg);
+ tcg_out_st16_8(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+ } else {
+ tcg_out_st16_8(s, COND_AL, data_reg, addr_reg, 0);
+ }
+ break;
+ case 2:
+ default:
+ if (bswap) {
+ tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
+ tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+ } else {
+ tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
+ }
+ break;
+ case 3:
+ /* TODO: use block store -
+ * check that data_reg2 > data_reg or the other way */
+ if (bswap) {
+ tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg2);
+ tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
+ tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
+ tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 4);
+ } else {
+ tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
+ tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4);
+ }
+ break;
+ }
+#endif
+}
+
+static uint8_t *tb_ret_addr;
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ int c;
+
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ {
+ uint8_t *ld_ptr = s->code_ptr;
+ if (args[0] >> 8)
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
+ else
+ tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]);
+ tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
+ if (args[0] >> 8) {
+ *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
+ tcg_out32(s, args[0]);
+ }
+ }
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* Direct jump method */
+#if defined(USE_DIRECT_JUMP)
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ tcg_out_b_noaddr(s, COND_AL);
+#else
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ tcg_out32(s, 0);
+#endif
+ } else {
+ /* Indirect jump method */
+#if 1
+ c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8);
+ if (c > 0xfff || c < -0xfff) {
+ tcg_out_movi32(s, COND_AL, TCG_REG_R0,
+ (tcg_target_long) (s->tb_next + args[0]));
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
+ } else
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, c);
+#else
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
+ tcg_out32(s, (tcg_target_long) (s->tb_next + args[0]));
+#endif
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_call:
+ if (const_args[0])
+ tcg_out_call(s, COND_AL, args[0]);
+ else
+ tcg_out_callr(s, COND_AL, args[0]);
+ break;
+ case INDEX_op_jmp:
+ if (const_args[0])
+ tcg_out_goto(s, COND_AL, args[0]);
+ else
+ tcg_out_bx(s, COND_AL, args[0]);
+ break;
+ case INDEX_op_br:
+ tcg_out_goto_label(s, COND_AL, args[0]);
+ break;
+
+ case INDEX_op_ld8u_i32:
+ tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld8s_i32:
+ tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld16u_i32:
+ tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld16s_i32:
+ tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld_i32:
+ tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st8_i32:
+ tcg_out_st8(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st16_i32:
+ tcg_out_st16(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i32:
+ tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_mov_i32:
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+ args[0], 0, args[1], SHIFT_IMM_LSL(0));
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi32(s, COND_AL, args[0], args[1]);
+ break;
+ case INDEX_op_add_i32:
+ c = ARITH_ADD;
+ goto gen_arith;
+ case INDEX_op_sub_i32:
+ c = ARITH_SUB;
+ goto gen_arith;
+ case INDEX_op_and_i32:
+ c = ARITH_AND;
+ goto gen_arith;
+ case INDEX_op_andc_i32:
+ c = ARITH_BIC;
+ goto gen_arith;
+ case INDEX_op_or_i32:
+ c = ARITH_ORR;
+ goto gen_arith;
+ case INDEX_op_xor_i32:
+ c = ARITH_EOR;
+ /* Fall through. */
+ gen_arith:
+ if (const_args[2]) {
+ int rot;
+ rot = encode_imm(args[2]);
+ tcg_out_dat_imm(s, COND_AL, c,
+ args[0], args[1], rotl(args[2], rot) | (rot << 7));
+ } else
+ tcg_out_dat_reg(s, COND_AL, c,
+ args[0], args[1], args[2], SHIFT_IMM_LSL(0));
+ break;
+ case INDEX_op_add2_i32:
+ tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC,
+ args[0], args[1], args[2], args[3],
+ args[4], args[5], SHIFT_IMM_LSL(0));
+ break;
+ case INDEX_op_sub2_i32:
+ tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC,
+ args[0], args[1], args[2], args[3],
+ args[4], args[5], SHIFT_IMM_LSL(0));
+ break;
+ case INDEX_op_neg_i32:
+ tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
+ break;
+ case INDEX_op_not_i32:
+ tcg_out_dat_reg(s, COND_AL,
+ ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0));
+ break;
+ case INDEX_op_mul_i32:
+ tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
+ break;
+ /* XXX: Perhaps args[2] & 0x1f is wrong */
+ case INDEX_op_shl_i32:
+ c = const_args[2] ?
+ SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
+ goto gen_shift32;
+ case INDEX_op_shr_i32:
+ c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
+ SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
+ goto gen_shift32;
+ case INDEX_op_sar_i32:
+ c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
+ SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
+ goto gen_shift32;
+ case INDEX_op_rotr_i32:
+ c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) :
+ SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]);
+ /* Fall through. */
+ gen_shift32:
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
+ break;
+
+ case INDEX_op_rotl_i32:
+ if (const_args[2]) {
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
+ ((0x20 - args[2]) & 0x1f) ?
+ SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) :
+ SHIFT_IMM_LSL(0));
+ } else {
+ tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_R8, args[1], 0x20);
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
+ SHIFT_REG_ROR(TCG_REG_R8));
+ }
+ break;
+
+ case INDEX_op_brcond_i32:
+ if (const_args[1]) {
+ int rot;
+ rot = encode_imm(args[1]);
+ tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
+ args[0], rotl(args[1], rot) | (rot << 7));
+ } else {
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+ args[0], args[1], SHIFT_IMM_LSL(0));
+ }
+ tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]);
+ break;
+ case INDEX_op_brcond2_i32:
+ /* The resulting conditions are:
+ * TCG_COND_EQ --> a0 == a2 && a1 == a3,
+ * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
+ * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
+ * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
+ * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
+ * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
+ */
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+ args[1], args[3], SHIFT_IMM_LSL(0));
+ tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+ args[0], args[2], SHIFT_IMM_LSL(0));
+ tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]);
+ break;
+ case INDEX_op_setcond_i32:
+ if (const_args[2]) {
+ int rot;
+ rot = encode_imm(args[2]);
+ tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
+ args[1], rotl(args[2], rot) | (rot << 7));
+ } else {
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+ args[1], args[2], SHIFT_IMM_LSL(0));
+ }
+ tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
+ ARITH_MOV, args[0], 0, 1);
+ tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
+ ARITH_MOV, args[0], 0, 0);
+ break;
+ case INDEX_op_setcond2_i32:
+ /* See brcond2_i32 comment */
+ tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
+ args[2], args[4], SHIFT_IMM_LSL(0));
+ tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
+ args[1], args[3], SHIFT_IMM_LSL(0));
+ tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[5]],
+ ARITH_MOV, args[0], 0, 1);
+ tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[5])],
+ ARITH_MOV, args[0], 0, 0);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ case INDEX_op_bswap16_i32:
+ tcg_out_bswap16(s, COND_AL, args[0], args[1]);
+ break;
+ case INDEX_op_bswap32_i32:
+ tcg_out_bswap32(s, COND_AL, args[0], args[1]);
+ break;
+
+ case INDEX_op_ext8s_i32:
+ tcg_out_ext8s(s, COND_AL, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i32:
+ tcg_out_ext16s(s, COND_AL, args[0], args[1]);
+ break;
+ case INDEX_op_ext16u_i32:
+ tcg_out_ext16u(s, COND_AL, args[0], args[1]);
+ break;
+
+ default:
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef arm_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ /* TODO: "r", "r", "ri" */
+ { INDEX_op_add_i32, { "r", "r", "rI" } },
+ { INDEX_op_sub_i32, { "r", "r", "rI" } },
+ { INDEX_op_mul_i32, { "r", "r", "r" } },
+ { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+ { INDEX_op_and_i32, { "r", "r", "rI" } },
+ { INDEX_op_andc_i32, { "r", "r", "rI" } },
+ { INDEX_op_or_i32, { "r", "r", "rI" } },
+ { INDEX_op_xor_i32, { "r", "r", "rI" } },
+ { INDEX_op_neg_i32, { "r", "r" } },
+ { INDEX_op_not_i32, { "r", "r" } },
+
+ { INDEX_op_shl_i32, { "r", "r", "ri" } },
+ { INDEX_op_shr_i32, { "r", "r", "ri" } },
+ { INDEX_op_sar_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_brcond_i32, { "r", "rI" } },
+ { INDEX_op_setcond_i32, { "r", "r", "rI" } },
+
+ /* TODO: "r", "r", "r", "r", "ri", "ri" */
+ { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
+ { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
+ { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
+ { INDEX_op_setcond2_i32, { "r", "r", "r", "r", "r" } },
+
+#if TARGET_LONG_BITS == 32
+ { INDEX_op_qemu_ld8u, { "r", "l" } },
+ { INDEX_op_qemu_ld8s, { "r", "l" } },
+ { INDEX_op_qemu_ld16u, { "r", "l" } },
+ { INDEX_op_qemu_ld16s, { "r", "l" } },
+ { INDEX_op_qemu_ld32, { "r", "l" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "l" } },
+
+ { INDEX_op_qemu_st8, { "s", "s" } },
+ { INDEX_op_qemu_st16, { "s", "s" } },
+ { INDEX_op_qemu_st32, { "s", "s" } },
+ { INDEX_op_qemu_st64, { "S", "S", "s" } },
+#else
+ { INDEX_op_qemu_ld8u, { "r", "l", "l" } },
+ { INDEX_op_qemu_ld8s, { "r", "l", "l" } },
+ { INDEX_op_qemu_ld16u, { "r", "l", "l" } },
+ { INDEX_op_qemu_ld16s, { "r", "l", "l" } },
+ { INDEX_op_qemu_ld32, { "r", "l", "l" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "l", "l" } },
+
+ { INDEX_op_qemu_st8, { "s", "s", "s" } },
+ { INDEX_op_qemu_st16, { "s", "s", "s" } },
+ { INDEX_op_qemu_st32, { "s", "s", "s" } },
+ { INDEX_op_qemu_st64, { "S", "S", "s", "s" } },
+#endif
+
+ { INDEX_op_bswap16_i32, { "r", "r" } },
+ { INDEX_op_bswap32_i32, { "r", "r" } },
+
+ { INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
+
+ { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* fail safe */
+ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+ tcg_abort();
+#endif
+
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+ tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+ (1 << TCG_REG_R0) |
+ (1 << TCG_REG_R1) |
+ (1 << TCG_REG_R2) |
+ (1 << TCG_REG_R3) |
+ (1 << TCG_REG_R12) |
+ (1 << TCG_REG_R14));
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
+
+ tcg_add_target_add_op_defs(arm_op_defs);
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_st32(s, COND_AL, arg, arg1, arg2);
+}
+
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val > 0)
+ if (val < 0x100)
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
+ else
+ tcg_abort();
+ else if (val < 0) {
+ if (val > -0x100)
+ tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
+ else
+ tcg_abort();
+ }
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ tcg_out_movi32(s, COND_AL, ret, arg);
+}
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ /* There is no need to save r7, it is used to store the address
+ of the env structure and is not modified by GCC. */
+
+ /* stmdb sp!, { r4 - r6, r8 - r11, lr } */
+ tcg_out32(s, (COND_AL << 28) | 0x092d4f70);
+
+ tcg_out_bx(s, COND_AL, TCG_REG_R0);
+ tb_ret_addr = s->code_ptr;
+
+ /* ldmia sp!, { r4 - r6, r8 - r11, pc } */
+ tcg_out32(s, (COND_AL << 28) | 0x08bd8f70);
+}
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
new file mode 100644
index 0000000..d8d7d94
--- /dev/null
+++ b/tcg/arm/tcg-target.h
@@ -0,0 +1,93 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Fabrice Bellard
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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_ARM 1
+
+#define TCG_TARGET_REG_BITS 32
+#undef TCG_TARGET_WORDS_BIGENDIAN
+#undef TCG_TARGET_STACK_GROWSUP
+
+enum {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_PC,
+};
+
+#define TCG_TARGET_NB_REGS 16
+
+#define TCG_CT_CONST_ARM 0x100
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R13
+#define TCG_TARGET_STACK_ALIGN 8
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+/* optional instructions */
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#undef TCG_TARGET_HAS_ext8u_i32 /* and r0, r1, #0xff */
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+enum {
+ /* Note: must be synced with dyngen-exec.h */
+ TCG_AREG0 = TCG_REG_R7,
+};
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+#if QEMU_GNUC_PREREQ(4, 1)
+ __builtin___clear_cache((char *) start, (char *) stop);
+#else
+ 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));
+#endif
+}
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
new file mode 100644
index 0000000..7f4653e
--- /dev/null
+++ b/tcg/hppa/tcg-target.c
@@ -0,0 +1,1683 @@
+/*
+ * 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.
+ */
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+ "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
+ "%r24", "%r25", "%r26", "%dp", "%ret0", "%ret1", "%sp", "%r31",
+};
+#endif
+
+/* This is an 8 byte temp slot in the stack frame. */
+#define STACK_TEMP_OFS -16
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R16
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+
+ TCG_REG_R17,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+
+ TCG_REG_R26,
+ TCG_REG_R25,
+ TCG_REG_R24,
+ TCG_REG_R23,
+
+ TCG_REG_RET0,
+ TCG_REG_RET1,
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+ TCG_REG_R26,
+ TCG_REG_R25,
+ TCG_REG_R24,
+ TCG_REG_R23,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_RET0,
+ TCG_REG_RET1,
+};
+
+/* True iff val fits a signed field of width BITS. */
+static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
+{
+ return (val << ((sizeof(tcg_target_long) * 8 - bits))
+ >> (sizeof(tcg_target_long) * 8 - bits)) == val;
+}
+
+/* True iff depi can be used to compute (reg | MASK).
+ Accept a bit pattern like:
+ 0....01....1
+ 1....10....0
+ 0..01..10..0
+ Copied from gcc sources. */
+static inline int or_mask_p(tcg_target_ulong mask)
+{
+ if (mask == 0 || mask == -1) {
+ return 0;
+ }
+ mask += mask & -mask;
+ return (mask & (mask - 1)) == 0;
+}
+
+/* True iff depi or extru can be used to compute (reg & mask).
+ Accept a bit pattern like these:
+ 0....01....1
+ 1....10....0
+ 1..10..01..1
+ Copied from gcc sources. */
+static inline int and_mask_p(tcg_target_ulong mask)
+{
+ return or_mask_p(~mask);
+}
+
+static int low_sign_ext(int val, int len)
+{
+ return (((val << 1) & ~(-1u << len)) | ((val >> (len - 1)) & 1));
+}
+
+static int reassemble_12(int as12)
+{
+ return (((as12 & 0x800) >> 11) |
+ ((as12 & 0x400) >> 8) |
+ ((as12 & 0x3ff) << 3));
+}
+
+static int reassemble_17(int as17)
+{
+ return (((as17 & 0x10000) >> 16) |
+ ((as17 & 0x0f800) << 5) |
+ ((as17 & 0x00400) >> 8) |
+ ((as17 & 0x003ff) << 3));
+}
+
+static int reassemble_21(int as21)
+{
+ return (((as21 & 0x100000) >> 20) |
+ ((as21 & 0x0ffe00) >> 8) |
+ ((as21 & 0x000180) << 7) |
+ ((as21 & 0x00007c) << 14) |
+ ((as21 & 0x000003) << 12));
+}
+
+/* ??? Bizzarely, there is no PCREL12F relocation type. I guess all
+ such relocations are simply fully handled by the assembler. */
+#define R_PARISC_PCREL12F R_PARISC_NONE
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ uint32_t *insn_ptr = (uint32_t *)code_ptr;
+ uint32_t insn = *insn_ptr;
+ tcg_target_long pcrel;
+
+ value += addend;
+ pcrel = (value - ((tcg_target_long)code_ptr + 8)) >> 2;
+
+ switch (type) {
+ case R_PARISC_PCREL12F:
+ assert(check_fit_tl(pcrel, 12));
+ /* ??? We assume all patches are forward. See tcg_out_brcond
+ re setting the NUL bit on the branch and eliding the nop. */
+ assert(pcrel >= 0);
+ insn &= ~0x1ffdu;
+ insn |= reassemble_12(pcrel);
+ break;
+ case R_PARISC_PCREL17F:
+ assert(check_fit_tl(pcrel, 17));
+ insn &= ~0x1f1ffdu;
+ insn |= reassemble_17(pcrel);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ *insn_ptr = insn;
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch (ct_str[0]) {
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ break;
+ case 'L': /* qemu_ld/st constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23);
+ break;
+ case 'Z':
+ ct->ct |= TCG_CT_CONST_0;
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_S11;
+ break;
+ case 'J':
+ ct->ct |= TCG_CT_CONST_S5;
+ break;
+ case 'K':
+ ct->ct |= TCG_CT_CONST_MS11;
+ break;
+ case 'M':
+ ct->ct |= TCG_CT_CONST_AND;
+ break;
+ case 'O':
+ ct->ct |= TCG_CT_CONST_OR;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST) {
+ return 1;
+ } else if (ct & TCG_CT_CONST_0) {
+ return val == 0;
+ } else if (ct & TCG_CT_CONST_S5) {
+ return check_fit_tl(val, 5);
+ } else if (ct & TCG_CT_CONST_S11) {
+ return check_fit_tl(val, 11);
+ } else if (ct & TCG_CT_CONST_MS11) {
+ return check_fit_tl(-val, 11);
+ } else if (ct & TCG_CT_CONST_AND) {
+ return and_mask_p(val);
+ } else if (ct & TCG_CT_CONST_OR) {
+ return or_mask_p(val);
+ }
+ return 0;
+}
+
+#define INSN_OP(x) ((x) << 26)
+#define INSN_EXT3BR(x) ((x) << 13)
+#define INSN_EXT3SH(x) ((x) << 10)
+#define INSN_EXT4(x) ((x) << 6)
+#define INSN_EXT5(x) (x)
+#define INSN_EXT6(x) ((x) << 6)
+#define INSN_EXT7(x) ((x) << 6)
+#define INSN_EXT8A(x) ((x) << 6)
+#define INSN_EXT8B(x) ((x) << 5)
+#define INSN_T(x) (x)
+#define INSN_R1(x) ((x) << 16)
+#define INSN_R2(x) ((x) << 21)
+#define INSN_DEP_LEN(x) (32 - (x))
+#define INSN_SHDEP_CP(x) ((31 - (x)) << 5)
+#define INSN_SHDEP_P(x) ((x) << 5)
+#define INSN_COND(x) ((x) << 13)
+#define INSN_IM11(x) low_sign_ext(x, 11)
+#define INSN_IM14(x) low_sign_ext(x, 14)
+#define INSN_IM5(x) (low_sign_ext(x, 5) << 16)
+
+#define COND_NEVER 0
+#define COND_EQ 1
+#define COND_LT 2
+#define COND_LE 3
+#define COND_LTU 4
+#define COND_LEU 5
+#define COND_SV 6
+#define COND_OD 7
+#define COND_FALSE 8
+
+#define INSN_ADD (INSN_OP(0x02) | INSN_EXT6(0x18))
+#define INSN_ADDC (INSN_OP(0x02) | INSN_EXT6(0x1c))
+#define INSN_ADDI (INSN_OP(0x2d))
+#define INSN_ADDIL (INSN_OP(0x0a))
+#define INSN_ADDL (INSN_OP(0x02) | INSN_EXT6(0x28))
+#define INSN_AND (INSN_OP(0x02) | INSN_EXT6(0x08))
+#define INSN_ANDCM (INSN_OP(0x02) | INSN_EXT6(0x00))
+#define INSN_COMCLR (INSN_OP(0x02) | INSN_EXT6(0x22))
+#define INSN_COMICLR (INSN_OP(0x24))
+#define INSN_DEP (INSN_OP(0x35) | INSN_EXT3SH(3))
+#define INSN_DEPI (INSN_OP(0x35) | INSN_EXT3SH(7))
+#define INSN_EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7))
+#define INSN_EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6))
+#define INSN_LDIL (INSN_OP(0x08))
+#define INSN_LDO (INSN_OP(0x0d))
+#define INSN_MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2))
+#define INSN_OR (INSN_OP(0x02) | INSN_EXT6(0x09))
+#define INSN_SHD (INSN_OP(0x34) | INSN_EXT3SH(2))
+#define INSN_SUB (INSN_OP(0x02) | INSN_EXT6(0x10))
+#define INSN_SUBB (INSN_OP(0x02) | INSN_EXT6(0x14))
+#define INSN_SUBI (INSN_OP(0x25))
+#define INSN_VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5))
+#define INSN_VEXTRU (INSN_OP(0x34) | INSN_EXT3SH(4))
+#define INSN_VSHD (INSN_OP(0x34) | INSN_EXT3SH(0))
+#define INSN_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a))
+#define INSN_ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2))
+#define INSN_ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0))
+
+#define INSN_BL (INSN_OP(0x3a) | INSN_EXT3BR(0))
+#define INSN_BL_N (INSN_OP(0x3a) | INSN_EXT3BR(0) | 2)
+#define INSN_BLR (INSN_OP(0x3a) | INSN_EXT3BR(2))
+#define INSN_BV (INSN_OP(0x3a) | INSN_EXT3BR(6))
+#define INSN_BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2)
+#define INSN_BLE_SR4 (INSN_OP(0x39) | (1 << 13))
+
+#define INSN_LDB (INSN_OP(0x10))
+#define INSN_LDH (INSN_OP(0x11))
+#define INSN_LDW (INSN_OP(0x12))
+#define INSN_LDWM (INSN_OP(0x13))
+#define INSN_FLDDS (INSN_OP(0x0b) | INSN_EXT4(0) | (1 << 12))
+
+#define INSN_LDBX (INSN_OP(0x03) | INSN_EXT4(0))
+#define INSN_LDHX (INSN_OP(0x03) | INSN_EXT4(1))
+#define INSN_LDWX (INSN_OP(0x03) | INSN_EXT4(2))
+
+#define INSN_STB (INSN_OP(0x18))
+#define INSN_STH (INSN_OP(0x19))
+#define INSN_STW (INSN_OP(0x1a))
+#define INSN_STWM (INSN_OP(0x1b))
+#define INSN_FSTDS (INSN_OP(0x0b) | INSN_EXT4(8) | (1 << 12))
+
+#define INSN_COMBT (INSN_OP(0x20))
+#define INSN_COMBF (INSN_OP(0x22))
+#define INSN_COMIBT (INSN_OP(0x21))
+#define INSN_COMIBF (INSN_OP(0x23))
+
+/* supplied by libgcc */
+extern void *__canonicalize_funcptr_for_compare(void *);
+
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ /* PA1.1 defines COPY as OR r,0,t; PA2.0 defines COPY as LDO 0(r),t
+ but hppa-dis.c is unaware of this definition */
+ if (ret != arg) {
+ tcg_out32(s, INSN_OR | INSN_T(ret) | INSN_R1(arg)
+ | INSN_R2(TCG_REG_R0));
+ }
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ if (check_fit_tl(arg, 14)) {
+ tcg_out32(s, INSN_LDO | INSN_R1(ret)
+ | INSN_R2(TCG_REG_R0) | INSN_IM14(arg));
+ } else {
+ uint32_t hi, lo;
+ hi = arg >> 11;
+ lo = arg & 0x7ff;
+
+ tcg_out32(s, INSN_LDIL | INSN_R2(ret) | reassemble_21(hi));
+ if (lo) {
+ tcg_out32(s, INSN_LDO | INSN_R1(ret)
+ | INSN_R2(ret) | INSN_IM14(lo));
+ }
+ }
+}
+
+static void tcg_out_ldst(TCGContext *s, int ret, int addr,
+ tcg_target_long offset, int op)
+{
+ if (!check_fit_tl(offset, 14)) {
+ uint32_t hi, lo, op;
+
+ hi = offset >> 11;
+ lo = offset & 0x7ff;
+
+ if (addr == TCG_REG_R0) {
+ op = INSN_LDIL | INSN_R2(TCG_REG_R1);
+ } else {
+ op = INSN_ADDIL | INSN_R2(addr);
+ }
+ tcg_out32(s, op | reassemble_21(hi));
+
+ addr = TCG_REG_R1;
+ offset = lo;
+ }
+
+ if (ret != addr || offset != 0 || op != INSN_LDO) {
+ tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) | INSN_IM14(offset));
+ }
+}
+
+/* This function is required by tcg.c. */
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_ldst(s, ret, arg1, arg2, INSN_LDW);
+}
+
+/* This function is required by tcg.c. */
+static inline void tcg_out_st(TCGContext *s, TCGType type, int ret,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_ldst(s, ret, arg1, arg2, INSN_STW);
+}
+
+static void tcg_out_ldst_index(TCGContext *s, int data,
+ int base, int index, int op)
+{
+ tcg_out32(s, op | INSN_T(data) | INSN_R1(index) | INSN_R2(base));
+}
+
+static inline void tcg_out_addi2(TCGContext *s, int ret, int arg1,
+ tcg_target_long val)
+{
+ tcg_out_ldst(s, ret, arg1, val, INSN_LDO);
+}
+
+/* This function is required by tcg.c. */
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ tcg_out_addi2(s, reg, reg, val);
+}
+
+static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op)
+{
+ tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2));
+}
+
+static inline void tcg_out_arithi(TCGContext *s, int t, int r1,
+ tcg_target_long val, int op)
+{
+ assert(check_fit_tl(val, 11));
+ tcg_out32(s, op | INSN_R1(t) | INSN_R2(r1) | INSN_IM11(val));
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+ tcg_out_arith(s, TCG_REG_R0, TCG_REG_R0, TCG_REG_R0, INSN_OR);
+}
+
+static inline void tcg_out_mtctl_sar(TCGContext *s, int arg)
+{
+ tcg_out32(s, INSN_MTCTL | INSN_R2(11) | INSN_R1(arg));
+}
+
+/* Extract LEN bits at position OFS from ARG and place in RET.
+ Note that here the bit ordering is reversed from the PA-RISC
+ standard, such that the right-most bit is 0. */
+static inline void tcg_out_extr(TCGContext *s, int ret, int arg,
+ unsigned ofs, unsigned len, int sign)
+{
+ assert(ofs < 32 && len <= 32 - ofs);
+ tcg_out32(s, (sign ? INSN_EXTRS : INSN_EXTRU)
+ | INSN_R1(ret) | INSN_R2(arg)
+ | INSN_SHDEP_P(31 - ofs) | INSN_DEP_LEN(len));
+}
+
+/* Likewise with OFS interpreted little-endian. */
+static inline void tcg_out_dep(TCGContext *s, int ret, int arg,
+ unsigned ofs, unsigned len)
+{
+ assert(ofs < 32 && len <= 32 - ofs);
+ tcg_out32(s, INSN_DEP | INSN_R2(ret) | INSN_R1(arg)
+ | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len));
+}
+
+static inline void tcg_out_shd(TCGContext *s, int ret, int hi, int lo,
+ unsigned count)
+{
+ assert(count < 32);
+ tcg_out32(s, INSN_SHD | INSN_R1(hi) | INSN_R2(lo) | INSN_T(ret)
+ | INSN_SHDEP_CP(count));
+}
+
+static void tcg_out_vshd(TCGContext *s, int ret, int hi, int lo, int creg)
+{
+ tcg_out_mtctl_sar(s, creg);
+ tcg_out32(s, INSN_VSHD | INSN_T(ret) | INSN_R1(hi) | INSN_R2(lo));
+}
+
+static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m)
+{
+ int bs0, bs1;
+
+ /* Note that the argument is constrained to match or_mask_p. */
+ for (bs0 = 0; bs0 < 32; bs0++) {
+ if ((m & (1u << bs0)) != 0) {
+ break;
+ }
+ }
+ for (bs1 = bs0; bs1 < 32; bs1++) {
+ if ((m & (1u << bs1)) == 0) {
+ break;
+ }
+ }
+ assert(bs1 == 32 || (1ul << bs1) > m);
+
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
+ tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1)
+ | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0));
+}
+
+static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m)
+{
+ int ls0, ls1, ms0;
+
+ /* Note that the argument is constrained to match and_mask_p. */
+ for (ls0 = 0; ls0 < 32; ls0++) {
+ if ((m & (1u << ls0)) == 0) {
+ break;
+ }
+ }
+ for (ls1 = ls0; ls1 < 32; ls1++) {
+ if ((m & (1u << ls1)) != 0) {
+ break;
+ }
+ }
+ for (ms0 = ls1; ms0 < 32; ms0++) {
+ if ((m & (1u << ms0)) == 0) {
+ break;
+ }
+ }
+ assert (ms0 == 32);
+
+ if (ls1 == 32) {
+ tcg_out_extr(s, ret, arg, 0, ls0, 0);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
+ tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0)
+ | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0));
+ }
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg)
+{
+ tcg_out_extr(s, ret, arg, 0, 8, 1);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg)
+{
+ tcg_out_extr(s, ret, arg, 0, 16, 1);
+}
+
+static void tcg_out_shli(TCGContext *s, int ret, int arg, int count)
+{
+ count &= 31;
+ tcg_out32(s, INSN_ZDEP | INSN_R2(ret) | INSN_R1(arg)
+ | INSN_SHDEP_CP(31 - count) | INSN_DEP_LEN(32 - count));
+}
+
+static void tcg_out_shl(TCGContext *s, int ret, int arg, int creg)
+{
+ tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI);
+ tcg_out_mtctl_sar(s, TCG_REG_R20);
+ tcg_out32(s, INSN_ZVDEP | INSN_R2(ret) | INSN_R1(arg) | INSN_DEP_LEN(32));
+}
+
+static void tcg_out_shri(TCGContext *s, int ret, int arg, int count)
+{
+ count &= 31;
+ tcg_out_extr(s, ret, arg, count, 32 - count, 0);
+}
+
+static void tcg_out_shr(TCGContext *s, int ret, int arg, int creg)
+{
+ tcg_out_vshd(s, ret, TCG_REG_R0, arg, creg);
+}
+
+static void tcg_out_sari(TCGContext *s, int ret, int arg, int count)
+{
+ count &= 31;
+ tcg_out_extr(s, ret, arg, count, 32 - count, 1);
+}
+
+static void tcg_out_sar(TCGContext *s, int ret, int arg, int creg)
+{
+ tcg_out_arithi(s, TCG_REG_R20, creg, 31, INSN_SUBI);
+ tcg_out_mtctl_sar(s, TCG_REG_R20);
+ tcg_out32(s, INSN_VEXTRS | INSN_R1(ret) | INSN_R2(arg) | INSN_DEP_LEN(32));
+}
+
+static void tcg_out_rotli(TCGContext *s, int ret, int arg, int count)
+{
+ count &= 31;
+ tcg_out_shd(s, ret, arg, arg, 32 - count);
+}
+
+static void tcg_out_rotl(TCGContext *s, int ret, int arg, int creg)
+{
+ tcg_out_arithi(s, TCG_REG_R20, creg, 32, INSN_SUBI);
+ tcg_out_vshd(s, ret, arg, arg, TCG_REG_R20);
+}
+
+static void tcg_out_rotri(TCGContext *s, int ret, int arg, int count)
+{
+ count &= 31;
+ tcg_out_shd(s, ret, arg, arg, count);
+}
+
+static void tcg_out_rotr(TCGContext *s, int ret, int arg, int creg)
+{
+ tcg_out_vshd(s, ret, arg, arg, creg);
+}
+
+static void tcg_out_bswap16(TCGContext *s, int ret, int arg, int sign)
+{
+ if (ret != arg) {
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg); /* arg = xxAB */
+ }
+ tcg_out_dep(s, ret, ret, 16, 8); /* ret = xBAB */
+ tcg_out_extr(s, ret, ret, 8, 16, sign); /* ret = ..BA */
+}
+
+static void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp)
+{
+ /* arg = ABCD */
+ tcg_out_rotri(s, temp, arg, 16); /* temp = CDAB */
+ tcg_out_dep(s, temp, temp, 16, 8); /* temp = CBAB */
+ tcg_out_shd(s, ret, arg, temp, 8); /* ret = DCBA */
+}
+
+static void tcg_out_call(TCGContext *s, void *func)
+{
+ tcg_target_long val, hi, lo, disp;
+
+ val = (uint32_t)__canonicalize_funcptr_for_compare(func);
+ disp = (val - ((tcg_target_long)s->code_ptr + 8)) >> 2;
+
+ if (check_fit_tl(disp, 17)) {
+ tcg_out32(s, INSN_BL_N | INSN_R2(TCG_REG_RP) | reassemble_17(disp));
+ } else {
+ hi = val >> 11;
+ lo = val & 0x7ff;
+
+ tcg_out32(s, INSN_LDIL | INSN_R2(TCG_REG_R20) | reassemble_21(hi));
+ tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R20)
+ | reassemble_17(lo >> 2));
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_RP, TCG_REG_R31);
+ }
+}
+
+static void tcg_out_xmpyu(TCGContext *s, int retl, int reth,
+ int arg1, int arg2)
+{
+ /* Store both words into the stack for copy to the FPU. */
+ tcg_out_ldst(s, arg1, TCG_REG_SP, STACK_TEMP_OFS, INSN_STW);
+ tcg_out_ldst(s, arg2, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_STW);
+
+ /* Load both words into the FPU at the same time. We get away
+ with this because we can address the left and right half of the
+ FPU registers individually once loaded. */
+ /* fldds stack_temp(sp),fr22 */
+ tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_SP)
+ | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
+
+ /* xmpyu fr22r,fr22,fr22 */
+ tcg_out32(s, 0x3ad64796);
+
+ /* Store the 64-bit result back into the stack. */
+ /* fstds stack_temp(sp),fr22 */
+ tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_SP)
+ | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22));
+
+ /* Load the pieces of the result that the caller requested. */
+ if (reth) {
+ tcg_out_ldst(s, reth, TCG_REG_SP, STACK_TEMP_OFS, INSN_LDW);
+ }
+ if (retl) {
+ tcg_out_ldst(s, retl, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_LDW);
+ }
+}
+
+static void tcg_out_add2(TCGContext *s, int destl, int desth,
+ int al, int ah, int bl, int bh, int blconst)
+{
+ int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl);
+
+ if (blconst) {
+ tcg_out_arithi(s, tmp, al, bl, INSN_ADDI);
+ } else {
+ tcg_out_arith(s, tmp, al, bl, INSN_ADD);
+ }
+ tcg_out_arith(s, desth, ah, bh, INSN_ADDC);
+
+ tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
+}
+
+static void tcg_out_sub2(TCGContext *s, int destl, int desth, int al, int ah,
+ int bl, int bh, int alconst, int blconst)
+{
+ int tmp = (destl == ah || destl == bh ? TCG_REG_R20 : destl);
+
+ if (alconst) {
+ if (blconst) {
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R20, bl);
+ bl = TCG_REG_R20;
+ }
+ tcg_out_arithi(s, tmp, bl, al, INSN_SUBI);
+ } else if (blconst) {
+ tcg_out_arithi(s, tmp, al, -bl, INSN_ADDI);
+ } else {
+ tcg_out_arith(s, tmp, al, bl, INSN_SUB);
+ }
+ tcg_out_arith(s, desth, ah, bh, INSN_SUBB);
+
+ tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
+}
+
+static void tcg_out_branch(TCGContext *s, int label_index, int nul)
+{
+ TCGLabel *l = &s->labels[label_index];
+ uint32_t op = nul ? INSN_BL_N : INSN_BL;
+
+ if (l->has_value) {
+ tcg_target_long val = l->u.value;
+
+ val -= (tcg_target_long)s->code_ptr + 8;
+ val >>= 2;
+ assert(check_fit_tl(val, 17));
+
+ tcg_out32(s, op | reassemble_17(val));
+ } else {
+ /* We need to keep the offset unchanged for retranslation. */
+ uint32_t old_insn = *(uint32_t *)s->code_ptr;
+
+ tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL17F, label_index, 0);
+ tcg_out32(s, op | (old_insn & 0x1f1ffdu));
+ }
+}
+
+static const uint8_t tcg_cond_to_cmp_cond[10] =
+{
+ [TCG_COND_EQ] = COND_EQ,
+ [TCG_COND_NE] = COND_EQ | COND_FALSE,
+ [TCG_COND_LT] = COND_LT,
+ [TCG_COND_GE] = COND_LT | COND_FALSE,
+ [TCG_COND_LE] = COND_LE,
+ [TCG_COND_GT] = COND_LE | COND_FALSE,
+ [TCG_COND_LTU] = COND_LTU,
+ [TCG_COND_GEU] = COND_LTU | COND_FALSE,
+ [TCG_COND_LEU] = COND_LEU,
+ [TCG_COND_GTU] = COND_LEU | COND_FALSE,
+};
+
+static void tcg_out_brcond(TCGContext *s, int cond, TCGArg c1,
+ TCGArg c2, int c2const, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+ int op, pacond;
+
+ /* Note that COMIB operates as if the immediate is the first
+ operand. We model brcond with the immediate in the second
+ to better match what targets are likely to give us. For
+ consistency, model COMB with reversed operands as well. */
+ pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)];
+
+ if (c2const) {
+ op = (pacond & COND_FALSE ? INSN_COMIBF : INSN_COMIBT);
+ op |= INSN_IM5(c2);
+ } else {
+ op = (pacond & COND_FALSE ? INSN_COMBF : INSN_COMBT);
+ op |= INSN_R1(c2);
+ }
+ op |= INSN_R2(c1);
+ op |= INSN_COND(pacond & 7);
+
+ if (l->has_value) {
+ tcg_target_long val = l->u.value;
+
+ val -= (tcg_target_long)s->code_ptr + 8;
+ val >>= 2;
+ assert(check_fit_tl(val, 12));
+
+ /* ??? Assume that all branches to defined labels are backward.
+ Which means that if the nul bit is set, the delay slot is
+ executed if the branch is taken, and not executed in fallthru. */
+ tcg_out32(s, op | reassemble_12(val));
+ tcg_out_nop(s);
+ } else {
+ /* We need to keep the offset unchanged for retranslation. */
+ uint32_t old_insn = *(uint32_t *)s->code_ptr;
+
+ tcg_out_reloc(s, s->code_ptr, R_PARISC_PCREL12F, label_index, 0);
+ /* ??? Assume that all branches to undefined labels are forward.
+ Which means that if the nul bit is set, the delay slot is
+ not executed if the branch is taken, which is what we want. */
+ tcg_out32(s, op | 2 | (old_insn & 0x1ffdu));
+ }
+}
+
+static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ int op, pacond;
+
+ /* Note that COMICLR operates as if the immediate is the first
+ operand. We model setcond with the immediate in the second
+ to better match what targets are likely to give us. For
+ consistency, model COMCLR with reversed operands as well. */
+ pacond = tcg_cond_to_cmp_cond[tcg_swap_cond(cond)];
+
+ if (c2const) {
+ op = INSN_COMICLR | INSN_R2(c1) | INSN_R1(ret) | INSN_IM11(c2);
+ } else {
+ op = INSN_COMCLR | INSN_R2(c1) | INSN_R1(c2) | INSN_T(ret);
+ }
+ op |= INSN_COND(pacond & 7);
+ op |= pacond & COND_FALSE ? 1 << 12 : 0;
+
+ tcg_out32(s, op);
+}
+
+static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah,
+ TCGArg bl, int blconst, TCGArg bh, int bhconst,
+ int label_index)
+{
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ tcg_out_comclr(s, tcg_invert_cond(cond), TCG_REG_R0, al, bl, blconst);
+ tcg_out_brcond(s, cond, ah, bh, bhconst, label_index);
+ break;
+
+ default:
+ tcg_out_brcond(s, cond, ah, bh, bhconst, label_index);
+ tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst);
+ tcg_out_brcond(s, tcg_unsigned_cond(cond),
+ al, bl, blconst, label_index);
+ break;
+ }
+}
+
+static void tcg_out_setcond(TCGContext *s, int cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ tcg_out_comclr(s, tcg_invert_cond(cond), ret, c1, c2, c2const);
+ tcg_out_movi(s, TCG_TYPE_I32, ret, 1);
+}
+
+static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret,
+ TCGArg al, TCGArg ah, TCGArg bl, int blconst,
+ TCGArg bh, int bhconst)
+{
+ int scratch = TCG_REG_R20;
+
+ if (ret != al && ret != ah
+ && (blconst || ret != bl)
+ && (bhconst || ret != bh)) {
+ scratch = ret;
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ tcg_out_setcond(s, cond, scratch, al, bl, blconst);
+ tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst);
+ tcg_out_movi(s, TCG_TYPE_I32, scratch, cond == TCG_COND_NE);
+ break;
+
+ default:
+ tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst);
+ tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst);
+ tcg_out_movi(s, TCG_TYPE_I32, scratch, 0);
+ tcg_out_comclr(s, cond, TCG_REG_R0, ah, bh, bhconst);
+ tcg_out_movi(s, TCG_TYPE_I32, scratch, 1);
+ break;
+ }
+
+ tcg_out_mov(s, TCG_TYPE_I32, ret, scratch);
+}
+
+#if defined(CONFIG_SOFTMMU)
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+
+/* Load and compare a TLB entry, and branch if TLB miss. OFFSET is set to
+ the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate
+ TLB for the memory index. The return value is the offset from ENV
+ contained in R1 afterward (to be used when loading ADDEND); if the
+ return value is 0, R1 is not used. */
+
+static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo,
+ int addrhi, int s_bits, int lab_miss, int offset)
+{
+ int ret;
+
+ /* Extracting the index into the TLB. The "normal C operation" is
+ r1 = addr_reg >> TARGET_PAGE_BITS;
+ r1 &= CPU_TLB_SIZE - 1;
+ r1 <<= CPU_TLB_ENTRY_BITS;
+ What this does is extract CPU_TLB_BITS beginning at TARGET_PAGE_BITS
+ and place them at CPU_TLB_ENTRY_BITS. We can combine the first two
+ operations with an EXTRU. Unfortunately, the current value of
+ CPU_TLB_ENTRY_BITS is > 3, so we can't merge that shift with the
+ add that follows. */
+ tcg_out_extr(s, r1, addrlo, TARGET_PAGE_BITS, CPU_TLB_BITS, 0);
+ tcg_out_shli(s, r1, r1, CPU_TLB_ENTRY_BITS);
+ tcg_out_arith(s, r1, r1, TCG_AREG0, INSN_ADDL);
+
+ /* Make sure that both the addr_{read,write} and addend can be
+ read with a 14-bit offset from the same base register. */
+ if (check_fit_tl(offset + CPU_TLB_SIZE, 14)) {
+ ret = 0;
+ } else {
+ ret = (offset + 0x400) & ~0x7ff;
+ offset = ret - offset;
+ tcg_out_addi2(s, TCG_REG_R1, r1, ret);
+ r1 = TCG_REG_R1;
+ }
+
+ /* Load the entry from the computed slot. */
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R23, r1, offset);
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset + 4);
+ } else {
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset);
+ }
+
+ /* Compute the value that ought to appear in the TLB for a hit, namely, the page
+ of the address. We include the low N bits of the address to catch unaligned
+ accesses and force them onto the slow path. Do this computation after having
+ issued the load from the TLB slot to give the load time to complete. */
+ tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+
+ /* If not equal, jump to lab_miss. */
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_brcond2(s, TCG_COND_NE, TCG_REG_R20, TCG_REG_R23,
+ r0, 0, addrhi, 0, lab_miss);
+ } else {
+ tcg_out_brcond(s, TCG_COND_NE, TCG_REG_R20, r0, 0, lab_miss);
+ }
+
+ return ret;
+}
+#endif
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo_reg, int datahi_reg,
+ int addr_reg, int addend_reg, int opc)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 0;
+#else
+ const int bswap = 1;
+#endif
+
+ switch (opc) {
+ case 0:
+ tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX);
+ break;
+ case 0 | 4:
+ tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDBX);
+ tcg_out_ext8s(s, datalo_reg, datalo_reg);
+ break;
+ case 1:
+ tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX);
+ if (bswap) {
+ tcg_out_bswap16(s, datalo_reg, datalo_reg, 0);
+ }
+ break;
+ case 1 | 4:
+ tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDHX);
+ if (bswap) {
+ tcg_out_bswap16(s, datalo_reg, datalo_reg, 1);
+ } else {
+ tcg_out_ext16s(s, datalo_reg, datalo_reg);
+ }
+ break;
+ case 2:
+ tcg_out_ldst_index(s, datalo_reg, addr_reg, addend_reg, INSN_LDWX);
+ if (bswap) {
+ tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20);
+ }
+ break;
+ case 3:
+ if (bswap) {
+ int t = datahi_reg;
+ datahi_reg = datalo_reg;
+ datalo_reg = t;
+ }
+ /* We can't access the low-part with a reg+reg addressing mode,
+ so perform the addition now and use reg_ofs addressing mode. */
+ if (addend_reg != TCG_REG_R0) {
+ tcg_out_arith(s, TCG_REG_R20, addr_reg, addend_reg, INSN_ADD);
+ addr_reg = TCG_REG_R20;
+ }
+ /* Make sure not to clobber the base register. */
+ if (datahi_reg == addr_reg) {
+ tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW);
+ tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW);
+ } else {
+ tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_LDW);
+ tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_LDW);
+ }
+ if (bswap) {
+ tcg_out_bswap32(s, datalo_reg, datalo_reg, TCG_REG_R20);
+ tcg_out_bswap32(s, datahi_reg, datahi_reg, TCG_REG_R20);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ int datalo_reg = *args++;
+ /* Note that datahi_reg is only used for 64-bit loads. */
+ int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0);
+ int addrlo_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+ /* Note that addrhi_reg is only used for 64-bit guests. */
+ int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0);
+ int mem_index = *args;
+ int lab1, lab2, argreg, offset;
+
+ lab1 = gen_new_label();
+ lab2 = gen_new_label();
+
+ offset = offsetof(CPUState, tlb_table[mem_index][0].addr_read);
+ offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg,
+ opc & 3, lab1, offset);
+
+ /* TLB Hit. */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25),
+ offsetof(CPUState, tlb_table[mem_index][0].addend) - offset);
+ tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, TCG_REG_R20, opc);
+ tcg_out_branch(s, lab2, 1);
+
+ /* TLB Miss. */
+ /* label1: */
+ tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
+
+ argreg = TCG_REG_R26;
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
+ }
+ tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+
+ tcg_out_call(s, qemu_ld_helpers[opc & 3]);
+
+ switch (opc) {
+ case 0:
+ tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xff);
+ break;
+ case 0 | 4:
+ tcg_out_ext8s(s, datalo_reg, TCG_REG_RET0);
+ break;
+ case 1:
+ tcg_out_andi(s, datalo_reg, TCG_REG_RET0, 0xffff);
+ break;
+ case 1 | 4:
+ tcg_out_ext16s(s, datalo_reg, TCG_REG_RET0);
+ break;
+ case 2:
+ case 2 | 4:
+ tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET0);
+ break;
+ case 3:
+ tcg_out_mov(s, TCG_TYPE_I32, datahi_reg, TCG_REG_RET0);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET1);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ /* label2: */
+ tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr);
+#else
+ tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg,
+ (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_R0), opc);
+#endif
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int datalo_reg, int datahi_reg,
+ int addr_reg, int opc)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 0;
+#else
+ const int bswap = 1;
+#endif
+
+ switch (opc) {
+ case 0:
+ tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STB);
+ break;
+ case 1:
+ if (bswap) {
+ tcg_out_bswap16(s, TCG_REG_R20, datalo_reg, 0);
+ datalo_reg = TCG_REG_R20;
+ }
+ tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STH);
+ break;
+ case 2:
+ if (bswap) {
+ tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20);
+ datalo_reg = TCG_REG_R20;
+ }
+ tcg_out_ldst(s, datalo_reg, addr_reg, 0, INSN_STW);
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out_bswap32(s, TCG_REG_R20, datalo_reg, TCG_REG_R20);
+ tcg_out_bswap32(s, TCG_REG_R23, datahi_reg, TCG_REG_R23);
+ datahi_reg = TCG_REG_R20;
+ datalo_reg = TCG_REG_R23;
+ }
+ tcg_out_ldst(s, datahi_reg, addr_reg, 0, INSN_STW);
+ tcg_out_ldst(s, datalo_reg, addr_reg, 4, INSN_STW);
+ break;
+ default:
+ tcg_abort();
+ }
+
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+ int datalo_reg = *args++;
+ /* Note that datahi_reg is only used for 64-bit loads. */
+ int datahi_reg = (opc == 3 ? *args++ : TCG_REG_R0);
+ int addrlo_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+ /* Note that addrhi_reg is only used for 64-bit guests. */
+ int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0);
+ int mem_index = *args;
+ int lab1, lab2, argreg, offset;
+
+ lab1 = gen_new_label();
+ lab2 = gen_new_label();
+
+ offset = offsetof(CPUState, tlb_table[mem_index][0].addr_write);
+ offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg,
+ opc, lab1, offset);
+
+ /* TLB Hit. */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25),
+ offsetof(CPUState, tlb_table[mem_index][0].addend) - offset);
+
+ /* There are no indexed stores, so we must do this addition explitly.
+ Careful to avoid R20, which is used for the bswaps to follow. */
+ tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_REG_R20, INSN_ADDL);
+ tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, TCG_REG_R31, opc);
+ tcg_out_branch(s, lab2, 1);
+
+ /* TLB Miss. */
+ /* label1: */
+ tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
+
+ argreg = TCG_REG_R26;
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
+ }
+
+ switch(opc) {
+ case 0:
+ tcg_out_andi(s, argreg--, datalo_reg, 0xff);
+ tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+ break;
+ case 1:
+ tcg_out_andi(s, argreg--, datalo_reg, 0xffff);
+ tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+ break;
+ case 2:
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, datalo_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+ break;
+ case 3:
+ /* Because of the alignment required by the 64-bit data argument,
+ we will always use R23/R24. Also, we will always run out of
+ argument registers for storing mem_index, so that will have
+ to go on the stack. */
+ if (mem_index == 0) {
+ argreg = TCG_REG_R0;
+ } else {
+ argreg = TCG_REG_R20;
+ tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
+ }
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg);
+ tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP,
+ TCG_TARGET_CALL_STACK_OFFSET - 4);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ tcg_out_call(s, qemu_st_helpers[opc]);
+
+ /* label2: */
+ tcg_out_label(s, lab2, (tcg_target_long)s->code_ptr);
+#else
+ /* There are no indexed stores, so if GUEST_BASE is set we must do the add
+ explicitly. Careful to avoid R20, which is used for the bswaps to follow. */
+ if (GUEST_BASE != 0) {
+ tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_GUEST_BASE_REG, INSN_ADDL);
+ addrlo_reg = TCG_REG_R31;
+ }
+ tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, addrlo_reg, opc);
+#endif
+}
+
+static void tcg_out_exit_tb(TCGContext *s, TCGArg arg)
+{
+ if (!check_fit_tl(arg, 14)) {
+ uint32_t hi, lo;
+ hi = arg & ~0x7ff;
+ lo = arg & 0x7ff;
+ if (lo) {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, hi);
+ tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18));
+ tcg_out_addi(s, TCG_REG_RET0, lo);
+ return;
+ }
+ arg = hi;
+ }
+ tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_R18));
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, arg);
+}
+
+static void tcg_out_goto_tb(TCGContext *s, TCGArg arg)
+{
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+ fprintf(stderr, "goto_tb direct\n");
+ tcg_abort();
+ } else {
+ /* indirect jump method */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, TCG_REG_R0,
+ (tcg_target_long)(s->tb_next + arg));
+ tcg_out32(s, INSN_BV_N | INSN_R2(TCG_REG_R20));
+ }
+ s->tb_next_offset[arg] = s->code_ptr - s->code_buf;
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args)
+{
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_exit_tb(s, args[0]);
+ break;
+ case INDEX_op_goto_tb:
+ tcg_out_goto_tb(s, args[0]);
+ break;
+
+ case INDEX_op_call:
+ if (const_args[0]) {
+ tcg_out_call(s, (void *)args[0]);
+ } else {
+ /* ??? FIXME: the value in the register in args[0] is almost
+ certainly a procedure descriptor, not a code address. We
+ probably need to use the millicode $$dyncall routine. */
+ tcg_abort();
+ }
+ break;
+
+ case INDEX_op_jmp:
+ fprintf(stderr, "unimplemented jmp\n");
+ tcg_abort();
+ break;
+
+ case INDEX_op_br:
+ tcg_out_branch(s, args[0], 1);
+ break;
+
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
+ break;
+
+ case INDEX_op_ld8u_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB);
+ break;
+ case INDEX_op_ld8s_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDB);
+ tcg_out_ext8s(s, args[0], args[0]);
+ break;
+ case INDEX_op_ld16u_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH);
+ break;
+ case INDEX_op_ld16s_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDH);
+ tcg_out_ext16s(s, args[0], args[0]);
+ break;
+ case INDEX_op_ld_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_LDW);
+ break;
+
+ case INDEX_op_st8_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_STB);
+ break;
+ case INDEX_op_st16_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_STH);
+ break;
+ case INDEX_op_st_i32:
+ tcg_out_ldst(s, args[0], args[1], args[2], INSN_STW);
+ break;
+
+ case INDEX_op_add_i32:
+ if (const_args[2]) {
+ tcg_out_addi2(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_ADDL);
+ }
+ break;
+
+ case INDEX_op_sub_i32:
+ if (const_args[1]) {
+ if (const_args[2]) {
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1] - args[2]);
+ } else {
+ /* Recall that SUBI is a reversed subtract. */
+ tcg_out_arithi(s, args[0], args[2], args[1], INSN_SUBI);
+ }
+ } else if (const_args[2]) {
+ tcg_out_addi2(s, args[0], args[1], -args[2]);
+ } else {
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_SUB);
+ }
+ break;
+
+ case INDEX_op_and_i32:
+ if (const_args[2]) {
+ tcg_out_andi(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_AND);
+ }
+ break;
+
+ case INDEX_op_or_i32:
+ if (const_args[2]) {
+ tcg_out_ori(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_OR);
+ }
+ break;
+
+ case INDEX_op_xor_i32:
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_XOR);
+ break;
+
+ case INDEX_op_andc_i32:
+ if (const_args[2]) {
+ tcg_out_andi(s, args[0], args[1], ~args[2]);
+ } else {
+ tcg_out_arith(s, args[0], args[1], args[2], INSN_ANDCM);
+ }
+ break;
+
+ case INDEX_op_shl_i32:
+ if (const_args[2]) {
+ tcg_out_shli(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_shl(s, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_shr_i32:
+ if (const_args[2]) {
+ tcg_out_shri(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_shr(s, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_sar_i32:
+ if (const_args[2]) {
+ tcg_out_sari(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_sar(s, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_rotl_i32:
+ if (const_args[2]) {
+ tcg_out_rotli(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_rotl(s, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ tcg_out_rotri(s, args[0], args[1], args[2]);
+ } else {
+ tcg_out_rotr(s, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_mul_i32:
+ tcg_out_xmpyu(s, args[0], TCG_REG_R0, args[1], args[2]);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_xmpyu(s, args[0], args[1], args[2], args[3]);
+ break;
+
+ case INDEX_op_bswap16_i32:
+ tcg_out_bswap16(s, args[0], args[1], 0);
+ break;
+ case INDEX_op_bswap32_i32:
+ tcg_out_bswap32(s, args[0], args[1], TCG_REG_R20);
+ break;
+
+ case INDEX_op_not_i32:
+ tcg_out_arithi(s, args[0], args[1], -1, INSN_SUBI);
+ break;
+ case INDEX_op_ext8s_i32:
+ tcg_out_ext8s(s, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i32:
+ tcg_out_ext16s(s, args[0], args[1]);
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]);
+ break;
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args[4], args[0], args[1],
+ args[2], const_args[2],
+ args[3], const_args[3], args[5]);
+ break;
+
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args[5], args[0], args[1], args[2],
+ args[3], const_args[3], args[4], const_args[4]);
+ break;
+
+ case INDEX_op_add2_i32:
+ tcg_out_add2(s, args[0], args[1], args[2], args[3],
+ args[4], args[5], const_args[4]);
+ break;
+
+ case INDEX_op_sub2_i32:
+ tcg_out_sub2(s, args[0], args[1], args[2], args[3],
+ args[4], args[5], const_args[2], const_args[4]);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ default:
+ fprintf(stderr, "unknown opcode 0x%x\n", opc);
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef hppa_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "r" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "rZ", "r" } },
+ { INDEX_op_st16_i32, { "rZ", "r" } },
+ { INDEX_op_st_i32, { "rZ", "r" } },
+
+ { INDEX_op_add_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_sub_i32, { "r", "rI", "ri" } },
+ { INDEX_op_and_i32, { "r", "rZ", "rM" } },
+ { INDEX_op_or_i32, { "r", "rZ", "rO" } },
+ { INDEX_op_xor_i32, { "r", "rZ", "rZ" } },
+ /* Note that the second argument will be inverted, which means
+ we want a constant whose inversion matches M, and that O = ~M.
+ See the implementation of and_mask_p. */
+ { INDEX_op_andc_i32, { "r", "rZ", "rO" } },
+
+ { INDEX_op_mul_i32, { "r", "r", "r" } },
+ { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+
+ { INDEX_op_shl_i32, { "r", "r", "ri" } },
+ { INDEX_op_shr_i32, { "r", "r", "ri" } },
+ { INDEX_op_sar_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_bswap16_i32, { "r", "r" } },
+ { INDEX_op_bswap32_i32, { "r", "r" } },
+ { INDEX_op_not_i32, { "r", "r" } },
+
+ { INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+
+ { INDEX_op_brcond_i32, { "rZ", "rJ" } },
+ { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } },
+
+ { INDEX_op_setcond_i32, { "r", "rZ", "rI" } },
+ { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rI", "rI" } },
+
+ { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rI", "rZ" } },
+ { INDEX_op_sub2_i32, { "r", "r", "rI", "rZ", "rK", "rZ" } },
+
+#if TARGET_LONG_BITS == 32
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "LZ", "L" } },
+ { INDEX_op_qemu_st16, { "LZ", "L" } },
+ { INDEX_op_qemu_st32, { "LZ", "L" } },
+ { INDEX_op_qemu_st64, { "LZ", "LZ", "L" } },
+#else
+ { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
+
+ { INDEX_op_qemu_st8, { "LZ", "L", "L" } },
+ { INDEX_op_qemu_st16, { "LZ", "L", "L" } },
+ { INDEX_op_qemu_st32, { "LZ", "L", "L" } },
+ { INDEX_op_qemu_st64, { "LZ", "LZ", "L", "L" } },
+#endif
+ { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+ /* R2, the return address register, is saved specially
+ in the caller's frame. */
+ /* R3, the frame pointer, is not currently modified. */
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ /* R17 is the global env, so no need to save. */
+ TCG_REG_R18
+};
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int frame_size, i;
+
+ /* Allocate space for the fixed frame marker. */
+ frame_size = -TCG_TARGET_CALL_STACK_OFFSET;
+ frame_size += TCG_TARGET_STATIC_CALL_ARGS_SIZE;
+
+ /* Allocate space for the saved registers. */
+ frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
+
+ /* Align the allocated space. */
+ frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1)
+ & -TCG_TARGET_STACK_ALIGN);
+
+ /* The return address is stored in the caller's frame. */
+ tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -20);
+
+ /* Allocate stack frame, saving the first register at the same time. */
+ tcg_out_ldst(s, tcg_target_callee_save_regs[0],
+ TCG_REG_SP, frame_size, INSN_STWM);
+
+ /* Save all callee saved registers. */
+ for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_st(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, -frame_size + i * 4);
+ }
+
+#ifdef CONFIG_USE_GUEST_BASE
+ if (GUEST_BASE != 0) {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+ }
+#endif
+
+ /* Jump to TB, and adjust R18 to be the return address. */
+ tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26));
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R18, TCG_REG_R31);
+
+ /* Restore callee saved registers. */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -frame_size - 20);
+ for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, -frame_size + i * 4);
+ }
+
+ /* Deallocate stack frame and return. */
+ tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_RP));
+ tcg_out_ldst(s, tcg_target_callee_save_regs[0],
+ TCG_REG_SP, -frame_size, INSN_LDWM);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+
+ tcg_regset_clear(tcg_target_call_clobber_regs);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R20);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R21);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R22);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R23);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R24);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R25);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R26);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET0);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RET1);
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* addil target */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP); /* link register */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* frame pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */
+
+ tcg_add_target_add_op_defs(hppa_op_defs);
+}
diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
new file mode 100644
index 0000000..a5cc440
--- /dev/null
+++ b/tcg/hppa/tcg-target.h
@@ -0,0 +1,119 @@
+/*
+ * 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_HPPA 1
+
+#if defined(_PA_RISC1_1)
+#define TCG_TARGET_REG_BITS 32
+#else
+#error unsupported
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_RP,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_DP,
+ TCG_REG_RET0,
+ TCG_REG_RET1,
+ TCG_REG_SP,
+ TCG_REG_R31,
+};
+
+#define TCG_CT_CONST_0 0x0100
+#define TCG_CT_CONST_S5 0x0200
+#define TCG_CT_CONST_S11 0x0400
+#define TCG_CT_CONST_MS11 0x0800
+#define TCG_CT_CONST_AND 0x1000
+#define TCG_CT_CONST_OR 0x2000
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 64
+#define TCG_TARGET_CALL_STACK_OFFSET -48
+#define TCG_TARGET_STATIC_CALL_ARGS_SIZE 8*4
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_STACK_GROWSUP
+
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32 /* sub rd, 0, rs */
+#undef TCG_TARGET_HAS_ext8u_i32 /* and rd, rs, 0xff */
+#undef TCG_TARGET_HAS_ext16u_i32 /* and rd, rs, 0xffff */
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_R17
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ start &= ~31;
+ while (start <= stop) {
+ asm volatile ("fdc 0(%0)\n\t"
+ "sync\n\t"
+ "fic 0(%%sr4, %0)\n\t"
+ "sync"
+ : : "r"(start) : "memory");
+ start += 32;
+ }
+}
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
new file mode 100644
index 0000000..bb19a95
--- /dev/null
+++ b/tcg/i386/tcg-target.c
@@ -0,0 +1,1982 @@
+/*
+ * 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.
+ */
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+#if TCG_TARGET_REG_BITS == 64
+ "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+#else
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
+#endif
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RBP,
+ TCG_REG_RBX,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R9,
+ TCG_REG_R8,
+ TCG_REG_RCX,
+ TCG_REG_RDX,
+ TCG_REG_RSI,
+ TCG_REG_RDI,
+ TCG_REG_RAX,
+#else
+ TCG_REG_EBX,
+ TCG_REG_ESI,
+ TCG_REG_EDI,
+ TCG_REG_EBP,
+ TCG_REG_ECX,
+ TCG_REG_EDX,
+ TCG_REG_EAX,
+#endif
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RDI,
+ TCG_REG_RSI,
+ TCG_REG_RDX,
+ TCG_REG_RCX,
+ TCG_REG_R8,
+ TCG_REG_R9,
+#else
+ TCG_REG_EAX,
+ TCG_REG_EDX,
+ TCG_REG_ECX
+#endif
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_EAX,
+ TCG_REG_EDX
+};
+
+static uint8_t *tb_ret_addr;
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch(type) {
+ case R_386_PC32:
+ value -= (uintptr_t)code_ptr;
+ if (value != (int32_t)value) {
+ tcg_abort();
+ }
+ *(uint32_t *)code_ptr = value;
+ break;
+ case R_386_PC8:
+ value -= (uintptr_t)code_ptr;
+ if (value != (int8_t)value) {
+ tcg_abort();
+ }
+ *(uint8_t *)code_ptr = value;
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ if (TCG_TARGET_REG_BITS == 64) {
+ return 6;
+ }
+
+ flags &= TCG_CALL_TYPE_MASK;
+ switch(flags) {
+ case TCG_CALL_TYPE_STD:
+ return 0;
+ case TCG_CALL_TYPE_REGPARM_1:
+ case TCG_CALL_TYPE_REGPARM_2:
+ case TCG_CALL_TYPE_REGPARM:
+ return flags - TCG_CALL_TYPE_REGPARM_1 + 1;
+ default:
+ tcg_abort();
+ }
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch(ct_str[0]) {
+ case 'a':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX);
+ break;
+ case 'b':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX);
+ break;
+ case 'c':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX);
+ break;
+ case 'd':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX);
+ break;
+ case 'S':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI);
+ break;
+ case 'D':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI);
+ break;
+ case 'q':
+ ct->ct |= TCG_CT_REG;
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xf);
+ }
+ break;
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xff);
+ }
+ break;
+
+ /* qemu_ld/st address constraint */
+ case 'L':
+ ct->ct |= TCG_CT_REG;
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
+ }
+ break;
+
+ case 'e':
+ ct->ct |= TCG_CT_CONST_S32;
+ break;
+ case 'Z':
+ ct->ct |= TCG_CT_CONST_U32;
+ break;
+
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) {
+ return 1;
+ }
+ return 0;
+}
+
+#if TCG_TARGET_REG_BITS == 64
+# define LOWREGMASK(x) ((x) & 7)
+#else
+# define LOWREGMASK(x) (x)
+#endif
+
+#define P_EXT 0x100 /* 0x0f opcode prefix */
+#define P_DATA16 0x200 /* 0x66 opcode prefix */
+#if TCG_TARGET_REG_BITS == 64
+# define P_ADDR32 0x400 /* 0x67 opcode prefix */
+# define P_REXW 0x800 /* Set REX.W = 1 */
+# define P_REXB_R 0x1000 /* REG field as byte register */
+# define P_REXB_RM 0x2000 /* R/M field as byte register */
+#else
+# define P_ADDR32 0
+# define P_REXW 0
+# define P_REXB_R 0
+# define P_REXB_RM 0
+#endif
+
+#define OPC_ARITH_EvIz (0x81)
+#define OPC_ARITH_EvIb (0x83)
+#define OPC_ARITH_GvEv (0x03) /* ... plus (ARITH_FOO << 3) */
+#define OPC_ADD_GvEv (OPC_ARITH_GvEv | (ARITH_ADD << 3))
+#define OPC_BSWAP (0xc8 | P_EXT)
+#define OPC_CALL_Jz (0xe8)
+#define OPC_CMP_GvEv (OPC_ARITH_GvEv | (ARITH_CMP << 3))
+#define OPC_DEC_r32 (0x48)
+#define OPC_IMUL_GvEv (0xaf | P_EXT)
+#define OPC_IMUL_GvEvIb (0x6b)
+#define OPC_IMUL_GvEvIz (0x69)
+#define OPC_INC_r32 (0x40)
+#define OPC_JCC_long (0x80 | P_EXT) /* ... plus condition code */
+#define OPC_JCC_short (0x70) /* ... plus condition code */
+#define OPC_JMP_long (0xe9)
+#define OPC_JMP_short (0xeb)
+#define OPC_LEA (0x8d)
+#define OPC_MOVB_EvGv (0x88) /* stores, more or less */
+#define OPC_MOVL_EvGv (0x89) /* stores, more or less */
+#define OPC_MOVL_GvEv (0x8b) /* loads, more or less */
+#define OPC_MOVL_EvIz (0xc7)
+#define OPC_MOVL_Iv (0xb8)
+#define OPC_MOVSBL (0xbe | P_EXT)
+#define OPC_MOVSWL (0xbf | P_EXT)
+#define OPC_MOVSLQ (0x63 | P_REXW)
+#define OPC_MOVZBL (0xb6 | P_EXT)
+#define OPC_MOVZWL (0xb7 | P_EXT)
+#define OPC_POP_r32 (0x58)
+#define OPC_PUSH_r32 (0x50)
+#define OPC_PUSH_Iv (0x68)
+#define OPC_PUSH_Ib (0x6a)
+#define OPC_RET (0xc3)
+#define OPC_SETCC (0x90 | P_EXT | P_REXB_RM) /* ... plus cc */
+#define OPC_SHIFT_1 (0xd1)
+#define OPC_SHIFT_Ib (0xc1)
+#define OPC_SHIFT_cl (0xd3)
+#define OPC_TESTL (0x85)
+#define OPC_XCHG_ax_r32 (0x90)
+
+#define OPC_GRP3_Ev (0xf7)
+#define OPC_GRP5 (0xff)
+
+/* Group 1 opcode extensions for 0x80-0x83.
+ These are also used as modifiers for OPC_ARITH. */
+#define ARITH_ADD 0
+#define ARITH_OR 1
+#define ARITH_ADC 2
+#define ARITH_SBB 3
+#define ARITH_AND 4
+#define ARITH_SUB 5
+#define ARITH_XOR 6
+#define ARITH_CMP 7
+
+/* Group 2 opcode extensions for 0xc0, 0xc1, 0xd0-0xd3. */
+#define SHIFT_ROL 0
+#define SHIFT_ROR 1
+#define SHIFT_SHL 4
+#define SHIFT_SHR 5
+#define SHIFT_SAR 7
+
+/* Group 3 opcode extensions for 0xf6, 0xf7. To be used with OPC_GRP3. */
+#define EXT3_NOT 2
+#define EXT3_NEG 3
+#define EXT3_MUL 4
+#define EXT3_IMUL 5
+#define EXT3_DIV 6
+#define EXT3_IDIV 7
+
+/* Group 5 opcode extensions for 0xff. To be used with OPC_GRP5. */
+#define EXT5_INC_Ev 0
+#define EXT5_DEC_Ev 1
+#define EXT5_CALLN_Ev 2
+#define EXT5_JMPN_Ev 4
+
+/* Condition codes to be added to OPC_JCC_{long,short}. */
+#define JCC_JMP (-1)
+#define JCC_JO 0x0
+#define JCC_JNO 0x1
+#define JCC_JB 0x2
+#define JCC_JAE 0x3
+#define JCC_JE 0x4
+#define JCC_JNE 0x5
+#define JCC_JBE 0x6
+#define JCC_JA 0x7
+#define JCC_JS 0x8
+#define JCC_JNS 0x9
+#define JCC_JP 0xa
+#define JCC_JNP 0xb
+#define JCC_JL 0xc
+#define JCC_JGE 0xd
+#define JCC_JLE 0xe
+#define JCC_JG 0xf
+
+static const uint8_t tcg_cond_to_jcc[10] = {
+ [TCG_COND_EQ] = JCC_JE,
+ [TCG_COND_NE] = JCC_JNE,
+ [TCG_COND_LT] = JCC_JL,
+ [TCG_COND_GE] = JCC_JGE,
+ [TCG_COND_LE] = JCC_JLE,
+ [TCG_COND_GT] = JCC_JG,
+ [TCG_COND_LTU] = JCC_JB,
+ [TCG_COND_GEU] = JCC_JAE,
+ [TCG_COND_LEU] = JCC_JBE,
+ [TCG_COND_GTU] = JCC_JA,
+};
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x)
+{
+ int rex;
+
+ if (opc & P_DATA16) {
+ /* We should never be asking for both 16 and 64-bit operation. */
+ assert((opc & P_REXW) == 0);
+ tcg_out8(s, 0x66);
+ }
+ if (opc & P_ADDR32) {
+ tcg_out8(s, 0x67);
+ }
+
+ rex = 0;
+ rex |= (opc & P_REXW) >> 8; /* REX.W */
+ rex |= (r & 8) >> 1; /* REX.R */
+ rex |= (x & 8) >> 2; /* REX.X */
+ rex |= (rm & 8) >> 3; /* REX.B */
+
+ /* P_REXB_{R,RM} indicates that the given register is the low byte.
+ For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do,
+ as otherwise the encoding indicates %[abcd]h. Note that the values
+ that are ORed in merely indicate that the REX byte must be present;
+ those bits get discarded in output. */
+ rex |= opc & (r >= 4 ? P_REXB_R : 0);
+ rex |= opc & (rm >= 4 ? P_REXB_RM : 0);
+
+ if (rex) {
+ tcg_out8(s, (uint8_t)(rex | 0x40));
+ }
+
+ if (opc & P_EXT) {
+ tcg_out8(s, 0x0f);
+ }
+ tcg_out8(s, opc);
+}
+#else
+static void tcg_out_opc(TCGContext *s, int opc)
+{
+ if (opc & P_DATA16) {
+ tcg_out8(s, 0x66);
+ }
+ if (opc & P_EXT) {
+ tcg_out8(s, 0x0f);
+ }
+ tcg_out8(s, opc);
+}
+/* Discard the register arguments to tcg_out_opc early, so as not to penalize
+ the 32-bit compilation paths. This method works with all versions of gcc,
+ whereas relying on optimization may not be able to exclude them. */
+#define tcg_out_opc(s, opc, r, rm, x) (tcg_out_opc)(s, opc)
+#endif
+
+static void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
+{
+ tcg_out_opc(s, opc, r, rm, 0);
+ tcg_out8(s, 0xc0 | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
+}
+
+/* Output an opcode with a full "rm + (index<<shift) + offset" address mode.
+ We handle either RM and INDEX missing with a negative value. In 64-bit
+ mode for absolute addresses, ~RM is the size of the immediate operand
+ that will follow the instruction. */
+
+static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
+ int index, int shift,
+ tcg_target_long offset)
+{
+ int mod, len;
+
+ if (index < 0 && rm < 0) {
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* Try for a rip-relative addressing mode. This has replaced
+ the 32-bit-mode absolute addressing encoding. */
+ tcg_target_long pc = (tcg_target_long)s->code_ptr + 5 + ~rm;
+ tcg_target_long disp = offset - pc;
+ if (disp == (int32_t)disp) {
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (LOWREGMASK(r) << 3) | 5);
+ tcg_out32(s, disp);
+ return;
+ }
+
+ /* Try for an absolute address encoding. This requires the
+ use of the MODRM+SIB encoding and is therefore larger than
+ rip-relative addressing. */
+ if (offset == (int32_t)offset) {
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (LOWREGMASK(r) << 3) | 4);
+ tcg_out8(s, (4 << 3) | 5);
+ tcg_out32(s, offset);
+ return;
+ }
+
+ /* ??? The memory isn't directly addressable. */
+ tcg_abort();
+ } else {
+ /* Absolute address. */
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (r << 3) | 5);
+ tcg_out32(s, offset);
+ return;
+ }
+ }
+
+ /* Find the length of the immediate addend. Note that the encoding
+ that would be used for (%ebp) indicates absolute addressing. */
+ if (rm < 0) {
+ mod = 0, len = 4, rm = 5;
+ } else if (offset == 0 && LOWREGMASK(rm) != TCG_REG_EBP) {
+ mod = 0, len = 0;
+ } else if (offset == (int8_t)offset) {
+ mod = 0x40, len = 1;
+ } else {
+ mod = 0x80, len = 4;
+ }
+
+ /* Use a single byte MODRM format if possible. Note that the encoding
+ that would be used for %esp is the escape to the two byte form. */
+ if (index < 0 && LOWREGMASK(rm) != TCG_REG_ESP) {
+ /* Single byte MODRM format. */
+ tcg_out_opc(s, opc, r, rm, 0);
+ tcg_out8(s, mod | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
+ } else {
+ /* Two byte MODRM+SIB format. */
+
+ /* Note that the encoding that would place %esp into the index
+ field indicates no index register. In 64-bit mode, the REX.X
+ bit counts, so %r12 can be used as the index. */
+ if (index < 0) {
+ index = 4;
+ } else {
+ assert(index != TCG_REG_ESP);
+ }
+
+ tcg_out_opc(s, opc, r, rm, index);
+ tcg_out8(s, mod | (LOWREGMASK(r) << 3) | 4);
+ tcg_out8(s, (shift << 6) | (LOWREGMASK(index) << 3) | LOWREGMASK(rm));
+ }
+
+ if (len == 1) {
+ tcg_out8(s, offset);
+ } else if (len == 4) {
+ tcg_out32(s, offset);
+ }
+}
+
+/* A simplification of the above with no index or shift. */
+static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r,
+ int rm, tcg_target_long offset)
+{
+ tcg_out_modrm_sib_offset(s, opc, r, rm, -1, 0, offset);
+}
+
+/* Generate dest op= src. Uses the same ARITH_* codes as tgen_arithi. */
+static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
+{
+ /* Propagate an opcode prefix, such as P_REXW. */
+ int ext = subop & ~0x7;
+ subop &= 0x7;
+
+ tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3) + ext, dest, src);
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ if (arg != ret) {
+ int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm(s, opc, ret, arg);
+ }
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ if (arg == 0) {
+ tgen_arithr(s, ARITH_XOR, ret, ret);
+ return;
+ } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
+ tcg_out_opc(s, OPC_MOVL_Iv + LOWREGMASK(ret), 0, ret, 0);
+ tcg_out32(s, arg);
+ } else if (arg == (int32_t)arg) {
+ tcg_out_modrm(s, OPC_MOVL_EvIz + P_REXW, 0, ret);
+ tcg_out32(s, arg);
+ } else {
+ tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0);
+ tcg_out32(s, arg);
+ tcg_out32(s, arg >> 31 >> 1);
+ }
+}
+
+static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
+{
+ if (val == (int8_t)val) {
+ tcg_out_opc(s, OPC_PUSH_Ib, 0, 0, 0);
+ tcg_out8(s, val);
+ } else if (val == (int32_t)val) {
+ tcg_out_opc(s, OPC_PUSH_Iv, 0, 0, 0);
+ tcg_out32(s, val);
+ } else {
+ tcg_abort();
+ }
+}
+
+static inline void tcg_out_push(TCGContext *s, int reg)
+{
+ tcg_out_opc(s, OPC_PUSH_r32 + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_pop(TCGContext *s, int reg)
+{
+ tcg_out_opc(s, OPC_POP_r32 + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+ int arg1, tcg_target_long arg2)
+{
+ int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm_offset(s, opc, ret, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ int opc = OPC_MOVL_EvGv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm_offset(s, opc, arg, arg1, arg2);
+}
+
+static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
+{
+ /* Propagate an opcode prefix, such as P_DATA16. */
+ int ext = subopc & ~0x7;
+ subopc &= 0x7;
+
+ if (count == 1) {
+ tcg_out_modrm(s, OPC_SHIFT_1 + ext, subopc, reg);
+ } else {
+ tcg_out_modrm(s, OPC_SHIFT_Ib + ext, subopc, reg);
+ tcg_out8(s, count);
+ }
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int reg)
+{
+ tcg_out_opc(s, OPC_BSWAP + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static inline void tcg_out_rolw_8(TCGContext *s, int reg)
+{
+ tcg_out_shifti(s, SHIFT_ROL + P_DATA16, reg, 8);
+}
+
+static inline void tcg_out_ext8u(TCGContext *s, int dest, int src)
+{
+ /* movzbl */
+ assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+ tcg_out_modrm(s, OPC_MOVZBL + P_REXB_RM, dest, src);
+}
+
+static void tcg_out_ext8s(TCGContext *s, int dest, int src, int rexw)
+{
+ /* movsbl */
+ assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+ tcg_out_modrm(s, OPC_MOVSBL + P_REXB_RM + rexw, dest, src);
+}
+
+static inline void tcg_out_ext16u(TCGContext *s, int dest, int src)
+{
+ /* movzwl */
+ tcg_out_modrm(s, OPC_MOVZWL, dest, src);
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int dest, int src, int rexw)
+{
+ /* movsw[lq] */
+ tcg_out_modrm(s, OPC_MOVSWL + rexw, dest, src);
+}
+
+static inline void tcg_out_ext32u(TCGContext *s, int dest, int src)
+{
+ /* 32-bit mov zero extends. */
+ tcg_out_modrm(s, OPC_MOVL_GvEv, dest, src);
+}
+
+static inline void tcg_out_ext32s(TCGContext *s, int dest, int src)
+{
+ tcg_out_modrm(s, OPC_MOVSLQ, dest, src);
+}
+
+static inline void tcg_out_bswap64(TCGContext *s, int reg)
+{
+ tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static void tgen_arithi(TCGContext *s, int c, int r0,
+ tcg_target_long val, int cf)
+{
+ int rexw = 0;
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ rexw = c & -8;
+ c &= 7;
+ }
+
+ /* ??? While INC is 2 bytes shorter than ADDL $1, they also induce
+ partial flags update stalls on Pentium4 and are not recommended
+ by current Intel optimization manuals. */
+ if (!cf && (c == ARITH_ADD || c == ARITH_SUB) && (val == 1 || val == -1)) {
+ int is_inc = (c == ARITH_ADD) ^ (val < 0);
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* The single-byte increment encodings are re-tasked as the
+ REX prefixes. Use the MODRM encoding. */
+ tcg_out_modrm(s, OPC_GRP5 + rexw,
+ (is_inc ? EXT5_INC_Ev : EXT5_DEC_Ev), r0);
+ } else {
+ tcg_out8(s, (is_inc ? OPC_INC_r32 : OPC_DEC_r32) + r0);
+ }
+ return;
+ }
+
+ if (c == ARITH_AND) {
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (val == 0xffffffffu) {
+ tcg_out_ext32u(s, r0, r0);
+ return;
+ }
+ if (val == (uint32_t)val) {
+ /* AND with no high bits set can use a 32-bit operation. */
+ rexw = 0;
+ }
+ }
+ if (val == 0xffu && (r0 < 4 || TCG_TARGET_REG_BITS == 64)) {
+ tcg_out_ext8u(s, r0, r0);
+ return;
+ }
+ if (val == 0xffffu) {
+ tcg_out_ext16u(s, r0, r0);
+ return;
+ }
+ }
+
+ if (val == (int8_t)val) {
+ tcg_out_modrm(s, OPC_ARITH_EvIb + rexw, c, r0);
+ tcg_out8(s, val);
+ return;
+ }
+ if (rexw == 0 || val == (int32_t)val) {
+ tcg_out_modrm(s, OPC_ARITH_EvIz + rexw, c, r0);
+ tcg_out32(s, val);
+ return;
+ }
+
+ tcg_abort();
+}
+
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val != 0) {
+ tgen_arithi(s, ARITH_ADD + P_REXW, reg, val, 0);
+ }
+}
+
+/* Use SMALL != 0 to force a short forward branch. */
+static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
+{
+ int32_t val, val1;
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value) {
+ val = l->u.value - (tcg_target_long)s->code_ptr;
+ val1 = val - 2;
+ if ((int8_t)val1 == val1) {
+ if (opc == -1) {
+ tcg_out8(s, OPC_JMP_short);
+ } else {
+ tcg_out8(s, OPC_JCC_short + opc);
+ }
+ tcg_out8(s, val1);
+ } else {
+ if (small) {
+ tcg_abort();
+ }
+ if (opc == -1) {
+ tcg_out8(s, OPC_JMP_long);
+ tcg_out32(s, val - 5);
+ } else {
+ tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
+ tcg_out32(s, val - 6);
+ }
+ }
+ } else if (small) {
+ if (opc == -1) {
+ tcg_out8(s, OPC_JMP_short);
+ } else {
+ tcg_out8(s, OPC_JCC_short + opc);
+ }
+ tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1);
+ s->code_ptr += 1;
+ } else {
+ if (opc == -1) {
+ tcg_out8(s, OPC_JMP_long);
+ } else {
+ tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
+ }
+ tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
+ s->code_ptr += 4;
+ }
+}
+
+static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
+ int const_arg2, int rexw)
+{
+ if (const_arg2) {
+ if (arg2 == 0) {
+ /* test r, r */
+ tcg_out_modrm(s, OPC_TESTL + rexw, arg1, arg1);
+ } else {
+ tgen_arithi(s, ARITH_CMP + rexw, arg1, arg2, 0);
+ }
+ } else {
+ tgen_arithr(s, ARITH_CMP + rexw, arg1, arg2);
+ }
+}
+
+static void tcg_out_brcond32(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index, int small)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
+ tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_brcond64(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index, int small)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+ tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
+}
+#else
+/* XXX: we implement it at the target level to avoid having to
+ handle cross basic blocks temporaries */
+static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
+ const int *const_args, int small)
+{
+ int label_next;
+ label_next = gen_new_label();
+ switch(args[4]) {
+ case TCG_COND_EQ:
+ tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+ label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_EQ, args[1], args[3], const_args[3],
+ args[5], small);
+ break;
+ case TCG_COND_NE:
+ tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+ args[5], small);
+ tcg_out_brcond32(s, TCG_COND_NE, args[1], args[3], const_args[3],
+ args[5], small);
+ break;
+ case TCG_COND_LT:
+ tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_LE:
+ tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_GT:
+ tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_GE:
+ tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_LTU:
+ tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_LEU:
+ tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_GTU:
+ tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ case TCG_COND_GEU:
+ tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+ args[5], small);
+ tcg_out_jxx(s, JCC_JNE, label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+ args[5], small);
+ break;
+ default:
+ tcg_abort();
+ }
+ tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
+}
+#endif
+
+static void tcg_out_setcond32(TCGContext *s, TCGCond cond, TCGArg dest,
+ TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
+ tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
+ tcg_out_ext8u(s, dest, dest);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond64(TCGContext *s, TCGCond cond, TCGArg dest,
+ TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+ tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
+ tcg_out_ext8u(s, dest, dest);
+}
+#else
+static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
+ const int *const_args)
+{
+ TCGArg new_args[6];
+ int label_true, label_over;
+
+ memcpy(new_args, args+1, 5*sizeof(TCGArg));
+
+ if (args[0] == args[1] || args[0] == args[2]
+ || (!const_args[3] && args[0] == args[3])
+ || (!const_args[4] && args[0] == args[4])) {
+ /* When the destination overlaps with one of the argument
+ registers, don't do anything tricky. */
+ label_true = gen_new_label();
+ label_over = gen_new_label();
+
+ new_args[5] = label_true;
+ tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+ tcg_out_jxx(s, JCC_JMP, label_over, 1);
+ tcg_out_label(s, label_true, (tcg_target_long)s->code_ptr);
+
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], 1);
+ tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+ } else {
+ /* When the destination does not overlap one of the arguments,
+ clear the destination first, jump if cond false, and emit an
+ increment in the true case. This results in smaller code. */
+
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+
+ label_over = gen_new_label();
+ new_args[4] = tcg_invert_cond(new_args[4]);
+ new_args[5] = label_over;
+ tcg_out_brcond2(s, new_args, const_args+1, 1);
+
+ tgen_arithi(s, ARITH_ADD, args[0], 1, 0);
+ tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
+ }
+}
+#endif
+
+static void tcg_out_branch(TCGContext *s, int call, tcg_target_long dest)
+{
+ tcg_target_long disp = dest - (tcg_target_long)s->code_ptr - 5;
+
+ if (disp == (int32_t)disp) {
+ tcg_out_opc(s, call ? OPC_CALL_Jz : OPC_JMP_long, 0, 0, 0);
+ tcg_out32(s, disp);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, dest);
+ tcg_out_modrm(s, OPC_GRP5,
+ call ? EXT5_CALLN_Ev : EXT5_JMPN_Ev, TCG_REG_R10);
+ }
+}
+
+static inline void tcg_out_calli(TCGContext *s, tcg_target_long dest)
+{
+ tcg_out_branch(s, 1, dest);
+}
+
+static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
+{
+ tcg_out_branch(s, 0, dest);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+
+/* Perform the TLB load and compare.
+
+ Inputs:
+ ADDRLO_IDX contains the index into ARGS of the low part of the
+ address; the high part of the address is at ADDR_LOW_IDX+1.
+
+ MEM_INDEX and S_BITS are the memory context and log2 size of the load.
+
+ WHICH is the offset into the CPUTLBEntry structure of the slot to read.
+ This should be offsetof addr_read or addr_write.
+
+ Outputs:
+ LABEL_PTRS is filled with 1 (32-bit addresses) or 2 (64-bit addresses)
+ positions of the displacements of forward jumps to the TLB miss case.
+
+ First argument register is loaded with the low part of the address.
+ In the TLB hit case, it has been adjusted as indicated by the TLB
+ and so is a host address. In the TLB miss case, it continues to
+ hold a guest address.
+
+ Second argument register is clobbered. */
+
+static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
+ int mem_index, int s_bits,
+ const TCGArg *args,
+ uint8_t **label_ptr, int which)
+{
+ const int addrlo = args[addrlo_idx];
+ const int r0 = tcg_target_call_iarg_regs[0];
+ const int r1 = tcg_target_call_iarg_regs[1];
+ TCGType type = TCG_TYPE_I32;
+ int rexw = 0;
+
+ if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) {
+ type = TCG_TYPE_I64;
+ rexw = P_REXW;
+ }
+
+ tcg_out_mov(s, type, r1, addrlo);
+ tcg_out_mov(s, type, r0, addrlo);
+
+ tcg_out_shifti(s, SHIFT_SHR + rexw, r1,
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+
+ tgen_arithi(s, ARITH_AND + rexw, r0,
+ TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
+ tgen_arithi(s, ARITH_AND + rexw, r1,
+ (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
+
+ tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r1, TCG_AREG0, r1, 0,
+ offsetof(CPUState, tlb_table[mem_index][0])
+ + which);
+
+ /* cmp 0(r1), r0 */
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r0, r1, 0);
+
+ tcg_out_mov(s, type, r0, addrlo);
+
+ /* jne label1 */
+ tcg_out8(s, OPC_JCC_short + JCC_JNE);
+ label_ptr[0] = s->code_ptr;
+ s->code_ptr++;
+
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ /* cmp 4(r1), addrhi */
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r1, 4);
+
+ /* jne label1 */
+ tcg_out8(s, OPC_JCC_short + JCC_JNE);
+ label_ptr[1] = s->code_ptr;
+ s->code_ptr++;
+ }
+
+ /* TLB Hit. */
+
+ /* add addend(r1), r0 */
+ tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r0, r1,
+ offsetof(CPUTLBEntry, addend) - which);
+}
+#endif
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
+ int base, tcg_target_long ofs, int sizeop)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 1;
+#else
+ const int bswap = 0;
+#endif
+ switch (sizeop) {
+ case 0:
+ tcg_out_modrm_offset(s, OPC_MOVZBL, datalo, base, ofs);
+ break;
+ case 0 | 4:
+ tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW, datalo, base, ofs);
+ break;
+ case 1:
+ tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
+ if (bswap) {
+ tcg_out_rolw_8(s, datalo);
+ }
+ break;
+ case 1 | 4:
+ if (bswap) {
+ tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
+ tcg_out_rolw_8(s, datalo);
+ tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo);
+ } else {
+ tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW, datalo, base, ofs);
+ }
+ break;
+ case 2:
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ if (bswap) {
+ tcg_out_bswap32(s, datalo);
+ }
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case 2 | 4:
+ if (bswap) {
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ tcg_out_bswap32(s, datalo);
+ tcg_out_ext32s(s, datalo, datalo);
+ } else {
+ tcg_out_modrm_offset(s, OPC_MOVSLQ, datalo, base, ofs);
+ }
+ break;
+#endif
+ case 3:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_ld(s, TCG_TYPE_I64, datalo, base, ofs);
+ if (bswap) {
+ tcg_out_bswap64(s, datalo);
+ }
+ } else {
+ if (bswap) {
+ int t = datalo;
+ datalo = datahi;
+ datahi = t;
+ }
+ if (base != datalo) {
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ } else {
+ tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ }
+ if (bswap) {
+ tcg_out_bswap32(s, datalo);
+ tcg_out_bswap32(s, datahi);
+ }
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
+ EAX. It will be useful once fixed registers globals are less
+ common. */
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int data_reg, data_reg2 = 0;
+ int addrlo_idx;
+#if defined(CONFIG_SOFTMMU)
+ int mem_index, s_bits, arg_idx;
+ uint8_t *label_ptr[3];
+#endif
+
+ data_reg = args[0];
+ addrlo_idx = 1;
+ if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
+ data_reg2 = args[1];
+ addrlo_idx = 2;
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
+ s_bits = opc & 3;
+
+ tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+ label_ptr, offsetof(CPUTLBEntry, addr_read));
+
+ /* TLB Hit. */
+ tcg_out_qemu_ld_direct(s, data_reg, data_reg2,
+ tcg_target_call_iarg_regs[0], 0, opc);
+
+ /* jmp label2 */
+ tcg_out8(s, OPC_JMP_short);
+ label_ptr[2] = s->code_ptr;
+ s->code_ptr++;
+
+ /* TLB Miss. */
+
+ /* label1: */
+ *label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ *label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
+ }
+
+ /* XXX: move that code at the end of the TB */
+ /* The first argument is already loaded with addrlo. */
+ arg_idx = 1;
+ if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx++],
+ args[addrlo_idx + 1]);
+ }
+ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx],
+ mem_index);
+ tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]);
+
+ switch(opc) {
+ case 0 | 4:
+ tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
+ break;
+ case 1 | 4:
+ tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
+ break;
+ case 0:
+ tcg_out_ext8u(s, data_reg, TCG_REG_EAX);
+ break;
+ case 1:
+ tcg_out_ext16u(s, data_reg, TCG_REG_EAX);
+ break;
+ case 2:
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case 2 | 4:
+ tcg_out_ext32s(s, data_reg, TCG_REG_EAX);
+ break;
+#endif
+ case 3:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
+ } else if (data_reg == TCG_REG_EDX) {
+ /* xchg %edx, %eax */
+ tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EAX);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EDX);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+
+ /* label2: */
+ *label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
+#else
+ {
+ int32_t offset = GUEST_BASE;
+ int base = args[addrlo_idx];
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* ??? We assume all operations have left us with register
+ contents that are zero extended. So far this appears to
+ be true. If we want to enforce this, we can either do
+ an explicit zero-extension here, or (if GUEST_BASE == 0)
+ use the ADDR32 prefix. For now, do nothing. */
+
+ if (offset != GUEST_BASE) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+ base = TCG_REG_RDI, offset = 0;
+ }
+ }
+
+ tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, opc);
+ }
+#endif
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
+ int base, tcg_target_long ofs, int sizeop)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 1;
+#else
+ const int bswap = 0;
+#endif
+ /* ??? Ideally we wouldn't need a scratch register. For user-only,
+ we could perform the bswap twice to restore the original value
+ instead of moving to the scratch. But as it is, the L constraint
+ means that the second argument reg is definitely free here. */
+ int scratch = tcg_target_call_iarg_regs[1];
+
+ switch (sizeop) {
+ case 0:
+ tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R, datalo, base, ofs);
+ break;
+ case 1:
+ if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+ tcg_out_rolw_8(s, scratch);
+ datalo = scratch;
+ }
+ tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16, datalo, base, ofs);
+ break;
+ case 2:
+ if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+ tcg_out_bswap32(s, scratch);
+ datalo = scratch;
+ }
+ tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs);
+ break;
+ case 3:
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I64, scratch, datalo);
+ tcg_out_bswap64(s, scratch);
+ datalo = scratch;
+ }
+ tcg_out_st(s, TCG_TYPE_I64, datalo, base, ofs);
+ } else if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datahi);
+ tcg_out_bswap32(s, scratch);
+ tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs);
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+ tcg_out_bswap32(s, scratch);
+ tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs + 4);
+ } else {
+ tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs);
+ tcg_out_st(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int data_reg, data_reg2 = 0;
+ int addrlo_idx;
+#if defined(CONFIG_SOFTMMU)
+ int mem_index, s_bits;
+ int stack_adjust;
+ uint8_t *label_ptr[3];
+#endif
+
+ data_reg = args[0];
+ addrlo_idx = 1;
+ if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
+ data_reg2 = args[1];
+ addrlo_idx = 2;
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
+ s_bits = opc;
+
+ tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+ label_ptr, offsetof(CPUTLBEntry, addr_write));
+
+ /* TLB Hit. */
+ tcg_out_qemu_st_direct(s, data_reg, data_reg2,
+ tcg_target_call_iarg_regs[0], 0, opc);
+
+ /* jmp label2 */
+ tcg_out8(s, OPC_JMP_short);
+ label_ptr[2] = s->code_ptr;
+ s->code_ptr++;
+
+ /* TLB Miss. */
+
+ /* label1: */
+ *label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ *label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
+ }
+
+ /* XXX: move that code at the end of the TB */
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+ TCG_REG_RSI, data_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+ stack_adjust = 0;
+ } else if (TARGET_LONG_BITS == 32) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, data_reg);
+ if (opc == 3) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg2);
+ tcg_out_pushi(s, mem_index);
+ stack_adjust = 4;
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
+ stack_adjust = 0;
+ }
+ } else {
+ if (opc == 3) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
+ tcg_out_pushi(s, mem_index);
+ tcg_out_push(s, data_reg2);
+ tcg_out_push(s, data_reg);
+ stack_adjust = 12;
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
+ switch(opc) {
+ case 0:
+ tcg_out_ext8u(s, TCG_REG_ECX, data_reg);
+ break;
+ case 1:
+ tcg_out_ext16u(s, TCG_REG_ECX, data_reg);
+ break;
+ case 2:
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg);
+ break;
+ }
+ tcg_out_pushi(s, mem_index);
+ stack_adjust = 4;
+ }
+ }
+
+ tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
+
+ if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
+ /* Pop and discard. This is 2 bytes smaller than the add. */
+ tcg_out_pop(s, TCG_REG_ECX);
+ } else if (stack_adjust != 0) {
+ tcg_out_addi(s, TCG_REG_ESP, stack_adjust);
+ }
+
+ /* label2: */
+ *label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
+#else
+ {
+ int32_t offset = GUEST_BASE;
+ int base = args[addrlo_idx];
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* ??? We assume all operations have left us with register
+ contents that are zero extended. So far this appears to
+ be true. If we want to enforce this, we can either do
+ an explicit zero-extension here, or (if GUEST_BASE == 0)
+ use the ADDR32 prefix. For now, do nothing. */
+
+ if (offset != GUEST_BASE) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+ base = TCG_REG_RDI, offset = 0;
+ }
+ }
+
+ tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, opc);
+ }
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ int c, rexw = 0;
+
+#if TCG_TARGET_REG_BITS == 64
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i64): \
+ rexw = P_REXW; /* FALLTHRU */ \
+ case glue(glue(INDEX_op_, x), _i32)
+#else
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i32)
+#endif
+
+ switch(opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]);
+ tcg_out_jmp(s, (tcg_target_long) tb_ret_addr);
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+ tcg_out8(s, OPC_JMP_long); /* jmp im */
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ tcg_out32(s, 0);
+ } else {
+ /* indirect jump method */
+ tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
+ (tcg_target_long)(s->tb_next + args[0]));
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_call:
+ if (const_args[0]) {
+ tcg_out_calli(s, args[0]);
+ } else {
+ /* call *reg */
+ tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]);
+ }
+ break;
+ case INDEX_op_jmp:
+ if (const_args[0]) {
+ tcg_out_jmp(s, args[0]);
+ } else {
+ /* jmp *reg */
+ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, args[0]);
+ }
+ break;
+ case INDEX_op_br:
+ tcg_out_jxx(s, JCC_JMP, args[0], 0);
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ OP_32_64(ld8u):
+ /* Note that we can ignore REXW for the zero-extend to 64-bit. */
+ tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]);
+ break;
+ OP_32_64(ld8s):
+ tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, args[0], args[1], args[2]);
+ break;
+ OP_32_64(ld16u):
+ /* Note that we can ignore REXW for the zero-extend to 64-bit. */
+ tcg_out_modrm_offset(s, OPC_MOVZWL, args[0], args[1], args[2]);
+ break;
+ OP_32_64(ld16s):
+ tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, args[0], args[1], args[2]);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_ld32u_i64:
+#endif
+ case INDEX_op_ld_i32:
+ tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+ break;
+
+ OP_32_64(st8):
+ tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R,
+ args[0], args[1], args[2]);
+ break;
+ OP_32_64(st16):
+ tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16,
+ args[0], args[1], args[2]);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_st32_i64:
+#endif
+ case INDEX_op_st_i32:
+ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+ break;
+
+ OP_32_64(add):
+ /* For 3-operand addition, use LEA. */
+ if (args[0] != args[1]) {
+ TCGArg a0 = args[0], a1 = args[1], a2 = args[2], c3 = 0;
+
+ if (const_args[2]) {
+ c3 = a2, a2 = -1;
+ } else if (a0 == a2) {
+ /* Watch out for dest = src + dest, since we've removed
+ the matching constraint on the add. */
+ tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
+ break;
+ }
+
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3);
+ break;
+ }
+ c = ARITH_ADD;
+ goto gen_arith;
+ OP_32_64(sub):
+ c = ARITH_SUB;
+ goto gen_arith;
+ OP_32_64(and):
+ c = ARITH_AND;
+ goto gen_arith;
+ OP_32_64(or):
+ c = ARITH_OR;
+ goto gen_arith;
+ OP_32_64(xor):
+ c = ARITH_XOR;
+ goto gen_arith;
+ gen_arith:
+ if (const_args[2]) {
+ tgen_arithi(s, c + rexw, args[0], args[2], 0);
+ } else {
+ tgen_arithr(s, c + rexw, args[0], args[2]);
+ }
+ break;
+
+ OP_32_64(mul):
+ if (const_args[2]) {
+ int32_t val;
+ val = args[2];
+ if (val == (int8_t)val) {
+ tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, args[0], args[0]);
+ tcg_out8(s, val);
+ } else {
+ tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, args[0], args[0]);
+ tcg_out32(s, val);
+ }
+ } else {
+ tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, args[0], args[2]);
+ }
+ break;
+
+ OP_32_64(div2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]);
+ break;
+ OP_32_64(divu2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]);
+ break;
+
+ OP_32_64(shl):
+ c = SHIFT_SHL;
+ goto gen_shift;
+ OP_32_64(shr):
+ c = SHIFT_SHR;
+ goto gen_shift;
+ OP_32_64(sar):
+ c = SHIFT_SAR;
+ goto gen_shift;
+ OP_32_64(rotl):
+ c = SHIFT_ROL;
+ goto gen_shift;
+ OP_32_64(rotr):
+ c = SHIFT_ROR;
+ goto gen_shift;
+ gen_shift:
+ if (const_args[2]) {
+ tcg_out_shifti(s, c + rexw, args[0], args[2]);
+ } else {
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, args[0]);
+ }
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond32(s, args[2], args[0], args[1], const_args[1],
+ args[3], 0);
+ break;
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond32(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ OP_32_64(bswap16):
+ tcg_out_rolw_8(s, args[0]);
+ break;
+ OP_32_64(bswap32):
+ tcg_out_bswap32(s, args[0]);
+ break;
+
+ OP_32_64(neg):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, args[0]);
+ break;
+ OP_32_64(not):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, args[0]);
+ break;
+
+ OP_32_64(ext8s):
+ tcg_out_ext8s(s, args[0], args[1], rexw);
+ break;
+ OP_32_64(ext16s):
+ tcg_out_ext16s(s, args[0], args[1], rexw);
+ break;
+ OP_32_64(ext8u):
+ tcg_out_ext8u(s, args[0], args[1]);
+ break;
+ OP_32_64(ext16u):
+ tcg_out_ext16u(s, args[0], args[1]);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_qemu_ld32u:
+#endif
+ case INDEX_op_qemu_ld32:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args, const_args, 0);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args, const_args);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
+ break;
+ case INDEX_op_add2_i32:
+ if (const_args[4]) {
+ tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
+ } else {
+ tgen_arithr(s, ARITH_ADD, args[0], args[4]);
+ }
+ if (const_args[5]) {
+ tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
+ } else {
+ tgen_arithr(s, ARITH_ADC, args[1], args[5]);
+ }
+ break;
+ case INDEX_op_sub2_i32:
+ if (const_args[4]) {
+ tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
+ } else {
+ tgen_arithr(s, ARITH_SUB, args[0], args[4]);
+ }
+ if (const_args[5]) {
+ tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
+ } else {
+ tgen_arithr(s, ARITH_SBB, args[1], args[5]);
+ }
+ break;
+#else /* TCG_TARGET_REG_BITS == 64 */
+ case INDEX_op_movi_i64:
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_modrm_offset(s, OPC_MOVSLQ, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, 2 | 4);
+ break;
+
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond64(s, args[2], args[0], args[1], const_args[1],
+ args[3], 0);
+ break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond64(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_bswap64_i64:
+ tcg_out_bswap64(s, args[0]);
+ break;
+ case INDEX_op_ext32u_i64:
+ tcg_out_ext32u(s, args[0], args[1]);
+ break;
+ case INDEX_op_ext32s_i64:
+ tcg_out_ext32s(s, args[0], args[1]);
+ break;
+#endif
+
+ default:
+ tcg_abort();
+ }
+
+#undef OP_32_64
+}
+
+static const TCGTargetOpDef x86_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "q", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "r", "ri" } },
+ { INDEX_op_sub_i32, { "r", "0", "ri" } },
+ { INDEX_op_mul_i32, { "r", "0", "ri" } },
+ { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_and_i32, { "r", "0", "ri" } },
+ { INDEX_op_or_i32, { "r", "0", "ri" } },
+ { INDEX_op_xor_i32, { "r", "0", "ri" } },
+
+ { INDEX_op_shl_i32, { "r", "0", "ci" } },
+ { INDEX_op_shr_i32, { "r", "0", "ci" } },
+ { INDEX_op_sar_i32, { "r", "0", "ci" } },
+ { INDEX_op_rotl_i32, { "r", "0", "ci" } },
+ { INDEX_op_rotr_i32, { "r", "0", "ci" } },
+
+ { INDEX_op_brcond_i32, { "r", "ri" } },
+
+ { INDEX_op_bswap16_i32, { "r", "0" } },
+ { INDEX_op_bswap32_i32, { "r", "0" } },
+
+ { INDEX_op_neg_i32, { "r", "0" } },
+
+ { INDEX_op_not_i32, { "r", "0" } },
+
+ { INDEX_op_ext8s_i32, { "r", "q" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext8u_i32, { "r", "q" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
+
+ { INDEX_op_setcond_i32, { "q", "r", "ri" } },
+
+#if TCG_TARGET_REG_BITS == 32
+ { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
+ { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+ { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+ { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
+ { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+#else
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+
+ { INDEX_op_add_i64, { "r", "0", "re" } },
+ { INDEX_op_mul_i64, { "r", "0", "re" } },
+ { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_sub_i64, { "r", "0", "re" } },
+ { INDEX_op_and_i64, { "r", "0", "reZ" } },
+ { INDEX_op_or_i64, { "r", "0", "re" } },
+ { INDEX_op_xor_i64, { "r", "0", "re" } },
+
+ { INDEX_op_shl_i64, { "r", "0", "ci" } },
+ { INDEX_op_shr_i64, { "r", "0", "ci" } },
+ { INDEX_op_sar_i64, { "r", "0", "ci" } },
+ { INDEX_op_rotl_i64, { "r", "0", "ci" } },
+ { INDEX_op_rotr_i64, { "r", "0", "ci" } },
+
+ { INDEX_op_brcond_i64, { "r", "re" } },
+ { INDEX_op_setcond_i64, { "r", "r", "re" } },
+
+ { INDEX_op_bswap16_i64, { "r", "0" } },
+ { INDEX_op_bswap32_i64, { "r", "0" } },
+ { INDEX_op_bswap64_i64, { "r", "0" } },
+ { INDEX_op_neg_i64, { "r", "0" } },
+ { INDEX_op_not_i64, { "r", "0" } },
+
+ { INDEX_op_ext8s_i64, { "r", "r" } },
+ { INDEX_op_ext16s_i64, { "r", "r" } },
+ { INDEX_op_ext32s_i64, { "r", "r" } },
+ { INDEX_op_ext8u_i64, { "r", "r" } },
+ { INDEX_op_ext16u_i64, { "r", "r" } },
+ { INDEX_op_ext32u_i64, { "r", "r" } },
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L" } },
+#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "cb", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L", "L" } },
+#else
+ { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
+
+ { INDEX_op_qemu_st8, { "cb", "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
+#endif
+ { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RBP,
+ TCG_REG_RBX,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ /* TCG_REG_R14, */ /* Currently used for the global env. */
+ TCG_REG_R15,
+#else
+ /* TCG_REG_EBP, */ /* Currently used for the global env. */
+ TCG_REG_EBX,
+ TCG_REG_ESI,
+ TCG_REG_EDI,
+#endif
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int i, frame_size, push_size, stack_addend;
+
+ /* TB prologue */
+
+ /* Save all callee saved registers. */
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_push(s, tcg_target_callee_save_regs[i]);
+ }
+
+ /* Reserve some stack space. */
+ push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
+ push_size *= TCG_TARGET_REG_BITS / 8;
+
+ frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
+ frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+ ~(TCG_TARGET_STACK_ALIGN - 1);
+ stack_addend = frame_size - push_size;
+ tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
+
+ /* jmp *tb. */
+ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[0]);
+
+ /* TB epilogue */
+ tb_ret_addr = s->code_ptr;
+
+ tcg_out_addi(s, TCG_REG_ESP, stack_addend);
+
+ for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+ tcg_out_pop(s, tcg_target_callee_save_regs[i]);
+ }
+ tcg_out_opc(s, OPC_RET, 0, 0, 0);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* fail safe */
+ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+ tcg_abort();
+#endif
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
+ } else {
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
+ }
+
+ tcg_regset_clear(tcg_target_call_clobber_regs);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EAX);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RDI);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RSI);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
+ }
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP);
+
+ tcg_add_target_add_op_defs(x86_op_defs);
+}
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
new file mode 100644
index 0000000..bfafbfc
--- /dev/null
+++ b/tcg/i386/tcg-target.h
@@ -0,0 +1,126 @@
+/*
+ * 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
+
+#if defined(__x86_64__)
+# define TCG_TARGET_REG_BITS 64
+#else
+# define TCG_TARGET_REG_BITS 32
+#endif
+//#define TCG_TARGET_WORDS_BIGENDIAN
+
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_TARGET_NB_REGS 16
+#else
+# define TCG_TARGET_NB_REGS 8
+#endif
+
+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,
+
+ /* 64-bit registers; always define the symbols to avoid
+ too much if-deffing. */
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_RAX = TCG_REG_EAX,
+ TCG_REG_RCX = TCG_REG_ECX,
+ TCG_REG_RDX = TCG_REG_EDX,
+ TCG_REG_RBX = TCG_REG_EBX,
+ TCG_REG_RSP = TCG_REG_ESP,
+ TCG_REG_RBP = TCG_REG_EBP,
+ TCG_REG_RSI = TCG_REG_ESI,
+ TCG_REG_RDI = TCG_REG_EDI,
+};
+
+#define TCG_CT_CONST_S32 0x100
+#define TCG_CT_CONST_U32 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_ESP
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div2_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div2_i64
+#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* Note: must be synced with dyngen-exec.h */
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_AREG0 TCG_REG_R14
+#else
+# define TCG_AREG0 TCG_REG_EBP
+#endif
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
new file mode 100644
index 0000000..8dac7f7
--- /dev/null
+++ b/tcg/ia64/tcg-target.c
@@ -0,0 +1,2390 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009-2010 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - 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.
+ */
+
+/*
+ * Register definitions
+ */
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
+ "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
+};
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R55
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+/* Branch registers */
+enum {
+ TCG_REG_B0 = 0,
+ TCG_REG_B1,
+ TCG_REG_B2,
+ TCG_REG_B3,
+ TCG_REG_B4,
+ TCG_REG_B5,
+ TCG_REG_B6,
+ TCG_REG_B7,
+};
+
+/* Floating point registers */
+enum {
+ TCG_REG_F0 = 0,
+ TCG_REG_F1,
+ TCG_REG_F2,
+ TCG_REG_F3,
+ TCG_REG_F4,
+ TCG_REG_F5,
+ TCG_REG_F6,
+ TCG_REG_F7,
+ TCG_REG_F8,
+ TCG_REG_F9,
+ TCG_REG_F10,
+ TCG_REG_F11,
+ TCG_REG_F12,
+ TCG_REG_F13,
+ TCG_REG_F14,
+ TCG_REG_F15,
+};
+
+/* Predicate registers */
+enum {
+ TCG_REG_P0 = 0,
+ TCG_REG_P1,
+ TCG_REG_P2,
+ TCG_REG_P3,
+ TCG_REG_P4,
+ TCG_REG_P5,
+ TCG_REG_P6,
+ TCG_REG_P7,
+ TCG_REG_P8,
+ TCG_REG_P9,
+ TCG_REG_P10,
+ TCG_REG_P11,
+ TCG_REG_P12,
+ TCG_REG_P13,
+ TCG_REG_P14,
+ TCG_REG_P15,
+};
+
+/* Application registers */
+enum {
+ TCG_REG_PFS = 64,
+};
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R34,
+ TCG_REG_R35,
+ TCG_REG_R36,
+ TCG_REG_R37,
+ TCG_REG_R38,
+ TCG_REG_R39,
+ TCG_REG_R40,
+ TCG_REG_R41,
+ TCG_REG_R42,
+ TCG_REG_R43,
+ TCG_REG_R44,
+ TCG_REG_R45,
+ TCG_REG_R46,
+ TCG_REG_R47,
+ TCG_REG_R48,
+ TCG_REG_R49,
+ TCG_REG_R50,
+ TCG_REG_R51,
+ TCG_REG_R52,
+ TCG_REG_R53,
+ TCG_REG_R54,
+ TCG_REG_R55,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31,
+ TCG_REG_R56,
+ TCG_REG_R57,
+ TCG_REG_R58,
+ TCG_REG_R59,
+ TCG_REG_R60,
+ TCG_REG_R61,
+ TCG_REG_R62,
+ TCG_REG_R63,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11
+};
+
+static const int tcg_target_call_iarg_regs[8] = {
+ TCG_REG_R56,
+ TCG_REG_R57,
+ TCG_REG_R58,
+ TCG_REG_R59,
+ TCG_REG_R60,
+ TCG_REG_R61,
+ TCG_REG_R62,
+ TCG_REG_R63,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_R8,
+ TCG_REG_R9
+};
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 8;
+}
+
+/*
+ * opcode formation
+ */
+
+/* bundle templates: stops (double bar in the IA64 manual) are marked with
+ an uppercase letter. */
+enum {
+ mii = 0x00,
+ miI = 0x01,
+ mIi = 0x02,
+ mII = 0x03,
+ mlx = 0x04,
+ mLX = 0x05,
+ mmi = 0x08,
+ mmI = 0x09,
+ Mmi = 0x0a,
+ MmI = 0x0b,
+ mfi = 0x0c,
+ mfI = 0x0d,
+ mmf = 0x0e,
+ mmF = 0x0f,
+ mib = 0x10,
+ miB = 0x11,
+ mbb = 0x12,
+ mbB = 0x13,
+ bbb = 0x16,
+ bbB = 0x17,
+ mmb = 0x18,
+ mmB = 0x19,
+ mfb = 0x1c,
+ mfB = 0x1d,
+};
+
+enum {
+ OPC_ADD_A1 = 0x10000000000ull,
+ OPC_AND_A1 = 0x10060000000ull,
+ OPC_AND_A3 = 0x10160000000ull,
+ OPC_ANDCM_A1 = 0x10068000000ull,
+ OPC_ANDCM_A3 = 0x10168000000ull,
+ OPC_ADDS_A4 = 0x10800000000ull,
+ OPC_ADDL_A5 = 0x12000000000ull,
+ OPC_ALLOC_M34 = 0x02c00000000ull,
+ OPC_BR_DPTK_FEW_B1 = 0x08400000000ull,
+ OPC_BR_SPTK_MANY_B1 = 0x08000001000ull,
+ OPC_BR_SPTK_MANY_B4 = 0x00100001000ull,
+ OPC_BR_CALL_SPTK_MANY_B5 = 0x02100001000ull,
+ OPC_BR_RET_SPTK_MANY_B4 = 0x00108001100ull,
+ OPC_BRL_SPTK_MANY_X3 = 0x18000001000ull,
+ OPC_CMP_LT_A6 = 0x18000000000ull,
+ OPC_CMP_LTU_A6 = 0x1a000000000ull,
+ OPC_CMP_EQ_A6 = 0x1c000000000ull,
+ OPC_CMP4_LT_A6 = 0x18400000000ull,
+ OPC_CMP4_LTU_A6 = 0x1a400000000ull,
+ OPC_CMP4_EQ_A6 = 0x1c400000000ull,
+ OPC_DEP_Z_I12 = 0x0a600000000ull,
+ OPC_EXTR_I11 = 0x0a400002000ull,
+ OPC_EXTR_U_I11 = 0x0a400000000ull,
+ OPC_FCVT_FX_TRUNC_S1_F10 = 0x004d0000000ull,
+ OPC_FCVT_FXU_TRUNC_S1_F10 = 0x004d8000000ull,
+ OPC_FCVT_XF_F11 = 0x000e0000000ull,
+ OPC_FMA_S1_F1 = 0x10400000000ull,
+ OPC_FNMA_S1_F1 = 0x18400000000ull,
+ OPC_FRCPA_S1_F6 = 0x00600000000ull,
+ OPC_GETF_SIG_M19 = 0x08708000000ull,
+ OPC_LD1_M1 = 0x08000000000ull,
+ OPC_LD1_M3 = 0x0a000000000ull,
+ OPC_LD2_M1 = 0x08040000000ull,
+ OPC_LD2_M3 = 0x0a040000000ull,
+ OPC_LD4_M1 = 0x08080000000ull,
+ OPC_LD4_M3 = 0x0a080000000ull,
+ OPC_LD8_M1 = 0x080c0000000ull,
+ OPC_LD8_M3 = 0x0a0c0000000ull,
+ OPC_MUX1_I3 = 0x0eca0000000ull,
+ OPC_NOP_B9 = 0x04008000000ull,
+ OPC_NOP_F16 = 0x00008000000ull,
+ OPC_NOP_I18 = 0x00008000000ull,
+ OPC_NOP_M48 = 0x00008000000ull,
+ OPC_MOV_I21 = 0x00e00100000ull,
+ OPC_MOV_RET_I21 = 0x00e00500000ull,
+ OPC_MOV_I22 = 0x00188000000ull,
+ OPC_MOV_I_I26 = 0x00150000000ull,
+ OPC_MOVL_X2 = 0x0c000000000ull,
+ OPC_OR_A1 = 0x10070000000ull,
+ OPC_SETF_EXP_M18 = 0x0c748000000ull,
+ OPC_SETF_SIG_M18 = 0x0c708000000ull,
+ OPC_SHL_I7 = 0x0f240000000ull,
+ OPC_SHR_I5 = 0x0f220000000ull,
+ OPC_SHR_U_I5 = 0x0f200000000ull,
+ OPC_SHRP_I10 = 0x0ac00000000ull,
+ OPC_SXT1_I29 = 0x000a0000000ull,
+ OPC_SXT2_I29 = 0x000a8000000ull,
+ OPC_SXT4_I29 = 0x000b0000000ull,
+ OPC_ST1_M4 = 0x08c00000000ull,
+ OPC_ST2_M4 = 0x08c40000000ull,
+ OPC_ST4_M4 = 0x08c80000000ull,
+ OPC_ST8_M4 = 0x08cc0000000ull,
+ OPC_SUB_A1 = 0x10028000000ull,
+ OPC_SUB_A3 = 0x10128000000ull,
+ OPC_UNPACK4_L_I2 = 0x0f860000000ull,
+ OPC_XMA_L_F2 = 0x1d000000000ull,
+ OPC_XOR_A1 = 0x10078000000ull,
+ OPC_ZXT1_I29 = 0x00080000000ull,
+ OPC_ZXT2_I29 = 0x00088000000ull,
+ OPC_ZXT4_I29 = 0x00090000000ull,
+};
+
+static inline uint64_t tcg_opc_a1(int qp, uint64_t opc, int r1,
+ int r2, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a3(int qp, uint64_t opc, int r1,
+ uint64_t imm, int r3)
+{
+ return opc
+ | ((imm & 0x80) << 29) /* s */
+ | ((imm & 0x7f) << 13) /* imm7b */
+ | ((r3 & 0x7f) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a4(int qp, uint64_t opc, int r1,
+ uint64_t imm, int r3)
+{
+ return opc
+ | ((imm & 0x2000) << 23) /* s */
+ | ((imm & 0x1f80) << 20) /* imm6d */
+ | ((imm & 0x007f) << 13) /* imm7b */
+ | ((r3 & 0x7f) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a5(int qp, uint64_t opc, int r1,
+ uint64_t imm, int r3)
+{
+ return opc
+ | ((imm & 0x200000) << 15) /* s */
+ | ((imm & 0x1f0000) << 6) /* imm5c */
+ | ((imm & 0x00ff80) << 20) /* imm9d */
+ | ((imm & 0x00007f) << 13) /* imm7b */
+ | ((r3 & 0x03) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_a6(int qp, uint64_t opc, int p1,
+ int p2, int r2, int r3)
+{
+ return opc
+ | ((p2 & 0x3f) << 27)
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((p1 & 0x3f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b1(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100000) << 16) /* s */
+ | ((imm & 0x0fffff) << 13) /* imm20b */
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b4(int qp, uint64_t opc, int b2)
+{
+ return opc
+ | ((b2 & 0x7) << 13)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_b5(int qp, uint64_t opc, int b1, int b2)
+{
+ return opc
+ | ((b2 & 0x7) << 13)
+ | ((b1 & 0x7) << 6)
+ | (qp & 0x3f);
+}
+
+
+static inline uint64_t tcg_opc_b9(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100000) << 16) /* i */
+ | ((imm & 0x0fffff) << 6) /* imm20a */
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f1(int qp, uint64_t opc, int f1,
+ int f3, int f4, int f2)
+{
+ return opc
+ | ((f4 & 0x7f) << 27)
+ | ((f3 & 0x7f) << 20)
+ | ((f2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f2(int qp, uint64_t opc, int f1,
+ int f3, int f4, int f2)
+{
+ return opc
+ | ((f4 & 0x7f) << 27)
+ | ((f3 & 0x7f) << 20)
+ | ((f2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f6(int qp, uint64_t opc, int f1,
+ int p2, int f2, int f3)
+{
+ return opc
+ | ((p2 & 0x3f) << 27)
+ | ((f3 & 0x7f) << 20)
+ | ((f2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f10(int qp, uint64_t opc, int f1, int f2)
+{
+ return opc
+ | ((f2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f11(int qp, uint64_t opc, int f1, int f2)
+{
+ return opc
+ | ((f2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_f16(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100000) << 16) /* i */
+ | ((imm & 0x0fffff) << 6) /* imm20a */
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i2(int qp, uint64_t opc, int r1,
+ int r2, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i3(int qp, uint64_t opc, int r1,
+ int r2, int mbtype)
+{
+ return opc
+ | ((mbtype & 0x0f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i5(int qp, uint64_t opc, int r1,
+ int r3, int r2)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i7(int qp, uint64_t opc, int r1,
+ int r2, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i10(int qp, uint64_t opc, int r1,
+ int r2, int r3, uint64_t count)
+{
+ return opc
+ | ((count & 0x3f) << 27)
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i11(int qp, uint64_t opc, int r1,
+ int r3, uint64_t pos, uint64_t len)
+{
+ return opc
+ | ((len & 0x3f) << 27)
+ | ((r3 & 0x7f) << 20)
+ | ((pos & 0x3f) << 14)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i12(int qp, uint64_t opc, int r1,
+ int r2, uint64_t pos, uint64_t len)
+{
+ return opc
+ | ((len & 0x3f) << 27)
+ | ((pos & 0x3f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i18(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100000) << 16) /* i */
+ | ((imm & 0x0fffff) << 6) /* imm20a */
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i21(int qp, uint64_t opc, int b1,
+ int r2, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x1ff) << 24)
+ | ((r2 & 0x7f) << 13)
+ | ((b1 & 0x7) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i22(int qp, uint64_t opc, int r1, int b2)
+{
+ return opc
+ | ((b2 & 0x7) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i26(int qp, uint64_t opc, int ar3, int r2)
+{
+ return opc
+ | ((ar3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_i29(int qp, uint64_t opc, int r1, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_l2(uint64_t imm)
+{
+ return (imm & 0x7fffffffffc00000ull) >> 22;
+}
+
+static inline uint64_t tcg_opc_l3(uint64_t imm)
+{
+ return (imm & 0x07fffffffff00000ull) >> 18;
+}
+
+static inline uint64_t tcg_opc_m1(int qp, uint64_t opc, int r1, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m3(int qp, uint64_t opc, int r1,
+ int r3, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100) << 28) /* s */
+ | ((imm & 0x080) << 20) /* i */
+ | ((imm & 0x07f) << 13) /* imm7b */
+ | ((r3 & 0x7f) << 20)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m4(int qp, uint64_t opc, int r2, int r3)
+{
+ return opc
+ | ((r3 & 0x7f) << 20)
+ | ((r2 & 0x7f) << 13)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m18(int qp, uint64_t opc, int f1, int r2)
+{
+ return opc
+ | ((r2 & 0x7f) << 13)
+ | ((f1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m19(int qp, uint64_t opc, int r1, int f2)
+{
+ return opc
+ | ((f2 & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m34(int qp, uint64_t opc, int r1,
+ int sof, int sol, int sor)
+{
+ return opc
+ | ((sor & 0x0f) << 27)
+ | ((sol & 0x7f) << 20)
+ | ((sof & 0x7f) << 13)
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_m48(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x100000) << 16) /* i */
+ | ((imm & 0x0fffff) << 6) /* imm20a */
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_x2(int qp, uint64_t opc,
+ int r1, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x8000000000000000ull) >> 27) /* i */
+ | (imm & 0x0000000000200000ull) /* ic */
+ | ((imm & 0x00000000001f0000ull) << 6) /* imm5c */
+ | ((imm & 0x000000000000ff80ull) << 20) /* imm9d */
+ | ((imm & 0x000000000000007full) << 13) /* imm7b */
+ | ((r1 & 0x7f) << 6)
+ | (qp & 0x3f);
+}
+
+static inline uint64_t tcg_opc_x3(int qp, uint64_t opc, uint64_t imm)
+{
+ return opc
+ | ((imm & 0x0800000000000000ull) >> 23) /* i */
+ | ((imm & 0x00000000000fffffull) << 13) /* imm20b */
+ | (qp & 0x3f);
+}
+
+
+/*
+ * Relocations
+ */
+
+static inline void reloc_pcrel21b (void *pc, tcg_target_long target)
+{
+ uint64_t imm;
+ int64_t disp;
+ int slot;
+
+ slot = (tcg_target_long) pc & 3;
+ pc = (void *)((tcg_target_long) pc & ~3);
+
+ disp = target - (tcg_target_long) pc;
+ imm = (uint64_t) disp >> 4;
+
+ switch(slot) {
+ case 0:
+ *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 8) & 0xfffffdc00003ffffull)
+ | ((imm & 0x100000) << 21) /* s */
+ | ((imm & 0x0fffff) << 18); /* imm20b */
+ break;
+ case 1:
+ *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xfffffffffffb8000ull)
+ | ((imm & 0x100000) >> 2) /* s */
+ | ((imm & 0x0fffe0) >> 5); /* imm20b */
+ *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x07ffffffffffffffull)
+ | ((imm & 0x00001f) << 59); /* imm20b */
+ break;
+ case 2:
+ *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fffffffffull)
+ | ((imm & 0x100000) << 39) /* s */
+ | ((imm & 0x0fffff) << 36); /* imm20b */
+ break;
+ }
+}
+
+static inline uint64_t get_reloc_pcrel21b (void *pc)
+{
+ int64_t low, high;
+ int slot;
+
+ slot = (tcg_target_long) pc & 3;
+ pc = (void *)((tcg_target_long) pc & ~3);
+
+ low = (*(uint64_t *)(pc + 0));
+ high = (*(uint64_t *)(pc + 8));
+
+ switch(slot) {
+ case 0:
+ return ((low >> 21) & 0x100000) + /* s */
+ ((low >> 18) & 0x0fffff); /* imm20b */
+ case 1:
+ return ((high << 2) & 0x100000) + /* s */
+ ((high << 5) & 0x0fffe0) + /* imm20b */
+ ((low >> 59) & 0x00001f); /* imm20b */
+ case 2:
+ return ((high >> 39) & 0x100000) + /* s */
+ ((high >> 36) & 0x0fffff); /* imm20b */
+ default:
+ tcg_abort();
+ }
+}
+
+static inline void reloc_pcrel60b (void *pc, tcg_target_long target)
+{
+ int64_t disp;
+ uint64_t imm;
+
+ disp = target - (tcg_target_long) pc;
+ imm = (uint64_t) disp >> 4;
+
+ *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fff800000ull)
+ | (imm & 0x0800000000000000ull) /* s */
+ | ((imm & 0x07fffff000000000ull) >> 36) /* imm39 */
+ | ((imm & 0x00000000000fffffull) << 36); /* imm20b */
+ *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x00003fffffffffffull)
+ | ((imm & 0x0000000ffff00000ull) << 28); /* imm39 */
+}
+
+static inline uint64_t get_reloc_pcrel60b (void *pc)
+{
+ int64_t low, high;
+
+ low = (*(uint64_t *)(pc + 0));
+ high = (*(uint64_t *)(pc + 8));
+
+ return ((high) & 0x0800000000000000ull) + /* s */
+ ((high >> 36) & 0x00000000000fffffull) + /* imm20b */
+ ((high << 36) & 0x07fffff000000000ull) + /* imm39 */
+ ((low >> 28) & 0x0000000ffff00000ull); /* imm39 */
+}
+
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch (type) {
+ case R_IA64_PCREL21B:
+ reloc_pcrel21b(code_ptr, value);
+ break;
+ case R_IA64_PCREL60B:
+ reloc_pcrel60b(code_ptr, value);
+ default:
+ tcg_abort();
+ }
+}
+
+/*
+ * Constraints
+ */
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch(ct_str[0]) {
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffffffffffffull);
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_S22;
+ break;
+ case 'S':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffffffffffffull);
+#if defined(CONFIG_SOFTMMU)
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R56);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R57);
+#endif
+ break;
+ case 'Z':
+ /* We are cheating a bit here, using the fact that the register
+ r0 is also the register number 0. Hence there is no need
+ to check for const_args in each instruction. */
+ ct->ct |= TCG_CT_CONST_ZERO;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+ return 1;
+ else if ((ct & TCG_CT_CONST_S22) && val == ((int32_t)val << 10) >> 10)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Code generation
+ */
+
+static uint8_t *tb_ret_addr;
+
+static inline void tcg_out_bundle(TCGContext *s, int template,
+ uint64_t slot0, uint64_t slot1,
+ uint64_t slot2)
+{
+ template &= 0x1f; /* 5 bits */
+ slot0 &= 0x1ffffffffffull; /* 41 bits */
+ slot1 &= 0x1ffffffffffull; /* 41 bits */
+ slot2 &= 0x1ffffffffffull; /* 41 bits */
+
+ *(uint64_t *)(s->code_ptr + 0) = (slot1 << 46) | (slot0 << 5) | template;
+ *(uint64_t *)(s->code_ptr + 8) = (slot2 << 23) | (slot1 >> 18);
+ s->code_ptr += 16;
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+ TCGArg ret, TCGArg arg)
+{
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, ret, 0, arg));
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+ TCGArg reg, tcg_target_long arg)
+{
+ tcg_out_bundle(s, mLX,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_l2 (arg),
+ tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, reg, arg));
+}
+
+static inline void tcg_out_addi(TCGContext *s, TCGArg reg, tcg_target_long val)
+{
+ if (val == ((int32_t)val << 10) >> 10) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+ TCG_REG_R2, val, TCG_REG_R0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
+ reg, TCG_REG_R2));
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, val);
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
+ reg, TCG_REG_R2));
+ }
+}
+
+static void tcg_out_br(TCGContext *s, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+
+ /* We pay attention here to not modify the branch target by reading
+ the existing value and using it again. This ensure that caches and
+ memory are kept coherent during retranslation. */
+ tcg_out_bundle(s, mmB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_b1 (TCG_REG_P0, OPC_BR_SPTK_MANY_B1,
+ get_reloc_pcrel21b(s->code_ptr + 2)));
+
+ if (l->has_value) {
+ reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value);
+ } else {
+ tcg_out_reloc(s, (s->code_ptr - 16) + 2,
+ R_IA64_PCREL21B, label_index, 0);
+ }
+}
+
+static inline void tcg_out_call(TCGContext *s, TCGArg addr)
+{
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R2, addr),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R3, 8, addr),
+ tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+ TCG_REG_B6, TCG_REG_R2, 0));
+ tcg_out_bundle(s, mmB,
+ tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R3),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_b5 (TCG_REG_P0, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+}
+
+static void tcg_out_exit_tb(TCGContext *s, tcg_target_long arg)
+{
+ int64_t disp;
+ uint64_t imm;
+
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R8, arg);
+
+ disp = tb_ret_addr - s->code_ptr;
+ imm = (uint64_t)disp >> 4;
+
+ tcg_out_bundle(s, mLX,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_l3 (imm),
+ tcg_opc_x3 (TCG_REG_P0, OPC_BRL_SPTK_MANY_X3, imm));
+}
+
+static inline void tcg_out_goto_tb(TCGContext *s, TCGArg arg)
+{
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+ tcg_abort();
+ } else {
+ /* indirect jump method */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2,
+ (tcg_target_long)(s->tb_next + arg));
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1,
+ TCG_REG_R2, TCG_REG_R2),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, TCG_REG_B6,
+ TCG_REG_R2, 0));
+ tcg_out_bundle(s, mmB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4,
+ TCG_REG_B6));
+ }
+ s->tb_next_offset[arg] = s->code_ptr - s->code_buf;
+}
+
+static inline void tcg_out_jmp(TCGContext *s, TCGArg addr)
+{
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, TCG_REG_B6, addr, 0));
+ tcg_out_bundle(s, mmB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_b4(TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
+}
+
+static inline void tcg_out_ld_rel(TCGContext *s, uint64_t opc_m4, TCGArg arg,
+ TCGArg arg1, tcg_target_long arg2)
+{
+ if (arg2 == ((int16_t)arg2 >> 2) << 2) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4,
+ TCG_REG_R2, arg2, arg1),
+ tcg_opc_m1 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, arg2);
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1,
+ TCG_REG_R2, TCG_REG_R2, arg1),
+ tcg_opc_m1 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+}
+
+static inline void tcg_out_st_rel(TCGContext *s, uint64_t opc_m4, TCGArg arg,
+ TCGArg arg1, tcg_target_long arg2)
+{
+ if (arg2 == ((int16_t)arg2 >> 2) << 2) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4,
+ TCG_REG_R2, arg2, arg1),
+ tcg_opc_m4 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, arg2);
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1,
+ TCG_REG_R2, TCG_REG_R2, arg1),
+ tcg_opc_m4 (TCG_REG_P0, opc_m4, arg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGArg arg,
+ TCGArg arg1, tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_ld_rel(s, OPC_LD4_M1, arg, arg1, arg2);
+ } else {
+ tcg_out_ld_rel(s, OPC_LD8_M1, arg, arg1, arg2);
+ }
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGArg arg,
+ TCGArg arg1, tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_st_rel(s, OPC_ST4_M4, arg, arg1, arg2);
+ } else {
+ tcg_out_st_rel(s, OPC_ST8_M4, arg, arg1, arg2);
+ }
+}
+
+static inline void tcg_out_alu(TCGContext *s, uint64_t opc_a1, TCGArg ret,
+ TCGArg arg1, int const_arg1,
+ TCGArg arg2, int const_arg2)
+{
+ uint64_t opc1, opc2;
+
+ if (const_arg1 && arg1 != 0) {
+ opc1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+ TCG_REG_R2, arg1, TCG_REG_R0);
+ arg1 = TCG_REG_R2;
+ } else {
+ opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+ }
+
+ if (const_arg2 && arg2 != 0) {
+ opc2 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
+ TCG_REG_R3, arg2, TCG_REG_R0);
+ arg2 = TCG_REG_R3;
+ } else {
+ opc2 = tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0);
+ }
+
+ tcg_out_bundle(s, mII,
+ opc1,
+ opc2,
+ tcg_opc_a1(TCG_REG_P0, opc_a1, ret, arg1, arg2));
+}
+
+static inline void tcg_out_eqv(TCGContext *s, TCGArg ret,
+ TCGArg arg1, int const_arg1,
+ TCGArg arg2, int const_arg2)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_XOR_A1, ret, arg1, arg2),
+ tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_nand(TCGContext *s, TCGArg ret,
+ TCGArg arg1, int const_arg1,
+ TCGArg arg2, int const_arg2)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, ret, arg1, arg2),
+ tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_nor(TCGContext *s, TCGArg ret,
+ TCGArg arg1, int const_arg1,
+ TCGArg arg2, int const_arg2)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret, arg1, arg2),
+ tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, ret, -1, ret));
+}
+
+static inline void tcg_out_orc(TCGContext *s, TCGArg ret,
+ TCGArg arg1, int const_arg1,
+ TCGArg arg2, int const_arg2)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a3 (TCG_REG_P0, OPC_ANDCM_A3, TCG_REG_R2, -1, arg2),
+ tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret, arg1, TCG_REG_R2));
+}
+
+static inline void tcg_out_mul(TCGContext *s, TCGArg ret,
+ TCGArg arg1, TCGArg arg2)
+{
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m18(TCG_REG_P0, OPC_SETF_SIG_M18, TCG_REG_F6, arg1),
+ tcg_opc_m18(TCG_REG_P0, OPC_SETF_SIG_M18, TCG_REG_F7, arg2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ tcg_out_bundle(s, mmF,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_f2 (TCG_REG_P0, OPC_XMA_L_F2, TCG_REG_F6, TCG_REG_F6,
+ TCG_REG_F7, TCG_REG_F0));
+ tcg_out_bundle(s, miI,
+ tcg_opc_m19(TCG_REG_P0, OPC_GETF_SIG_M19, ret, TCG_REG_F6),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+}
+
+static inline void tcg_out_sar_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_I11,
+ ret, arg1, arg2, 31 - arg2));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3,
+ TCG_REG_R3, 0x1f, arg2),
+ tcg_opc_i29(TCG_REG_P0, OPC_SXT4_I29, TCG_REG_R2, arg1),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_I5, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_sar_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_I11,
+ ret, arg1, arg2, 63 - arg2));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_I5, ret, arg1, arg2));
+ }
+}
+
+static inline void tcg_out_shl_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret,
+ arg1, 63 - arg2, 31 - arg2));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R2,
+ 0x1f, arg2),
+ tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, ret,
+ arg1, TCG_REG_R2));
+ }
+}
+
+static inline void tcg_out_shl_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret,
+ arg1, 63 - arg2, 63 - arg2));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, ret,
+ arg1, arg2));
+ }
+}
+
+static inline void tcg_out_shr_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+ arg1, arg2, 31 - arg2));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+ 0x1f, arg2),
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R2, arg1),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_shr_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+ arg1, arg2, 63 - arg2));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+ arg1, arg2));
+ }
+}
+
+static inline void tcg_out_rotl_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+ TCG_REG_R2, arg1, arg1),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+ TCG_REG_R2, 32 - arg2, 31));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+ TCG_REG_R2, arg1, arg1),
+ tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+ 0x1f, arg2));
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R3,
+ 0x20, TCG_REG_R3),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_rotl_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i10(TCG_REG_P0, OPC_SHRP_I10, ret, arg1,
+ arg1, 0x40 - arg2));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R2,
+ 0x40, arg2),
+ tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, TCG_REG_R3,
+ arg1, arg2),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, TCG_REG_R2,
+ arg1, TCG_REG_R2));
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_rotr_i32(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+ TCG_REG_R2, arg1, arg1),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, ret,
+ TCG_REG_R2, arg2, 31));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_a3 (TCG_REG_P0, OPC_AND_A3, TCG_REG_R3,
+ 0x1f, arg2),
+ tcg_opc_i2 (TCG_REG_P0, OPC_UNPACK4_L_I2,
+ TCG_REG_R2, arg1, arg1),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_rotr_i64(TCGContext *s, TCGArg ret, TCGArg arg1,
+ TCGArg arg2, int const_arg2)
+{
+ if (const_arg2) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i10(TCG_REG_P0, OPC_SHRP_I10, ret, arg1,
+ arg1, arg2));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_a3 (TCG_REG_P0, OPC_SUB_A3, TCG_REG_R2,
+ 0x40, arg2),
+ tcg_opc_i5 (TCG_REG_P0, OPC_SHR_U_I5, TCG_REG_R3,
+ arg1, arg2),
+ tcg_opc_i7 (TCG_REG_P0, OPC_SHL_I7, TCG_REG_R2,
+ arg1, TCG_REG_R2));
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_a1 (TCG_REG_P0, OPC_OR_A1, ret,
+ TCG_REG_R2, TCG_REG_R3));
+ }
+}
+
+static inline void tcg_out_ext(TCGContext *s, uint64_t opc_i29,
+ TCGArg ret, TCGArg arg)
+{
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i29(TCG_REG_P0, opc_i29, ret, arg));
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret, arg, 15, 15),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, ret, 0xb));
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, ret, arg, 31, 31),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, ret, 0xb));
+}
+
+static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg)
+{
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb));
+}
+
+static inline uint64_t tcg_opc_cmp_a(int qp, TCGCond cond, TCGArg arg1,
+ TCGArg arg2, int cmp4)
+{
+ uint64_t opc_eq_a6, opc_lt_a6, opc_ltu_a6;
+
+ if (cmp4) {
+ opc_eq_a6 = OPC_CMP4_EQ_A6;
+ opc_lt_a6 = OPC_CMP4_LT_A6;
+ opc_ltu_a6 = OPC_CMP4_LTU_A6;
+ } else {
+ opc_eq_a6 = OPC_CMP_EQ_A6;
+ opc_lt_a6 = OPC_CMP_LT_A6;
+ opc_ltu_a6 = OPC_CMP_LTU_A6;
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ return tcg_opc_a6 (qp, opc_eq_a6, TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+ case TCG_COND_NE:
+ return tcg_opc_a6 (qp, opc_eq_a6, TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+ case TCG_COND_LT:
+ return tcg_opc_a6 (qp, opc_lt_a6, TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+ case TCG_COND_LTU:
+ return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P6, TCG_REG_P7, arg1, arg2);
+ case TCG_COND_GE:
+ return tcg_opc_a6 (qp, opc_lt_a6, TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+ case TCG_COND_GEU:
+ return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P7, TCG_REG_P6, arg1, arg2);
+ case TCG_COND_LE:
+ return tcg_opc_a6 (qp, opc_lt_a6, TCG_REG_P7, TCG_REG_P6, arg2, arg1);
+ case TCG_COND_LEU:
+ return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P7, TCG_REG_P6, arg2, arg1);
+ case TCG_COND_GT:
+ return tcg_opc_a6 (qp, opc_lt_a6, TCG_REG_P6, TCG_REG_P7, arg2, arg1);
+ case TCG_COND_GTU:
+ return tcg_opc_a6 (qp, opc_ltu_a6, TCG_REG_P6, TCG_REG_P7, arg2, arg1);
+ default:
+ tcg_abort();
+ break;
+ }
+}
+
+static inline void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1,
+ int const_arg1, TCGArg arg2, int const_arg2,
+ int label_index, int cmp4)
+{
+ TCGLabel *l = &s->labels[label_index];
+ uint64_t opc1, opc2;
+
+ if (const_arg1 && arg1 != 0) {
+ opc1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2,
+ arg1, TCG_REG_R0);
+ arg1 = TCG_REG_R2;
+ } else {
+ opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+ }
+
+ if (const_arg2 && arg2 != 0) {
+ opc2 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3,
+ arg2, TCG_REG_R0);
+ arg2 = TCG_REG_R3;
+ } else {
+ opc2 = tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0);
+ }
+
+ tcg_out_bundle(s, mII,
+ opc1,
+ opc2,
+ tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4));
+ tcg_out_bundle(s, mmB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_b1 (TCG_REG_P6, OPC_BR_DPTK_FEW_B1,
+ get_reloc_pcrel21b(s->code_ptr + 2)));
+
+ if (l->has_value) {
+ reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value);
+ } else {
+ tcg_out_reloc(s, (s->code_ptr - 16) + 2,
+ R_IA64_PCREL21B, label_index, 0);
+ }
+}
+
+static inline void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg ret,
+ TCGArg arg1, TCGArg arg2, int cmp4)
+{
+ tcg_out_bundle(s, MmI,
+ tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4),
+ tcg_opc_a5(TCG_REG_P6, OPC_ADDL_A5, ret, 1, TCG_REG_R0),
+ tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, 0, TCG_REG_R0));
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+/* Load and compare a TLB entry, and return the result in (p6, p7).
+ R2 is loaded with the address of the addend TLB entry.
+ R56 is loaded with the address, zero extented on 32-bit targets. */
+static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg,
+ int s_bits, uint64_t offset_rw,
+ uint64_t offset_addend)
+{
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3,
+ TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+ TCG_REG_R0),
+ tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R2,
+ addr_reg, TARGET_PAGE_BITS, CPU_TLB_BITS - 1),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R2,
+ TCG_REG_R2, 63 - CPU_TLB_ENTRY_BITS,
+ 63 - CPU_TLB_ENTRY_BITS));
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2,
+ offset_rw, TCG_REG_R2),
+#if TARGET_LONG_BITS == 32
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R56, addr_reg),
+#else
+ tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R56,
+ 0, addr_reg),
+#endif
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+ TCG_REG_R2, TCG_AREG0));
+ tcg_out_bundle(s, mII,
+ tcg_opc_m3 (TCG_REG_P0,
+ (TARGET_LONG_BITS == 32
+ ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R57,
+ TCG_REG_R2, offset_addend - offset_rw),
+ tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3,
+ TCG_REG_R3, TCG_REG_R56),
+ tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6,
+ TCG_REG_P7, TCG_REG_R3, TCG_REG_R57));
+}
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, mem_index, s_bits, bswap;
+ uint64_t opc_ld_m1[4] = { OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1 };
+ uint64_t opc_ext_i29[8] = { OPC_ZXT1_I29, OPC_ZXT2_I29, OPC_ZXT4_I29, 0,
+ OPC_SXT1_I29, OPC_SXT2_I29, OPC_SXT4_I29, 0 };
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+ s_bits = opc & 3;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+ /* Read the TLB entry */
+ tcg_out_qemu_tlb(s, addr_reg, s_bits,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_read),
+ offsetof(CPUState, tlb_table[mem_index][0].addend));
+
+ /* P6 is the fast path, and P7 the slow path */
+ tcg_out_bundle(s, mLX,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R57,
+ mem_index, TCG_REG_R0),
+ tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]),
+ tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
+ (tcg_target_long) qemu_ld_helpers[s_bits]));
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+ TCG_REG_R2, 8),
+ tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
+ TCG_REG_R3, TCG_REG_R56),
+ tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
+ TCG_REG_R3, 0));
+ if (bswap && s_bits == 1) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+ TCG_REG_R8, TCG_REG_R3),
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+ TCG_REG_R8, TCG_REG_R8, 15, 15));
+ } else if (bswap && s_bits == 2) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+ TCG_REG_R8, TCG_REG_R3),
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+ TCG_REG_R8, TCG_REG_R8, 31, 31));
+ } else {
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits],
+ TCG_REG_R8, TCG_REG_R3),
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+ if (!bswap || s_bits == 0) {
+ tcg_out_bundle(s, miB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+ } else {
+ tcg_out_bundle(s, miB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+ TCG_REG_R8, TCG_REG_R8, 0xb),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+ }
+
+ if (opc == 3) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ data_reg, 0, TCG_REG_R8));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i29(TCG_REG_P0, opc_ext_i29[opc],
+ data_reg, TCG_REG_R8));
+ }
+}
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, mem_index, bswap;
+ uint64_t opc_st_m4[4] = { OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4 };
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+ tcg_out_qemu_tlb(s, addr_reg, opc,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_write),
+ offsetof(CPUState, tlb_table[mem_index][0].addend));
+
+ /* P6 is the fast path, and P7 the slow path */
+ tcg_out_bundle(s, mLX,
+ tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R57,
+ 0, data_reg),
+ tcg_opc_l2 ((tcg_target_long) qemu_st_helpers[opc]),
+ tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2,
+ (tcg_target_long) qemu_st_helpers[opc]));
+ tcg_out_bundle(s, MmI,
+ tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3,
+ TCG_REG_R2, 8),
+ tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3,
+ TCG_REG_R3, TCG_REG_R56),
+ tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6,
+ TCG_REG_R3, 0));
+
+ if (!bswap || opc == 0) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+ TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else if (opc == 1) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+ TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+ TCG_REG_R2, data_reg, 15, 15),
+ tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+ TCG_REG_R2, TCG_REG_R2, 0xb));
+ data_reg = TCG_REG_R2;
+ } else if (opc == 2) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+ TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12,
+ TCG_REG_R2, data_reg, 31, 31),
+ tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+ TCG_REG_R2, TCG_REG_R2, 0xb));
+ data_reg = TCG_REG_R2;
+ } else if (opc == 3) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1,
+ TCG_REG_R1, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3,
+ TCG_REG_R2, data_reg, 0xb));
+ data_reg = TCG_REG_R2;
+ }
+
+ tcg_out_bundle(s, miB,
+ tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
+ data_reg, TCG_REG_R3),
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58,
+ mem_index, TCG_REG_R0),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+}
+
+#else /* !CONFIG_SOFTMMU */
+
+static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ static uint64_t const opc_ld_m1[4] = {
+ OPC_LD1_M1, OPC_LD2_M1, OPC_LD4_M1, OPC_LD8_M1
+ };
+ static uint64_t const opc_sxt_i29[4] = {
+ OPC_SXT1_I29, OPC_SXT2_I29, OPC_SXT4_I29, 0
+ };
+ int addr_reg, data_reg, s_bits, bswap;
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ s_bits = opc & 3;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+#if TARGET_LONG_BITS == 32
+ if (GUEST_BASE != 0) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+ TCG_REG_R3, addr_reg),
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+ TCG_GUEST_BASE_REG, TCG_REG_R3));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+ TCG_REG_R2, addr_reg),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+
+ if (!bswap || s_bits == 0) {
+ if (s_bits == opc) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+ data_reg, data_reg));
+ }
+ } else if (s_bits == 3) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb));
+ } else {
+ if (s_bits == 1) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ data_reg, data_reg, 15, 15));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ data_reg, data_reg, 31, 31));
+ }
+ if (opc == s_bits) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb));
+ } else {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb),
+ tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+ data_reg, data_reg));
+ }
+ }
+#else
+ if (GUEST_BASE != 0) {
+ tcg_out_bundle(s, MmI,
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+ TCG_GUEST_BASE_REG, addr_reg),
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, TCG_REG_R2),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else {
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_m1 (TCG_REG_P0, opc_ld_m1[s_bits],
+ data_reg, addr_reg),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+
+ if (bswap && s_bits == 1) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ data_reg, data_reg, 15, 15),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb));
+ } else if (bswap && s_bits == 2) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ data_reg, data_reg, 31, 31),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb));
+ } else if (bswap && s_bits == 3) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ data_reg, data_reg, 0xb));
+ }
+ if (s_bits != opc) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i29(TCG_REG_P0, opc_sxt_i29[s_bits],
+ data_reg, data_reg));
+ }
+#endif
+}
+
+static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+ static uint64_t const opc_st_m4[4] = {
+ OPC_ST1_M4, OPC_ST2_M4, OPC_ST4_M4, OPC_ST8_M4
+ };
+ int addr_reg, data_reg, bswap;
+#if TARGET_LONG_BITS == 64
+ uint64_t add_guest_base;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+#if TARGET_LONG_BITS == 32
+ if (GUEST_BASE != 0) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+ TCG_REG_R3, addr_reg),
+ tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+ TCG_GUEST_BASE_REG, TCG_REG_R3));
+ } else {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29,
+ TCG_REG_R2, addr_reg),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+
+ if (bswap) {
+ if (opc == 1) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ TCG_REG_R3, data_reg, 15, 15),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, TCG_REG_R3, 0xb));
+ data_reg = TCG_REG_R3;
+ } else if (opc == 2) {
+ tcg_out_bundle(s, mII,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ TCG_REG_R3, data_reg, 31, 31),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, TCG_REG_R3, 0xb));
+ data_reg = TCG_REG_R3;
+ } else if (opc == 3) {
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, data_reg, 0xb));
+ data_reg = TCG_REG_R3;
+ }
+ }
+ tcg_out_bundle(s, mmI,
+ tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+ data_reg, TCG_REG_R2),
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+#else
+ if (GUEST_BASE != 0) {
+ add_guest_base = tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2,
+ TCG_GUEST_BASE_REG, addr_reg);
+ addr_reg = TCG_REG_R2;
+ } else {
+ add_guest_base = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0);
+ }
+
+ if (!bswap || opc == 0) {
+ tcg_out_bundle(s, (GUEST_BASE ? MmI : mmI),
+ add_guest_base,
+ tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+ data_reg, addr_reg),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ } else {
+ if (opc == 1) {
+ tcg_out_bundle(s, mII,
+ add_guest_base,
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ TCG_REG_R3, data_reg, 15, 15),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, TCG_REG_R3, 0xb));
+ data_reg = TCG_REG_R3;
+ } else if (opc == 2) {
+ tcg_out_bundle(s, mII,
+ add_guest_base,
+ tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12,
+ TCG_REG_R3, data_reg, 31, 31),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, TCG_REG_R3, 0xb));
+ data_reg = TCG_REG_R3;
+ } else if (opc == 3) {
+ tcg_out_bundle(s, miI,
+ add_guest_base,
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3,
+ TCG_REG_R3, data_reg, 0xb));
+ data_reg = TCG_REG_R3;
+ }
+ tcg_out_bundle(s, miI,
+ tcg_opc_m4 (TCG_REG_P0, opc_st_m4[opc],
+ data_reg, addr_reg),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
+ tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
+ }
+#endif
+}
+
+#endif
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ switch(opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_exit_tb(s, args[0]);
+ break;
+ case INDEX_op_br:
+ tcg_out_br(s, args[0]);
+ break;
+ case INDEX_op_call:
+ tcg_out_call(s, args[0]);
+ break;
+ case INDEX_op_goto_tb:
+ tcg_out_goto_tb(s, args[0]);
+ break;
+ case INDEX_op_jmp:
+ tcg_out_jmp(s, args[0]);
+ break;
+
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_movi_i64:
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+
+ case INDEX_op_ld8u_i32:
+ case INDEX_op_ld8u_i64:
+ tcg_out_ld_rel(s, OPC_LD1_M1, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld8s_i32:
+ case INDEX_op_ld8s_i64:
+ tcg_out_ld_rel(s, OPC_LD1_M1, args[0], args[1], args[2]);
+ tcg_out_ext(s, OPC_SXT1_I29, args[0], args[0]);
+ break;
+ case INDEX_op_ld16u_i32:
+ case INDEX_op_ld16u_i64:
+ tcg_out_ld_rel(s, OPC_LD2_M1, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld16s_i32:
+ case INDEX_op_ld16s_i64:
+ tcg_out_ld_rel(s, OPC_LD2_M1, args[0], args[1], args[2]);
+ tcg_out_ext(s, OPC_SXT2_I29, args[0], args[0]);
+ break;
+ case INDEX_op_ld_i32:
+ case INDEX_op_ld32u_i64:
+ tcg_out_ld_rel(s, OPC_LD4_M1, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_ld_rel(s, OPC_LD4_M1, args[0], args[1], args[2]);
+ tcg_out_ext(s, OPC_SXT4_I29, args[0], args[0]);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ld_rel(s, OPC_LD8_M1, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st8_i32:
+ case INDEX_op_st8_i64:
+ tcg_out_st_rel(s, OPC_ST1_M4, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st16_i32:
+ case INDEX_op_st16_i64:
+ tcg_out_st_rel(s, OPC_ST2_M4, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i32:
+ case INDEX_op_st32_i64:
+ tcg_out_st_rel(s, OPC_ST4_M4, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_st_rel(s, OPC_ST8_M4, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_add_i32:
+ case INDEX_op_add_i64:
+ tcg_out_alu(s, OPC_ADD_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_sub_i32:
+ case INDEX_op_sub_i64:
+ tcg_out_alu(s, OPC_SUB_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_and_i32:
+ case INDEX_op_and_i64:
+ tcg_out_alu(s, OPC_AND_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_andc_i32:
+ case INDEX_op_andc_i64:
+ tcg_out_alu(s, OPC_ANDCM_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_eqv_i32:
+ case INDEX_op_eqv_i64:
+ tcg_out_eqv(s, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_nand_i32:
+ case INDEX_op_nand_i64:
+ tcg_out_nand(s, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_nor_i32:
+ case INDEX_op_nor_i64:
+ tcg_out_nor(s, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_or_i32:
+ case INDEX_op_or_i64:
+ tcg_out_alu(s, OPC_OR_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_orc_i32:
+ case INDEX_op_orc_i64:
+ tcg_out_orc(s, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+ case INDEX_op_xor_i32:
+ case INDEX_op_xor_i64:
+ tcg_out_alu(s, OPC_XOR_A1, args[0], args[1], const_args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_mul_i32:
+ case INDEX_op_mul_i64:
+ tcg_out_mul(s, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_sar_i32:
+ tcg_out_sar_i32(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_sar_i64:
+ tcg_out_sar_i64(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_shl_i32:
+ tcg_out_shl_i32(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_shl_i64:
+ tcg_out_shl_i64(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_shr_i32:
+ tcg_out_shr_i32(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_shr_i64:
+ tcg_out_shr_i64(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_rotl_i32:
+ tcg_out_rotl_i32(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_rotl_i64:
+ tcg_out_rotl_i64(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_rotr_i32:
+ tcg_out_rotr_i32(s, args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_rotr_i64:
+ tcg_out_rotr_i64(s, args[0], args[1], args[2], const_args[2]);
+ break;
+
+ case INDEX_op_ext8s_i32:
+ case INDEX_op_ext8s_i64:
+ tcg_out_ext(s, OPC_SXT1_I29, args[0], args[1]);
+ break;
+ case INDEX_op_ext8u_i32:
+ case INDEX_op_ext8u_i64:
+ tcg_out_ext(s, OPC_ZXT1_I29, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i32:
+ case INDEX_op_ext16s_i64:
+ tcg_out_ext(s, OPC_SXT2_I29, args[0], args[1]);
+ break;
+ case INDEX_op_ext16u_i32:
+ case INDEX_op_ext16u_i64:
+ tcg_out_ext(s, OPC_ZXT2_I29, args[0], args[1]);
+ break;
+ case INDEX_op_ext32s_i64:
+ tcg_out_ext(s, OPC_SXT4_I29, args[0], args[1]);
+ break;
+ case INDEX_op_ext32u_i64:
+ tcg_out_ext(s, OPC_ZXT4_I29, args[0], args[1]);
+ break;
+
+ case INDEX_op_bswap16_i32:
+ case INDEX_op_bswap16_i64:
+ tcg_out_bswap16(s, args[0], args[1]);
+ break;
+ case INDEX_op_bswap32_i32:
+ case INDEX_op_bswap32_i64:
+ tcg_out_bswap32(s, args[0], args[1]);
+ break;
+ case INDEX_op_bswap64_i64:
+ tcg_out_bswap64(s, args[0], args[1]);
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond(s, args[2], args[0], const_args[0],
+ args[1], const_args[1], args[3], 1);
+ break;
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond(s, args[2], args[0], const_args[0],
+ args[1], const_args[1], args[3], 0);
+ break;
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond(s, args[3], args[0], args[1], args[2], 1);
+ break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond(s, args[3], args[0], args[1], args[2], 0);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ case INDEX_op_qemu_ld32u:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, 2 | 4);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ default:
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef ia64_op_defs[] = {
+ { INDEX_op_br, { } },
+ { INDEX_op_call, { "r" } },
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_jmp, { "r" } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "rZ", "r" } },
+ { INDEX_op_st16_i32, { "rZ", "r" } },
+ { INDEX_op_st_i32, { "rZ", "r" } },
+
+ { INDEX_op_add_i32, { "r", "rI", "rI" } },
+ { INDEX_op_sub_i32, { "r", "rI", "rI" } },
+
+ { INDEX_op_and_i32, { "r", "rI", "rI" } },
+ { INDEX_op_andc_i32, { "r", "rI", "rI" } },
+ { INDEX_op_eqv_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_nand_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_or_i32, { "r", "rI", "rI" } },
+ { INDEX_op_orc_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_xor_i32, { "r", "rI", "rI" } },
+
+ { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+
+ { INDEX_op_sar_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_shl_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_shr_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
+
+ { INDEX_op_ext8s_i32, { "r", "rZ"} },
+ { INDEX_op_ext8u_i32, { "r", "rZ"} },
+ { INDEX_op_ext16s_i32, { "r", "rZ"} },
+ { INDEX_op_ext16u_i32, { "r", "rZ"} },
+
+ { INDEX_op_bswap16_i32, { "r", "rZ" } },
+ { INDEX_op_bswap32_i32, { "r", "rZ" } },
+
+ { INDEX_op_brcond_i32, { "rI", "rI" } },
+ { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
+
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i64, { "rZ", "r" } },
+ { INDEX_op_st16_i64, { "rZ", "r" } },
+ { INDEX_op_st32_i64, { "rZ", "r" } },
+ { INDEX_op_st_i64, { "rZ", "r" } },
+
+ { INDEX_op_add_i64, { "r", "rI", "rI" } },
+ { INDEX_op_sub_i64, { "r", "rI", "rI" } },
+
+ { INDEX_op_and_i64, { "r", "rI", "rI" } },
+ { INDEX_op_andc_i64, { "r", "rI", "rI" } },
+ { INDEX_op_eqv_i64, { "r", "rZ", "rZ" } },
+ { INDEX_op_nand_i64, { "r", "rZ", "rZ" } },
+ { INDEX_op_nor_i64, { "r", "rZ", "rZ" } },
+ { INDEX_op_or_i64, { "r", "rI", "rI" } },
+ { INDEX_op_orc_i64, { "r", "rZ", "rZ" } },
+ { INDEX_op_xor_i64, { "r", "rI", "rI" } },
+
+ { INDEX_op_mul_i64, { "r", "rZ", "rZ" } },
+
+ { INDEX_op_sar_i64, { "r", "rZ", "ri" } },
+ { INDEX_op_shl_i64, { "r", "rZ", "ri" } },
+ { INDEX_op_shr_i64, { "r", "rZ", "ri" } },
+ { INDEX_op_rotl_i64, { "r", "rZ", "ri" } },
+ { INDEX_op_rotr_i64, { "r", "rZ", "ri" } },
+
+ { INDEX_op_ext8s_i64, { "r", "rZ"} },
+ { INDEX_op_ext8u_i64, { "r", "rZ"} },
+ { INDEX_op_ext16s_i64, { "r", "rZ"} },
+ { INDEX_op_ext16u_i64, { "r", "rZ"} },
+ { INDEX_op_ext32s_i64, { "r", "rZ"} },
+ { INDEX_op_ext32u_i64, { "r", "rZ"} },
+
+ { INDEX_op_bswap16_i64, { "r", "rZ" } },
+ { INDEX_op_bswap32_i64, { "r", "rZ" } },
+ { INDEX_op_bswap64_i64, { "r", "rZ" } },
+
+ { INDEX_op_brcond_i64, { "rI", "rI" } },
+ { INDEX_op_setcond_i64, { "r", "rZ", "rZ" } },
+
+ { INDEX_op_qemu_ld8u, { "r", "r" } },
+ { INDEX_op_qemu_ld8s, { "r", "r" } },
+ { INDEX_op_qemu_ld16u, { "r", "r" } },
+ { INDEX_op_qemu_ld16s, { "r", "r" } },
+ { INDEX_op_qemu_ld32, { "r", "r" } },
+ { INDEX_op_qemu_ld32u, { "r", "r" } },
+ { INDEX_op_qemu_ld32s, { "r", "r" } },
+ { INDEX_op_qemu_ld64, { "r", "r" } },
+
+ { INDEX_op_qemu_st8, { "SZ", "r" } },
+ { INDEX_op_qemu_st16, { "SZ", "r" } },
+ { INDEX_op_qemu_st32, { "SZ", "r" } },
+ { INDEX_op_qemu_st64, { "SZ", "r" } },
+
+ { -1 },
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int frame_size;
+
+ /* reserve some stack space */
+ frame_size = TCG_STATIC_CALL_ARGS_SIZE;
+ frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+ ~(TCG_TARGET_STACK_ALIGN - 1);
+
+ /* First emit adhoc function descriptor */
+ *(uint64_t *)(s->code_ptr) = (uint64_t)s->code_ptr + 16; /* entry point */
+ s->code_ptr += 16; /* skip GP */
+
+ /* prologue */
+ tcg_out_bundle(s, mII,
+ tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
+ TCG_REG_R33, 32, 24, 0),
+ tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+ TCG_REG_B6, TCG_REG_R32, 0),
+ tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+ TCG_REG_R32, TCG_REG_B0));
+
+ /* ??? If GUEST_BASE < 0x200000, we could load the register via
+ an ADDL in the M slot of the next bundle. */
+ if (GUEST_BASE != 0) {
+ tcg_out_bundle(s, mlx,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_l2 (GUEST_BASE),
+ tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2,
+ TCG_GUEST_BASE_REG, GUEST_BASE));
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+ }
+
+ tcg_out_bundle(s, miB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ TCG_REG_R12, -frame_size, TCG_REG_R12),
+ tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
+
+ /* epilogue */
+ tb_ret_addr = s->code_ptr;
+ tcg_out_bundle(s, miI,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
+ TCG_REG_B0, TCG_REG_R32, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ TCG_REG_R12, frame_size, TCG_REG_R12));
+ tcg_out_bundle(s, miB,
+ tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
+ tcg_opc_i26(TCG_REG_P0, OPC_MOV_I_I26,
+ TCG_REG_PFS, TCG_REG_R33),
+ tcg_opc_b4 (TCG_REG_P0, OPC_BR_RET_SPTK_MANY_B4,
+ TCG_REG_B0));
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32],
+ 0xffffffffffffffffull);
+ tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I64],
+ 0xffffffffffffffffull);
+
+ tcg_regset_clear(tcg_target_call_clobber_regs);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R15);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R16);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R17);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R18);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R19);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R20);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R21);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R22);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R23);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R24);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R25);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R26);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R27);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R28);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R29);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R30);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R31);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R56);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R57);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R58);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R59);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R60);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R61);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R62);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R63);
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* zero register */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* global pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); /* internal use */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* internal use */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12); /* stack pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R32); /* return address */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R33); /* PFS */
+
+ /* The following 3 are not in use, are call-saved, but *not* saved
+ by the prologue. Therefore we cannot use them without modifying
+ the prologue. There doesn't seem to be any good reason to use
+ these as opposed to the windowed registers. */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R4);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R5);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6);
+
+ tcg_add_target_add_op_defs(ia64_op_defs);
+}
diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h
new file mode 100644
index 0000000..e56e88f
--- /dev/null
+++ b/tcg/ia64/tcg-target.h
@@ -0,0 +1,156 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009-2010 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - 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_IA64 1
+
+#define TCG_TARGET_REG_BITS 64
+
+/* We only map the first 64 registers */
+#define TCG_TARGET_NB_REGS 64
+enum {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31,
+ TCG_REG_R32,
+ TCG_REG_R33,
+ TCG_REG_R34,
+ TCG_REG_R35,
+ TCG_REG_R36,
+ TCG_REG_R37,
+ TCG_REG_R38,
+ TCG_REG_R39,
+ TCG_REG_R40,
+ TCG_REG_R41,
+ TCG_REG_R42,
+ TCG_REG_R43,
+ TCG_REG_R44,
+ TCG_REG_R45,
+ TCG_REG_R46,
+ TCG_REG_R47,
+ TCG_REG_R48,
+ TCG_REG_R49,
+ TCG_REG_R50,
+ TCG_REG_R51,
+ TCG_REG_R52,
+ TCG_REG_R53,
+ TCG_REG_R54,
+ TCG_REG_R55,
+ TCG_REG_R56,
+ TCG_REG_R57,
+ TCG_REG_R58,
+ TCG_REG_R59,
+ TCG_REG_R60,
+ TCG_REG_R61,
+ TCG_REG_R62,
+ TCG_REG_R63,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_S22 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R12
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 16
+
+/* optional instructions */
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_eqv_i32
+#define TCG_TARGET_HAS_eqv_i64
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_nand_i32
+#define TCG_TARGET_HAS_nand_i64
+#define TCG_TARGET_HAS_nor_i32
+#define TCG_TARGET_HAS_nor_i64
+#define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_orc_i64
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_rot_i64
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32 /* sub r1, r0, r3 */
+#undef TCG_TARGET_HAS_neg_i64 /* sub r1, r0, r3 */
+#undef TCG_TARGET_HAS_not_i32 /* xor r1, -1, r3 */
+#undef TCG_TARGET_HAS_not_i64 /* xor r1, -1, r3 */
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_R7
+
+/* Guest base is supported */
+#define TCG_TARGET_HAS_GUEST_BASE
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ start = start & ~(32UL - 1UL);
+ stop = (stop + (32UL - 1UL)) & ~(32UL - 1UL);
+
+ for (; start < stop; start += 32UL) {
+ asm volatile ("fc.i %0" :: "r" (start));
+ }
+ asm volatile (";;sync.i;;srlz.i;;");
+}
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
new file mode 100644
index 0000000..e04b0dc
--- /dev/null
+++ b/tcg/mips/tcg-target.c
@@ -0,0 +1,1533 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - 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.
+ */
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+# define TCG_NEED_BSWAP 0
+#else
+# define TCG_NEED_BSWAP 1
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "zero",
+ "at",
+ "v0",
+ "v1",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "t0",
+ "t1",
+ "t2",
+ "t3",
+ "t4",
+ "t5",
+ "t6",
+ "t7",
+ "s0",
+ "s1",
+ "s2",
+ "s3",
+ "s4",
+ "s5",
+ "s6",
+ "s7",
+ "t8",
+ "t9",
+ "k0",
+ "k1",
+ "gp",
+ "sp",
+ "fp",
+ "ra",
+};
+#endif
+
+/* check if we really need so many registers :P */
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_S0,
+ TCG_REG_S1,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_T1,
+ TCG_REG_T2,
+ TCG_REG_T3,
+ TCG_REG_T4,
+ TCG_REG_T5,
+ TCG_REG_T6,
+ TCG_REG_T7,
+ TCG_REG_T8,
+ TCG_REG_T9,
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3,
+ TCG_REG_V0,
+ TCG_REG_V1
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_V0,
+ TCG_REG_V1
+};
+
+static uint8_t *tb_ret_addr;
+
+static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target)
+{
+ return target & 0xffff;
+}
+
+static inline void reloc_lo16 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+ | reloc_lo16_val(pc, target);
+}
+
+static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target)
+{
+ return (target >> 16) & 0xffff;
+}
+
+static inline void reloc_hi16 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+ | reloc_hi16_val(pc, target);
+}
+
+static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target)
+{
+ int32_t disp;
+
+ disp = target - (tcg_target_long) pc - 4;
+ if (disp != (disp << 14) >> 14) {
+ tcg_abort ();
+ }
+
+ return (disp >> 2) & 0xffff;
+}
+
+static inline void reloc_pc16 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+ | reloc_pc16_val(pc, target);
+}
+
+static inline uint32_t reloc_26_val (void *pc, tcg_target_long target)
+{
+ if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) {
+ tcg_abort ();
+ }
+
+ return (target >> 2) & 0x3ffffff;
+}
+
+static inline void reloc_pc26 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff)
+ | reloc_26_val(pc, target);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch(type) {
+ case R_MIPS_LO16:
+ reloc_lo16(code_ptr, value);
+ break;
+ case R_MIPS_HI16:
+ reloc_hi16(code_ptr, value);
+ break;
+ case R_MIPS_PC16:
+ reloc_pc16(code_ptr, value);
+ break;
+ case R_MIPS_26:
+ reloc_pc26(code_ptr, value);
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch(ct_str[0]) {
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffff);
+ break;
+ case 'C':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_clear(ct->u.regs);
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_T9);
+ break;
+ case 'L': /* qemu_ld output arg constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0);
+ break;
+ case 'l': /* qemu_ld input arg constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffff);
+#if defined(CONFIG_SOFTMMU)
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+#endif
+ break;
+ case 'S': /* qemu_st constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set(ct->u.regs, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+#if defined(CONFIG_SOFTMMU)
+# if TARGET_LONG_BITS == 64
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
+# endif
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+#endif
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_U16;
+ break;
+ case 'J':
+ ct->ct |= TCG_CT_CONST_S16;
+ break;
+ case 'Z':
+ /* We are cheating a bit here, using the fact that the register
+ ZERO is also the register number 0. Hence there is no need
+ to check for const_args in each instruction. */
+ ct->ct |= TCG_CT_CONST_ZERO;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+ return 1;
+ else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val)
+ return 1;
+ else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val)
+ return 1;
+ else
+ return 0;
+}
+
+/* instruction opcodes */
+enum {
+ OPC_BEQ = 0x04 << 26,
+ OPC_BNE = 0x05 << 26,
+ OPC_ADDIU = 0x09 << 26,
+ OPC_SLTI = 0x0A << 26,
+ OPC_SLTIU = 0x0B << 26,
+ OPC_ANDI = 0x0C << 26,
+ OPC_ORI = 0x0D << 26,
+ OPC_XORI = 0x0E << 26,
+ OPC_LUI = 0x0F << 26,
+ OPC_LB = 0x20 << 26,
+ OPC_LH = 0x21 << 26,
+ OPC_LW = 0x23 << 26,
+ OPC_LBU = 0x24 << 26,
+ OPC_LHU = 0x25 << 26,
+ OPC_LWU = 0x27 << 26,
+ OPC_SB = 0x28 << 26,
+ OPC_SH = 0x29 << 26,
+ OPC_SW = 0x2B << 26,
+
+ OPC_SPECIAL = 0x00 << 26,
+ OPC_SLL = OPC_SPECIAL | 0x00,
+ OPC_SRL = OPC_SPECIAL | 0x02,
+ OPC_SRA = OPC_SPECIAL | 0x03,
+ OPC_SLLV = OPC_SPECIAL | 0x04,
+ OPC_SRLV = OPC_SPECIAL | 0x06,
+ OPC_SRAV = OPC_SPECIAL | 0x07,
+ OPC_JR = OPC_SPECIAL | 0x08,
+ OPC_JALR = OPC_SPECIAL | 0x09,
+ OPC_MFHI = OPC_SPECIAL | 0x10,
+ OPC_MFLO = OPC_SPECIAL | 0x12,
+ OPC_MULT = OPC_SPECIAL | 0x18,
+ OPC_MULTU = OPC_SPECIAL | 0x19,
+ OPC_DIV = OPC_SPECIAL | 0x1A,
+ OPC_DIVU = OPC_SPECIAL | 0x1B,
+ OPC_ADDU = OPC_SPECIAL | 0x21,
+ OPC_SUBU = OPC_SPECIAL | 0x23,
+ OPC_AND = OPC_SPECIAL | 0x24,
+ OPC_OR = OPC_SPECIAL | 0x25,
+ OPC_XOR = OPC_SPECIAL | 0x26,
+ OPC_NOR = OPC_SPECIAL | 0x27,
+ OPC_SLT = OPC_SPECIAL | 0x2A,
+ OPC_SLTU = OPC_SPECIAL | 0x2B,
+
+ OPC_SPECIAL3 = 0x1f << 26,
+ OPC_SEB = OPC_SPECIAL3 | 0x420,
+ OPC_SEH = OPC_SPECIAL3 | 0x620,
+};
+
+/*
+ * Type reg
+ */
+static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt)
+{
+ int32_t inst;
+
+ inst = opc;
+ inst |= (rs & 0x1F) << 21;
+ inst |= (rt & 0x1F) << 16;
+ inst |= (rd & 0x1F) << 11;
+ tcg_out32(s, inst);
+}
+
+/*
+ * Type immediate
+ */
+static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm)
+{
+ int32_t inst;
+
+ inst = opc;
+ inst |= (rs & 0x1F) << 21;
+ inst |= (rt & 0x1F) << 16;
+ inst |= (imm & 0xffff);
+ tcg_out32(s, inst);
+}
+
+/*
+ * Type branch
+ */
+static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
+{
+ /* We pay attention here to not modify the branch target by reading
+ the existing value and using it again. This ensure that caches and
+ memory are kept coherent during retranslation. */
+ uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr);
+
+ tcg_out_opc_imm(s, opc, rt, rs, offset);
+}
+
+/*
+ * Type sa
+ */
+static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa)
+{
+ int32_t inst;
+
+ inst = opc;
+ inst |= (rt & 0x1F) << 16;
+ inst |= (rd & 0x1F) << 11;
+ inst |= (sa & 0x1F) << 6;
+ tcg_out32(s, inst);
+
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+ tcg_out32(s, 0);
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+ int reg, int32_t arg)
+{
+ if (arg == (int16_t)arg) {
+ tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg);
+ } else if (arg == (uint16_t)arg) {
+ tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg);
+ } else {
+ tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16);
+ tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
+ }
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg)
+{
+ /* ret and arg can't be register at */
+ if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+ tcg_abort();
+ }
+
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff);
+
+ tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
+ tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg)
+{
+ /* ret and arg can't be register at */
+ if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+ tcg_abort();
+ }
+
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff);
+
+ tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+ tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg)
+{
+ /* ret and arg must be different and can't be register at */
+ if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
+ tcg_abort();
+ }
+
+ tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
+ tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg)
+{
+#ifdef _MIPS_ARCH_MIPS32R2
+ tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg);
+#else
+ tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+ tcg_out_opc_sa(s, OPC_SRA, ret, ret, 24);
+#endif
+}
+
+static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg)
+{
+#ifdef _MIPS_ARCH_MIPS32R2
+ tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg);
+#else
+ tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16);
+ tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
+#endif
+}
+
+static inline void tcg_out_ldst(TCGContext *s, int opc, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ if (arg2 == (int16_t) arg2) {
+ tcg_out_opc_imm(s, opc, arg, arg1, arg2);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1);
+ tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0);
+ }
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val == (int16_t)val) {
+ tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val);
+ tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT);
+ }
+}
+
+static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
+ int arg2, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_opc_br(s, OPC_BEQ, arg1, arg2);
+ break;
+ case TCG_COND_NE:
+ tcg_out_opc_br(s, OPC_BNE, arg1, arg2);
+ break;
+ case TCG_COND_LT:
+ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_LTU:
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_GE:
+ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_GEU:
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_LE:
+ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_LEU:
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_GT:
+ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ case TCG_COND_GTU:
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+ break;
+ default:
+ tcg_abort();
+ break;
+ }
+ if (l->has_value) {
+ reloc_pc16(s->code_ptr - 4, l->u.value);
+ } else {
+ tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0);
+ }
+ tcg_out_nop(s);
+}
+
+/* XXX: we implement it at the target level to avoid having to
+ handle cross basic blocks temporaries */
+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, int arg1,
+ int arg2, int arg3, int arg4, int label_index)
+{
+ void *label_ptr;
+
+ switch(cond) {
+ case TCG_COND_NE:
+ tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index);
+ tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index);
+ return;
+ case TCG_COND_EQ:
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LE:
+ tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index);
+ break;
+ case TCG_COND_GT:
+ case TCG_COND_GE:
+ tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index);
+ break;
+ case TCG_COND_LTU:
+ case TCG_COND_LEU:
+ tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index);
+ break;
+ case TCG_COND_GTU:
+ case TCG_COND_GEU:
+ tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ label_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BNE, arg2, arg4);
+ tcg_out_nop(s);
+
+ switch(cond) {
+ case TCG_COND_EQ:
+ tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index);
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index);
+ break;
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index);
+ break;
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index);
+ break;
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr);
+}
+
+static void tcg_out_setcond(TCGContext *s, TCGCond cond, int ret,
+ int arg1, int arg2)
+{
+ switch (cond) {
+ case TCG_COND_EQ:
+ if (arg1 == 0) {
+ tcg_out_opc_imm(s, OPC_SLTIU, ret, arg2, 1);
+ } else if (arg2 == 0) {
+ tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1);
+ } else {
+ tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1);
+ }
+ break;
+ case TCG_COND_NE:
+ if (arg1 == 0) {
+ tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg2);
+ } else if (arg2 == 0) {
+ tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1);
+ } else {
+ tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+ tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret);
+ }
+ break;
+ case TCG_COND_LT:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+ break;
+ case TCG_COND_LTU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+ break;
+ case TCG_COND_GE:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_GEU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_LE:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_LEU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_GT:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+ break;
+ case TCG_COND_GTU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+ break;
+ default:
+ tcg_abort();
+ break;
+ }
+}
+
+/* XXX: we implement it at the target level to avoid having to
+ handle cross basic blocks temporaries */
+static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret,
+ int arg1, int arg2, int arg3, int arg4)
+{
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_AT, arg2, arg4);
+ tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg1, arg3);
+ tcg_out_opc_reg(s, OPC_AND, ret, TCG_REG_AT, TCG_REG_T0);
+ return;
+ case TCG_COND_NE:
+ tcg_out_setcond(s, TCG_COND_NE, TCG_REG_AT, arg2, arg4);
+ tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, arg1, arg3);
+ tcg_out_opc_reg(s, OPC_OR, ret, TCG_REG_AT, TCG_REG_T0);
+ return;
+ case TCG_COND_LT:
+ case TCG_COND_LE:
+ tcg_out_setcond(s, TCG_COND_LT, TCG_REG_AT, arg2, arg4);
+ break;
+ case TCG_COND_GT:
+ case TCG_COND_GE:
+ tcg_out_setcond(s, TCG_COND_GT, TCG_REG_AT, arg2, arg4);
+ break;
+ case TCG_COND_LTU:
+ case TCG_COND_LEU:
+ tcg_out_setcond(s, TCG_COND_LTU, TCG_REG_AT, arg2, arg4);
+ break;
+ case TCG_COND_GTU:
+ case TCG_COND_GEU:
+ tcg_out_setcond(s, TCG_COND_GTU, TCG_REG_AT, arg2, arg4);
+ break;
+ default:
+ tcg_abort();
+ break;
+ }
+
+ tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg2, arg4);
+
+ switch(cond) {
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ tcg_out_setcond(s, TCG_COND_LTU, ret, arg1, arg3);
+ break;
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ tcg_out_setcond(s, TCG_COND_LEU, ret, arg1, arg3);
+ break;
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ tcg_out_setcond(s, TCG_COND_GTU, ret, arg1, arg3);
+ break;
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ tcg_out_setcond(s, TCG_COND_GEU, ret, arg1, arg3);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ tcg_out_opc_reg(s, OPC_AND, ret, ret, TCG_REG_T0);
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+#endif
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int addr_regl, addr_reg1, addr_meml;
+ int data_regl, data_regh, data_reg1, data_reg2;
+ int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+ void *label1_ptr, *label2_ptr;
+ int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+ uint8_t *label3_ptr;
+# endif
+ int addr_regh, addr_reg2, addr_memh;
+#endif
+ data_regl = *args++;
+ if (opc == 3)
+ data_regh = *args++;
+ else
+ data_regh = 0;
+ addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+ addr_regh = *args++;
+#endif
+ mem_index = *args;
+ s_bits = opc & 3;
+
+ if (opc == 3) {
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ data_reg1 = data_regh;
+ data_reg2 = data_regl;
+#else
+ data_reg1 = data_regl;
+ data_reg2 = data_regh;
+#endif
+ } else {
+ data_reg1 = data_regl;
+ data_reg2 = 0;
+ }
+#if TARGET_LONG_BITS == 64
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ addr_reg1 = addr_regh;
+ addr_reg2 = addr_regl;
+ addr_memh = 0;
+ addr_meml = 4;
+# else
+ addr_reg1 = addr_regl;
+ addr_reg2 = addr_regh;
+ addr_memh = 4;
+ addr_meml = 0;
+# endif
+#else
+ addr_reg1 = addr_regl;
+ addr_meml = 0;
+#endif
+
+#if defined(CONFIG_SOFTMMU)
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+ tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+ label3_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
+ tcg_out_nop(s);
+
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh);
+
+ label1_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
+ tcg_out_nop(s);
+
+ reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+ label1_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
+ tcg_out_nop(s);
+# endif
+
+ /* slow path */
+ sp_args = TCG_REG_A0;
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+# endif
+ tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
+ tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+ tcg_out_nop(s);
+
+ switch(opc) {
+ case 0:
+ tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff);
+ break;
+ case 0 | 4:
+ tcg_out_ext8s(s, data_reg1, TCG_REG_V0);
+ break;
+ case 1:
+ tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff);
+ break;
+ case 1 | 4:
+ tcg_out_ext16s(s, data_reg1, TCG_REG_V0);
+ break;
+ case 2:
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
+ break;
+ case 3:
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_V1);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
+ break;
+ default:
+ tcg_abort();
+ }
+
+ label2_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
+ tcg_out_nop(s);
+
+ /* label1: fast path */
+ reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addend));
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl);
+#else
+ if (GUEST_BASE == (int16_t)GUEST_BASE) {
+ tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_V0, addr_regl, GUEST_BASE);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, GUEST_BASE);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
+ }
+#endif
+
+ switch(opc) {
+ case 0:
+ tcg_out_opc_imm(s, OPC_LBU, data_reg1, TCG_REG_V0, 0);
+ break;
+ case 0 | 4:
+ tcg_out_opc_imm(s, OPC_LB, data_reg1, TCG_REG_V0, 0);
+ break;
+ case 1:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
+ tcg_out_bswap16(s, data_reg1, TCG_REG_T0);
+ } else {
+ tcg_out_opc_imm(s, OPC_LHU, data_reg1, TCG_REG_V0, 0);
+ }
+ break;
+ case 1 | 4:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
+ tcg_out_bswap16s(s, data_reg1, TCG_REG_T0);
+ } else {
+ tcg_out_opc_imm(s, OPC_LH, data_reg1, TCG_REG_V0, 0);
+ }
+ break;
+ case 2:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
+ tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+ } else {
+ tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
+ }
+ break;
+ case 3:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 4);
+ tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
+ tcg_out_bswap32(s, data_reg2, TCG_REG_T0);
+ } else {
+ tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
+ tcg_out_opc_imm(s, OPC_LW, data_reg2, TCG_REG_V0, 4);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int addr_regl, addr_reg1, addr_meml;
+ int data_regl, data_regh, data_reg1, data_reg2;
+ int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+ uint8_t *label1_ptr, *label2_ptr;
+ int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+ uint8_t *label3_ptr;
+# endif
+ int addr_regh, addr_reg2, addr_memh;
+#endif
+
+ data_regl = *args++;
+ if (opc == 3) {
+ data_regh = *args++;
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ data_reg1 = data_regh;
+ data_reg2 = data_regl;
+#else
+ data_reg1 = data_regl;
+ data_reg2 = data_regh;
+#endif
+ } else {
+ data_reg1 = data_regl;
+ data_reg2 = 0;
+ data_regh = 0;
+ }
+ addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+ addr_regh = *args++;
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ addr_reg1 = addr_regh;
+ addr_reg2 = addr_regl;
+ addr_memh = 0;
+ addr_meml = 4;
+# else
+ addr_reg1 = addr_regl;
+ addr_reg2 = addr_regh;
+ addr_memh = 4;
+ addr_meml = 0;
+# endif
+#else
+ addr_reg1 = addr_regl;
+ addr_meml = 0;
+#endif
+ mem_index = *args;
+ s_bits = opc;
+
+#if defined(CONFIG_SOFTMMU)
+ tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+ tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+ label3_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
+ tcg_out_nop(s);
+
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh);
+
+ label1_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
+ tcg_out_nop(s);
+
+ reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+ label1_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
+ tcg_out_nop(s);
+# endif
+
+ /* slow path */
+ sp_args = TCG_REG_A0;
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+# endif
+ switch(opc) {
+ case 0:
+ tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+ break;
+ case 1:
+ tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+ break;
+ case 2:
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ break;
+ case 3:
+ sp_args = (sp_args + 1) & ~1;
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
+ break;
+ default:
+ tcg_abort();
+ }
+ if (sp_args > TCG_REG_A3) {
+ /* Push mem_index on the stack */
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
+ tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
+ }
+
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
+ tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+ tcg_out_nop(s);
+
+ label2_ptr = s->code_ptr;
+ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
+ tcg_out_nop(s);
+
+ /* label1: fast path */
+ reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
+ offsetof(CPUState, tlb_table[mem_index][0].addend));
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+#else
+ if (GUEST_BASE == (int16_t)GUEST_BASE) {
+ tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_A0, addr_regl, GUEST_BASE);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, GUEST_BASE);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+ }
+
+#endif
+
+ switch(opc) {
+ case 0:
+ tcg_out_opc_imm(s, OPC_SB, data_reg1, TCG_REG_A0, 0);
+ break;
+ case 1:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_bswap16(s, TCG_REG_T0, data_reg1);
+ tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, TCG_REG_A0, 0);
+ } else {
+ tcg_out_opc_imm(s, OPC_SH, data_reg1, TCG_REG_A0, 0);
+ }
+ break;
+ case 2:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+ tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
+ } else {
+ tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
+ }
+ break;
+ case 3:
+ if (TCG_NEED_BSWAP) {
+ tcg_out_bswap32(s, TCG_REG_T0, data_reg2);
+ tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
+ tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+ tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 4);
+ } else {
+ tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
+ tcg_out_opc_imm(s, OPC_SW, data_reg2, TCG_REG_A0, 4);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ switch(opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr);
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+ tcg_out_nop(s);
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+ tcg_abort();
+ } else {
+ /* indirect jump method */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0]));
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0);
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+ }
+ tcg_out_nop(s);
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_call:
+ tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0);
+ tcg_out_nop(s);
+ break;
+ case INDEX_op_jmp:
+ tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0);
+ tcg_out_nop(s);
+ break;
+ case INDEX_op_br:
+ tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]);
+ break;
+
+ case INDEX_op_mov_i32:
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+
+ case INDEX_op_ld8u_i32:
+ tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld8s_i32:
+ tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld16u_i32:
+ tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld16s_i32:
+ tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld_i32:
+ tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st8_i32:
+ tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st16_i32:
+ tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i32:
+ tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_add_i32:
+ if (const_args[2]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]);
+ }
+ break;
+ case INDEX_op_add2_i32:
+ if (const_args[4]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]);
+ }
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]);
+ if (const_args[5]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]);
+ }
+ tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0);
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
+ break;
+ case INDEX_op_sub_i32:
+ if (const_args[2]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]);
+ }
+ break;
+ case INDEX_op_sub2_i32:
+ if (const_args[4]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]);
+ }
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT);
+ if (const_args[5]) {
+ tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]);
+ }
+ tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0);
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
+ break;
+ case INDEX_op_mul_i32:
+ tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
+ tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]);
+ tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+ tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0);
+ break;
+ case INDEX_op_div_i32:
+ tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+ tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+ break;
+ case INDEX_op_divu_i32:
+ tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+ tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+ break;
+ case INDEX_op_rem_i32:
+ tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+ tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+ break;
+ case INDEX_op_remu_i32:
+ tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+ tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+ break;
+
+ case INDEX_op_and_i32:
+ if (const_args[2]) {
+ tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]);
+ }
+ break;
+ case INDEX_op_or_i32:
+ if (const_args[2]) {
+ tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]);
+ }
+ break;
+ case INDEX_op_nor_i32:
+ tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_not_i32:
+ tcg_out_opc_reg(s, OPC_NOR, args[0], TCG_REG_ZERO, args[1]);
+ break;
+ case INDEX_op_xor_i32:
+ if (const_args[2]) {
+ tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]);
+ }
+ break;
+
+ case INDEX_op_sar_i32:
+ if (const_args[2]) {
+ tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]);
+ }
+ break;
+ case INDEX_op_shl_i32:
+ if (const_args[2]) {
+ tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]);
+ }
+ break;
+ case INDEX_op_shr_i32:
+ if (const_args[2]) {
+ tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]);
+ }
+ break;
+
+ case INDEX_op_ext8s_i32:
+ tcg_out_ext8s(s, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i32:
+ tcg_out_ext16s(s, args[0], args[1]);
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond(s, args[2], args[0], args[1], args[3]);
+ break;
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
+ break;
+
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond(s, args[3], args[0], args[1], args[2]);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args[5], args[0], args[1], args[2], args[3], args[4]);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ default:
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef mips_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "C" } },
+ { INDEX_op_jmp, { "r" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "rZ", "r" } },
+ { INDEX_op_st16_i32, { "rZ", "r" } },
+ { INDEX_op_st_i32, { "rZ", "r" } },
+
+ { INDEX_op_add_i32, { "r", "rZ", "rJZ" } },
+ { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } },
+ { INDEX_op_div_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_divu_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_rem_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_remu_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } },
+
+ { INDEX_op_and_i32, { "r", "rZ", "rIZ" } },
+ { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_not_i32, { "r", "rZ" } },
+ { INDEX_op_or_i32, { "r", "rZ", "rIZ" } },
+ { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } },
+
+ { INDEX_op_shl_i32, { "r", "rZ", "riZ" } },
+ { INDEX_op_shr_i32, { "r", "rZ", "riZ" } },
+ { INDEX_op_sar_i32, { "r", "rZ", "riZ" } },
+
+ { INDEX_op_ext8s_i32, { "r", "rZ" } },
+ { INDEX_op_ext16s_i32, { "r", "rZ" } },
+
+ { INDEX_op_brcond_i32, { "rZ", "rZ" } },
+ { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
+ { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
+
+ { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+ { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+ { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
+
+#if TARGET_LONG_BITS == 32
+ { INDEX_op_qemu_ld8u, { "L", "lZ" } },
+ { INDEX_op_qemu_ld8s, { "L", "lZ" } },
+ { INDEX_op_qemu_ld16u, { "L", "lZ" } },
+ { INDEX_op_qemu_ld16s, { "L", "lZ" } },
+ { INDEX_op_qemu_ld32, { "L", "lZ" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "lZ" } },
+
+ { INDEX_op_qemu_st8, { "SZ", "SZ" } },
+ { INDEX_op_qemu_st16, { "SZ", "SZ" } },
+ { INDEX_op_qemu_st32, { "SZ", "SZ" } },
+ { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } },
+#else
+ { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } },
+ { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } },
+ { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } },
+ { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } },
+ { INDEX_op_qemu_ld32, { "L", "lZ", "lZ" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } },
+
+ { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } },
+ { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } },
+ { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } },
+ { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } },
+#endif
+ { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+#if 0 /* used for the global env (TCG_AREG0), so no need to save */
+ TCG_REG_S0,
+#endif
+ TCG_REG_S1,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_GP,
+ TCG_REG_FP,
+ TCG_REG_RA, /* should be last for ABI compliance */
+};
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int i, frame_size;
+
+ /* reserve some stack space */
+ frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4
+ + TCG_STATIC_CALL_ARGS_SIZE;
+ frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+ ~(TCG_TARGET_STACK_ALIGN - 1);
+
+ /* TB prologue */
+ tcg_out_addi(s, TCG_REG_SP, -frame_size);
+ for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+ tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+ }
+
+ /* Call generated code */
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0);
+ tcg_out_nop(s);
+ tb_ret_addr = s->code_ptr;
+
+ /* TB epilogue */
+ for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+ tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+ }
+
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0);
+ tcg_out_addi(s, TCG_REG_SP, frame_size);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
+ tcg_regset_set(tcg_target_call_clobber_regs,
+ (1 << TCG_REG_V0) |
+ (1 << TCG_REG_V1) |
+ (1 << TCG_REG_A0) |
+ (1 << TCG_REG_A1) |
+ (1 << TCG_REG_A2) |
+ (1 << TCG_REG_A3) |
+ (1 << TCG_REG_T1) |
+ (1 << TCG_REG_T2) |
+ (1 << TCG_REG_T3) |
+ (1 << TCG_REG_T4) |
+ (1 << TCG_REG_T5) |
+ (1 << TCG_REG_T6) |
+ (1 << TCG_REG_T7) |
+ (1 << TCG_REG_T8) |
+ (1 << TCG_REG_T9));
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0); /* kernel use only */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1); /* kernel use only */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT); /* internal use */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0); /* internal use */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
+
+ tcg_add_target_add_op_defs(mips_op_defs);
+}
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
new file mode 100644
index 0000000..0028bfa
--- /dev/null
+++ b/tcg/mips/tcg-target.h
@@ -0,0 +1,110 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - 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_MIPS 1
+
+#define TCG_TARGET_REG_BITS 32
+#ifdef __MIPSEB__
+# define TCG_TARGET_WORDS_BIGENDIAN
+#endif
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_ZERO = 0,
+ TCG_REG_AT,
+ TCG_REG_V0,
+ TCG_REG_V1,
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3,
+ TCG_REG_T0,
+ TCG_REG_T1,
+ TCG_REG_T2,
+ TCG_REG_T3,
+ TCG_REG_T4,
+ TCG_REG_T5,
+ TCG_REG_T6,
+ TCG_REG_T7,
+ TCG_REG_S0,
+ TCG_REG_S1,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_T8,
+ TCG_REG_T9,
+ TCG_REG_K0,
+ TCG_REG_K1,
+ TCG_REG_GP,
+ TCG_REG_SP,
+ TCG_REG_FP,
+ TCG_REG_RA,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_U16 0x200
+#define TCG_CT_CONST_S16 0x400
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 8
+#define TCG_TARGET_CALL_STACK_OFFSET 16
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_nor_i32
+#undef TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#undef TCG_TARGET_HAS_bswap32_i32
+#undef TCG_TARGET_HAS_bswap16_i32
+#undef TCG_TARGET_HAS_andc_i32
+#undef TCG_TARGET_HAS_orc_i32
+#undef TCG_TARGET_HAS_eqv_i32
+#undef TCG_TARGET_HAS_nand_i32
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32 /* sub rd, zero, rt */
+#undef TCG_TARGET_HAS_ext8u_i32 /* andi rt, rs, 0xff */
+#undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_S0
+
+/* guest base is supported */
+#define TCG_TARGET_HAS_GUEST_BASE
+
+#include <sys/cachectl.h>
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ cacheflush ((void *)start, stop-start, ICACHE);
+}
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
new file mode 100644
index 0000000..7970268
--- /dev/null
+++ b/tcg/ppc/tcg-target.c
@@ -0,0 +1,1922 @@
+/*
+ * 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.
+ */
+
+static uint8_t *tb_ret_addr;
+
+#ifdef _CALL_DARWIN
+#define LINKAGE_AREA_SIZE 24
+#define LR_OFFSET 8
+#elif defined _CALL_AIX
+#define LINKAGE_AREA_SIZE 52
+#define LR_OFFSET 8
+#else
+#define LINKAGE_AREA_SIZE 8
+#define LR_OFFSET 4
+#endif
+
+#define FAST_PATH
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG 30
+#else
+#define TCG_GUEST_BASE_REG 0
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "r0",
+ "r1",
+ "r2",
+ "r3",
+ "r4",
+ "r5",
+ "r6",
+ "r7",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "r16",
+ "r17",
+ "r18",
+ "r19",
+ "r20",
+ "r21",
+ "r22",
+ "r23",
+ "r24",
+ "r25",
+ "r26",
+ "r27",
+ "r28",
+ "r29",
+ "r30",
+ "r31"
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31,
+#ifdef _CALL_DARWIN
+ TCG_REG_R2,
+#endif
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+#ifndef _CALL_DARWIN
+ TCG_REG_R11,
+#endif
+ TCG_REG_R12,
+#ifndef _CALL_SYSV
+ TCG_REG_R13,
+#endif
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_R3,
+ TCG_REG_R4
+};
+
+static const int tcg_target_callee_save_regs[] = {
+#ifdef _CALL_DARWIN
+ TCG_REG_R11,
+ TCG_REG_R13,
+#endif
+#ifdef _CALL_AIX
+ TCG_REG_R13,
+#endif
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ /* TCG_REG_R27, */ /* currently used for the global env, so no
+ need to save */
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31
+};
+
+static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) pc;
+ if ((disp << 6) >> 6 != disp)
+ tcg_abort ();
+
+ return disp & 0x3fffffc;
+}
+
+static void reloc_pc24 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc)
+ | reloc_pc24_val (pc, target);
+}
+
+static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) pc;
+ if (disp != (int16_t) disp)
+ tcg_abort ();
+
+ return disp & 0xfffc;
+}
+
+static void reloc_pc14 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc)
+ | reloc_pc14_val (pc, target);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch (type) {
+ case R_PPC_REL14:
+ reloc_pc14 (code_ptr, value);
+ break;
+ case R_PPC_REL24:
+ reloc_pc24 (code_ptr, value);
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return ARRAY_SIZE (tcg_target_call_iarg_regs);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch (ct_str[0]) {
+ case 'A': case 'B': case 'C': case 'D':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A');
+ break;
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ break;
+#ifdef CONFIG_SOFTMMU
+ case 'L': /* qemu_ld constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+ break;
+ case 'K': /* qemu_st[8..32] constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
+#if TARGET_LONG_BITS == 64
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
+#endif
+ break;
+ case 'M': /* qemu_st64 constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7);
+ break;
+#else
+ case 'L':
+ case 'K':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ break;
+ case 'M':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+ break;
+#endif
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ return 0;
+}
+
+#define OPCD(opc) ((opc)<<26)
+#define XO31(opc) (OPCD(31)|((opc)<<1))
+#define XO19(opc) (OPCD(19)|((opc)<<1))
+
+#define B OPCD(18)
+#define BC OPCD(16)
+#define LBZ OPCD(34)
+#define LHZ OPCD(40)
+#define LHA OPCD(42)
+#define LWZ OPCD(32)
+#define STB OPCD(38)
+#define STH OPCD(44)
+#define STW OPCD(36)
+
+#define ADDIC OPCD(12)
+#define ADDI OPCD(14)
+#define ADDIS OPCD(15)
+#define ORI OPCD(24)
+#define ORIS OPCD(25)
+#define XORI OPCD(26)
+#define XORIS OPCD(27)
+#define ANDI OPCD(28)
+#define ANDIS OPCD(29)
+#define MULLI OPCD( 7)
+#define CMPLI OPCD(10)
+#define CMPI OPCD(11)
+#define SUBFIC OPCD( 8)
+
+#define LWZU OPCD(33)
+#define STWU OPCD(37)
+
+#define RLWIMI OPCD(20)
+#define RLWINM OPCD(21)
+#define RLWNM OPCD(23)
+
+#define BCLR XO19( 16)
+#define BCCTR XO19(528)
+#define CRAND XO19(257)
+#define CRANDC XO19(129)
+#define CRNAND XO19(225)
+#define CROR XO19(449)
+#define CRNOR XO19( 33)
+
+#define EXTSB XO31(954)
+#define EXTSH XO31(922)
+#define ADD XO31(266)
+#define ADDE XO31(138)
+#define ADDC XO31( 10)
+#define AND XO31( 28)
+#define SUBF XO31( 40)
+#define SUBFC XO31( 8)
+#define SUBFE XO31(136)
+#define OR XO31(444)
+#define XOR XO31(316)
+#define MULLW XO31(235)
+#define MULHWU XO31( 11)
+#define DIVW XO31(491)
+#define DIVWU XO31(459)
+#define CMP XO31( 0)
+#define CMPL XO31( 32)
+#define LHBRX XO31(790)
+#define LWBRX XO31(534)
+#define STHBRX XO31(918)
+#define STWBRX XO31(662)
+#define MFSPR XO31(339)
+#define MTSPR XO31(467)
+#define SRAWI XO31(824)
+#define NEG XO31(104)
+#define MFCR XO31( 19)
+#define CNTLZW XO31( 26)
+#define NOR XO31(124)
+#define ANDC XO31( 60)
+#define ORC XO31(412)
+#define EQV XO31(284)
+#define NAND XO31(476)
+
+#define LBZX XO31( 87)
+#define LHZX XO31(279)
+#define LHAX XO31(343)
+#define LWZX XO31( 23)
+#define STBX XO31(215)
+#define STHX XO31(407)
+#define STWX XO31(151)
+
+#define SPR(a,b) ((((a)<<5)|(b))<<11)
+#define LR SPR(8, 0)
+#define CTR SPR(9, 0)
+
+#define SLW XO31( 24)
+#define SRW XO31(536)
+#define SRAW XO31(792)
+
+#define TW XO31(4)
+#define TRAP (TW | TO (31))
+
+#define RT(r) ((r)<<21)
+#define RS(r) ((r)<<21)
+#define RA(r) ((r)<<16)
+#define RB(r) ((r)<<11)
+#define TO(t) ((t)<<21)
+#define SH(s) ((s)<<11)
+#define MB(b) ((b)<<6)
+#define ME(e) ((e)<<1)
+#define BO(o) ((o)<<21)
+
+#define LK 1
+
+#define TAB(t,a,b) (RT(t) | RA(a) | RB(b))
+#define SAB(s,a,b) (RS(s) | RA(a) | RB(b))
+
+#define BF(n) ((n)<<23)
+#define BI(n, c) (((c)+((n)*4))<<16)
+#define BT(n, c) (((c)+((n)*4))<<21)
+#define BA(n, c) (((c)+((n)*4))<<16)
+#define BB(n, c) (((c)+((n)*4))<<11)
+
+#define BO_COND_TRUE BO (12)
+#define BO_COND_FALSE BO (4)
+#define BO_ALWAYS BO (20)
+
+enum {
+ CR_LT,
+ CR_GT,
+ CR_EQ,
+ CR_SO
+};
+
+static const uint32_t tcg_to_bc[10] = {
+ [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE,
+ [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE,
+ [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+ [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+};
+
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ tcg_out32 (s, OR | SAB (arg, ret, arg));
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ if (arg == (int16_t) arg)
+ tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
+ else {
+ tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff));
+ if (arg & 0xffff)
+ tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff));
+ }
+}
+
+static void tcg_out_ldst (TCGContext *s, int ret, int addr,
+ int offset, int op1, int op2)
+{
+ if (offset == (int16_t) offset)
+ tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, offset);
+ tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+ }
+}
+
+static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) s->code_ptr;
+ if ((disp << 6) >> 6 == disp)
+ tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target);
+ tcg_out32 (s, MTSPR | RS (0) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS | mask);
+ }
+}
+
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+{
+#ifdef _CALL_AIX
+ int reg;
+
+ if (const_arg) {
+ reg = 2;
+ tcg_out_movi (s, TCG_TYPE_I32, reg, arg);
+ }
+ else reg = arg;
+
+ tcg_out32 (s, LWZ | RT (0) | RA (reg));
+ tcg_out32 (s, MTSPR | RA (0) | CTR);
+ tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4);
+ tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+#else
+ if (const_arg) {
+ tcg_out_b (s, LK, arg);
+ }
+ else {
+ tcg_out32 (s, MTSPR | RS (arg) | LR);
+ tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+ }
+#endif
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+#endif
+
+static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, data_reg2, r0, r1, rbase, mem_index, s_bits, bswap;
+#ifdef CONFIG_SOFTMMU
+ int r2;
+ void *label1_ptr, *label2_ptr;
+#endif
+#if TARGET_LONG_BITS == 64
+ int addr_reg2;
+#endif
+
+ data_reg = *args++;
+ if (opc == 3)
+ data_reg2 = *args++;
+ else
+ data_reg2 = 0;
+ addr_reg = *args++;
+#if TARGET_LONG_BITS == 64
+ addr_reg2 = *args++;
+#endif
+ mem_index = *args;
+ s_bits = opc & 3;
+
+#ifdef CONFIG_SOFTMMU
+ r0 = 3;
+ r1 = 4;
+ r2 = 0;
+ rbase = 0;
+
+ tcg_out32 (s, (RLWINM
+ | RA (r0)
+ | RS (addr_reg)
+ | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+ | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
+ | ME (31 - CPU_TLB_ENTRY_BITS)
+ )
+ );
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+ tcg_out32 (s, (LWZU
+ | RT (r1)
+ | RA (r0)
+ | offsetof (CPUState, tlb_table[mem_index][0].addr_read)
+ )
+ );
+ tcg_out32 (s, (RLWINM
+ | RA (r2)
+ | RS (addr_reg)
+ | SH (0)
+ | MB ((32 - s_bits) & 31)
+ | ME (31 - TARGET_PAGE_BITS)
+ )
+ );
+
+ tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1));
+#if TARGET_LONG_BITS == 64
+ tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1));
+ tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+#endif
+
+ label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+ tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+ /* slow path */
+#if TARGET_LONG_BITS == 32
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
+ tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index);
+#else
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
+ tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index);
+#endif
+
+ tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+ switch (opc) {
+ case 0|4:
+ tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
+ break;
+ case 1|4:
+ tcg_out32 (s, EXTSH | RA (data_reg) | RS (3));
+ break;
+ case 0:
+ case 1:
+ case 2:
+ if (data_reg != 3)
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg, 3);
+ break;
+ case 3:
+ if (data_reg == 3) {
+ if (data_reg2 == 4) {
+ tcg_out_mov (s, TCG_TYPE_I32, 0, 4);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, 3);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, 0);
+ }
+ else {
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, 4);
+ }
+ }
+ else {
+ if (data_reg != 4) tcg_out_mov (s, TCG_TYPE_I32, data_reg, 4);
+ if (data_reg2 != 3) tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+ }
+ break;
+ }
+ label2_ptr = s->code_ptr;
+ tcg_out32 (s, B);
+
+ /* label1: fast path */
+#ifdef FAST_PATH
+ reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+ /* r0 now contains &env->tlb_table[mem_index][index].addr_read */
+ tcg_out32 (s, (LWZ
+ | RT (r0)
+ | RA (r0)
+ | (offsetof (CPUTLBEntry, addend)
+ - offsetof (CPUTLBEntry, addr_read))
+ ));
+ /* r0 = env->tlb_table[mem_index][index].addend */
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+ /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else /* !CONFIG_SOFTMMU */
+ r0 = addr_reg;
+ r1 = 3;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 0;
+#else
+ bswap = 1;
+#endif
+
+ switch (opc) {
+ default:
+ case 0:
+ tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+ break;
+ case 0|4:
+ tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg));
+ break;
+ case 1:
+ if (bswap)
+ tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0));
+ break;
+ case 1|4:
+ if (bswap) {
+ tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
+ }
+ else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
+ break;
+ case 2:
+ if (bswap)
+ tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0));
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, LWBRX | TAB (data_reg2, rbase, r1));
+ }
+ else {
+#ifdef CONFIG_USE_GUEST_BASE
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, LWZX | TAB (data_reg2, rbase, r0));
+ tcg_out32 (s, LWZX | TAB (data_reg, rbase, r1));
+#else
+ if (r0 == data_reg2) {
+ tcg_out32 (s, LWZ | RT (0) | RA (r0));
+ tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 0);
+ }
+ else {
+ tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0));
+ tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
+ }
+#endif
+ }
+ break;
+ }
+
+#ifdef CONFIG_SOFTMMU
+ reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap, rbase;
+#ifdef CONFIG_SOFTMMU
+ int r2, ir;
+ void *label1_ptr, *label2_ptr;
+#endif
+#if TARGET_LONG_BITS == 64
+ int addr_reg2;
+#endif
+
+ data_reg = *args++;
+ if (opc == 3)
+ data_reg2 = *args++;
+ else
+ data_reg2 = 0;
+ addr_reg = *args++;
+#if TARGET_LONG_BITS == 64
+ addr_reg2 = *args++;
+#endif
+ mem_index = *args;
+
+#ifdef CONFIG_SOFTMMU
+ r0 = 3;
+ r1 = 4;
+ r2 = 0;
+ rbase = 0;
+
+ tcg_out32 (s, (RLWINM
+ | RA (r0)
+ | RS (addr_reg)
+ | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+ | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS))
+ | ME (31 - CPU_TLB_ENTRY_BITS)
+ )
+ );
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+ tcg_out32 (s, (LWZU
+ | RT (r1)
+ | RA (r0)
+ | offsetof (CPUState, tlb_table[mem_index][0].addr_write)
+ )
+ );
+ tcg_out32 (s, (RLWINM
+ | RA (r2)
+ | RS (addr_reg)
+ | SH (0)
+ | MB ((32 - opc) & 31)
+ | ME (31 - TARGET_PAGE_BITS)
+ )
+ );
+
+ tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1));
+#if TARGET_LONG_BITS == 64
+ tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1));
+ tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+#endif
+
+ label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+ tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+ /* slow path */
+#if TARGET_LONG_BITS == 32
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
+ ir = 4;
+#else
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+ ir = 5;
+#else
+ ir = 4;
+#endif
+#endif
+
+ switch (opc) {
+ case 0:
+ tcg_out32 (s, (RLWINM
+ | RA (ir)
+ | RS (data_reg)
+ | SH (0)
+ | MB (24)
+ | ME (31)));
+ break;
+ case 1:
+ tcg_out32 (s, (RLWINM
+ | RA (ir)
+ | RS (data_reg)
+ | SH (0)
+ | MB (16)
+ | ME (31)));
+ break;
+ case 2:
+ tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+ break;
+ case 3:
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+ ir = 5;
+#endif
+ tcg_out_mov (s, TCG_TYPE_I32, ir++, data_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+ break;
+ }
+ ir++;
+
+ tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
+ tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
+ label2_ptr = s->code_ptr;
+ tcg_out32 (s, B);
+
+ /* label1: fast path */
+#ifdef FAST_PATH
+ reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+ tcg_out32 (s, (LWZ
+ | RT (r0)
+ | RA (r0)
+ | (offsetof (CPUTLBEntry, addend)
+ - offsetof (CPUTLBEntry, addr_write))
+ ));
+ /* r0 = env->tlb_table[mem_index][index].addend */
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+ /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else /* !CONFIG_SOFTMMU */
+ r0 = addr_reg;
+ r1 = 3;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 0;
+#else
+ bswap = 1;
+#endif
+ switch (opc) {
+ case 0:
+ tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
+ break;
+ case 1:
+ if (bswap)
+ tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, STHX | SAB (data_reg, rbase, r0));
+ break;
+ case 2:
+ if (bswap)
+ tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, STWX | SAB (data_reg, rbase, r0));
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+ tcg_out32 (s, STWBRX | SAB (data_reg2, rbase, r1));
+ }
+ else {
+#ifdef CONFIG_USE_GUEST_BASE
+ tcg_out32 (s, STWX | SAB (data_reg2, rbase, r0));
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, STWX | SAB (data_reg, rbase, r1));
+#else
+ tcg_out32 (s, STW | RS (data_reg2) | RA (r0));
+ tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4);
+#endif
+ }
+ break;
+ }
+
+#ifdef CONFIG_SOFTMMU
+ reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_target_qemu_prologue (TCGContext *s)
+{
+ int i, frame_size;
+
+ frame_size = 0
+ + LINKAGE_AREA_SIZE
+ + TCG_STATIC_CALL_ARGS_SIZE
+ + ARRAY_SIZE (tcg_target_callee_save_regs) * 4
+ ;
+ frame_size = (frame_size + 15) & ~15;
+
+#ifdef _CALL_AIX
+ {
+ uint32_t addr;
+
+ /* First emit adhoc function descriptor */
+ addr = (uint32_t) s->code_ptr + 12;
+ tcg_out32 (s, addr); /* entry point */
+ s->code_ptr += 8; /* skip TOC and environment pointer */
+ }
+#endif
+ tcg_out32 (s, MFSPR | RT (0) | LR);
+ tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff));
+ for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+ tcg_out32 (s, (STW
+ | RS (tcg_target_callee_save_regs[i])
+ | RA (1)
+ | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
+ )
+ );
+ tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET));
+
+#ifdef CONFIG_USE_GUEST_BASE
+ if (GUEST_BASE) {
+ tcg_out_movi (s, TCG_TYPE_I32, TCG_GUEST_BASE_REG, GUEST_BASE);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+ }
+#endif
+
+ tcg_out32 (s, MTSPR | RS (3) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS);
+ tb_ret_addr = s->code_ptr;
+
+ for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+ tcg_out32 (s, (LWZ
+ | RT (tcg_target_callee_save_regs[i])
+ | RA (1)
+ | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
+ )
+ );
+ tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET));
+ tcg_out32 (s, MTSPR | RS (0) | LR);
+ tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size);
+ tcg_out32 (s, BCLR | BO_ALWAYS);
+}
+
+static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+ tcg_target_long arg2)
+{
+ tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
+}
+
+static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+ tcg_target_long arg2)
+{
+ tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
+}
+
+static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+ if (!si && rt == ra)
+ return;
+
+ if (si == (int16_t) si)
+ tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff));
+ else {
+ uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15);
+ tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h);
+ tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff));
+ }
+}
+
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ ppc_addi (s, reg, reg, val);
+}
+
+static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
+ int const_arg2, int cr)
+{
+ int imm;
+ uint32_t op;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ if (const_arg2) {
+ if ((int16_t) arg2 == arg2) {
+ op = CMPI;
+ imm = 1;
+ break;
+ }
+ else if ((uint16_t) arg2 == arg2) {
+ op = CMPLI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMPL;
+ imm = 0;
+ break;
+
+ case TCG_COND_LT:
+ case TCG_COND_GE:
+ case TCG_COND_LE:
+ case TCG_COND_GT:
+ if (const_arg2) {
+ if ((int16_t) arg2 == arg2) {
+ op = CMPI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMP;
+ imm = 0;
+ break;
+
+ case TCG_COND_LTU:
+ case TCG_COND_GEU:
+ case TCG_COND_LEU:
+ case TCG_COND_GTU:
+ if (const_arg2) {
+ if ((uint16_t) arg2 == arg2) {
+ op = CMPLI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMPL;
+ imm = 0;
+ break;
+
+ default:
+ tcg_abort ();
+ }
+ op |= BF (cr);
+
+ if (imm)
+ tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff));
+ else {
+ if (const_arg2) {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+ tcg_out32 (s, op | RA (arg1) | RB (0));
+ }
+ else
+ tcg_out32 (s, op | RA (arg1) | RB (arg2));
+ }
+
+}
+
+static void tcg_out_bc (TCGContext *s, int bc, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value)
+ tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value));
+ else {
+ uint16_t val = *(uint16_t *) &s->code_ptr[2];
+
+ /* Thanks to Andrzej Zaborowski */
+ tcg_out32 (s, bc | (val & 0xfffc));
+ tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0);
+ }
+}
+
+static void tcg_out_cr7eq_from_cond (TCGContext *s, const TCGArg *args,
+ const int *const_args)
+{
+ TCGCond cond = args[4];
+ int op;
+ struct { int bit1; int bit2; int cond2; } bits[] = {
+ [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT },
+ [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT },
+ [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT },
+ [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT },
+ [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU },
+ [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU },
+ [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU },
+ [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU },
+ }, *b = &bits[cond];
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ op = (cond == TCG_COND_EQ) ? CRAND : CRNAND;
+ tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6);
+ tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7);
+ tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LE:
+ case TCG_COND_GT:
+ case TCG_COND_GE:
+ case TCG_COND_LTU:
+ case TCG_COND_LEU:
+ case TCG_COND_GTU:
+ case TCG_COND_GEU:
+ op = (b->bit1 != b->bit2) ? CRANDC : CRAND;
+ tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5);
+ tcg_out_cmp (s, tcg_unsigned_cond (cond), args[0], args[2],
+ const_args[2], 7);
+ tcg_out32 (s, op | BT (7, CR_EQ) | BA (5, CR_EQ) | BB (7, b->bit2));
+ tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ));
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+static void tcg_out_setcond (TCGContext *s, TCGCond cond, TCGArg arg0,
+ TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+ int crop, sh, arg;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ if (const_arg2) {
+ if (!arg2) {
+ arg = arg1;
+ }
+ else {
+ arg = 0;
+ if ((uint16_t) arg2 == arg2) {
+ tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+ }
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+ tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+ }
+ }
+ }
+ else {
+ arg = 0;
+ tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+ }
+ tcg_out32 (s, CNTLZW | RS (arg) | RA (0));
+ tcg_out32 (s, (RLWINM
+ | RA (arg0)
+ | RS (0)
+ | SH (27)
+ | MB (5)
+ | ME (31)
+ )
+ );
+ break;
+
+ case TCG_COND_NE:
+ if (const_arg2) {
+ if (!arg2) {
+ arg = arg1;
+ }
+ else {
+ arg = 0;
+ if ((uint16_t) arg2 == arg2) {
+ tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+ }
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, arg2);
+ tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+ }
+ }
+ }
+ else {
+ arg = 0;
+ tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+ }
+
+ if (arg == arg1 && arg1 == arg0) {
+ tcg_out32 (s, ADDIC | RT (0) | RA (arg) | 0xffff);
+ tcg_out32 (s, SUBFE | TAB (arg0, 0, arg));
+ }
+ else {
+ tcg_out32 (s, ADDIC | RT (arg0) | RA (arg) | 0xffff);
+ tcg_out32 (s, SUBFE | TAB (arg0, arg0, arg));
+ }
+ break;
+
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ sh = 30;
+ crop = 0;
+ goto crtest;
+
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ sh = 29;
+ crop = 0;
+ goto crtest;
+
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ sh = 31;
+ crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_LT) | BB (7, CR_LT);
+ goto crtest;
+
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ sh = 31;
+ crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_GT) | BB (7, CR_GT);
+ crtest:
+ tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7);
+ if (crop) tcg_out32 (s, crop);
+ tcg_out32 (s, MFCR | RT (0));
+ tcg_out32 (s, (RLWINM
+ | RA (arg0)
+ | RS (0)
+ | SH (sh)
+ | MB (31)
+ | ME (31)
+ )
+ );
+ break;
+
+ default:
+ tcg_abort ();
+ }
+}
+
+static void tcg_out_setcond2 (TCGContext *s, const TCGArg *args,
+ const int *const_args)
+{
+ tcg_out_cr7eq_from_cond (s, args + 1, const_args + 1);
+ tcg_out32 (s, MFCR | RT (0));
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (0)
+ | SH (31)
+ | MB (31)
+ | ME (31)
+ )
+ );
+}
+
+static void tcg_out_brcond (TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
+{
+ tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7);
+ tcg_out_bc (s, tcg_to_bc[cond], label_index);
+}
+
+/* XXX: we implement it at the target level to avoid having to
+ handle cross basic blocks temporaries */
+static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args,
+ const int *const_args)
+{
+ tcg_out_cr7eq_from_cond (s, args, const_args);
+ tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), args[5]);
+}
+
+void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr)
+{
+ uint32_t *ptr;
+ long disp = addr - jmp_addr;
+ unsigned long patch_size;
+
+ ptr = (uint32_t *)jmp_addr;
+
+ if ((disp << 6) >> 6 != disp) {
+ ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */
+ ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */
+ ptr[2] = 0x7c0903a6; /* mtctr 0 */
+ ptr[3] = 0x4e800420; /* brctr */
+ patch_size = 16;
+ } else {
+ /* patch the branch destination */
+ if (disp != 16) {
+ *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */
+ patch_size = 4;
+ } else {
+ ptr[0] = 0x60000000; /* nop */
+ ptr[1] = 0x60000000;
+ ptr[2] = 0x60000000;
+ ptr[3] = 0x60000000;
+ patch_size = 16;
+ }
+ }
+ /* flush icache */
+ flush_icache_range(jmp_addr, jmp_addr + patch_size);
+}
+
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args)
+{
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]);
+ tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr);
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ s->code_ptr += 16;
+ }
+ else {
+ tcg_abort ();
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_br:
+ {
+ TCGLabel *l = &s->labels[args[0]];
+
+ if (l->has_value) {
+ tcg_out_b (s, 0, l->u.value);
+ }
+ else {
+ uint32_t val = *(uint32_t *) s->code_ptr;
+
+ /* Thanks to Andrzej Zaborowski */
+ tcg_out32 (s, B | (val & 0x3fffffc));
+ tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0);
+ }
+ }
+ break;
+ case INDEX_op_call:
+ tcg_out_call (s, args[0], const_args[0]);
+ break;
+ case INDEX_op_jmp:
+ if (const_args[0]) {
+ tcg_out_b (s, 0, args[0]);
+ }
+ else {
+ tcg_out32 (s, MTSPR | RS (args[0]) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS);
+ }
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_ld8u_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+ break;
+ case INDEX_op_ld8s_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+ tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0]));
+ break;
+ case INDEX_op_ld16u_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX);
+ break;
+ case INDEX_op_ld16s_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX);
+ break;
+ case INDEX_op_ld_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
+ break;
+ case INDEX_op_st8_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX);
+ break;
+ case INDEX_op_st16_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX);
+ break;
+ case INDEX_op_st_i32:
+ tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
+ break;
+
+ case INDEX_op_add_i32:
+ if (const_args[2])
+ ppc_addi (s, args[0], args[1], args[2]);
+ else
+ tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_sub_i32:
+ if (const_args[2])
+ ppc_addi (s, args[0], args[1], -args[2]);
+ else
+ tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+ break;
+
+ case INDEX_op_and_i32:
+ if (const_args[2]) {
+ uint32_t c;
+
+ c = args[2];
+
+ if (!c) {
+ tcg_out_movi (s, TCG_TYPE_I32, args[0], 0);
+ break;
+ }
+#ifdef __PPU__
+ uint32_t t, n;
+ int mb, me;
+
+ n = c ^ -(c & 1);
+ t = n + (n & -n);
+
+ if ((t & (t - 1)) == 0) {
+ int lzc, tzc;
+
+ if ((c & 0x80000001) == 0x80000001) {
+ lzc = clz32 (n);
+ tzc = ctz32 (n);
+
+ mb = 32 - tzc;
+ me = lzc - 1;
+ }
+ else {
+ lzc = clz32 (c);
+ tzc = ctz32 (c);
+
+ mb = lzc;
+ me = 31 - tzc;
+ }
+
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (mb)
+ | ME (me)
+ )
+ );
+ }
+ else
+#endif /* !__PPU__ */
+ {
+ if ((c & 0xffff) == c)
+ tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | c);
+ else if ((c & 0xffff0000) == c)
+ tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0])
+ | ((c >> 16) & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, c);
+ tcg_out32 (s, AND | SAB (args[1], args[0], 0));
+ }
+ }
+ }
+ else
+ tcg_out32 (s, AND | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_or_i32:
+ if (const_args[2]) {
+ if (args[2] & 0xffff) {
+ tcg_out32 (s, ORI | RS (args[1]) | RA (args[0])
+ | (args[2] & 0xffff));
+ if (args[2] >> 16)
+ tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ }
+ else {
+ tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ }
+ }
+ else
+ tcg_out32 (s, OR | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_xor_i32:
+ if (const_args[2]) {
+ if ((args[2] & 0xffff) == args[2])
+ tcg_out32 (s, XORI | RS (args[1]) | RA (args[0])
+ | (args[2] & 0xffff));
+ else if ((args[2] & 0xffff0000) == args[2])
+ tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+ tcg_out32 (s, XOR | SAB (args[1], args[0], 0));
+ }
+ }
+ else
+ tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_andc_i32:
+ tcg_out32 (s, ANDC | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_orc_i32:
+ tcg_out32 (s, ORC | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_eqv_i32:
+ tcg_out32 (s, EQV | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_nand_i32:
+ tcg_out32 (s, NAND | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_nor_i32:
+ tcg_out32 (s, NOR | SAB (args[1], args[0], args[2]));
+ break;
+
+ case INDEX_op_mul_i32:
+ if (const_args[2]) {
+ if (args[2] == (int16_t) args[2])
+ tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1])
+ | (args[2] & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+ tcg_out32 (s, MULLW | TAB (args[0], args[1], 0));
+ }
+ }
+ else
+ tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_div_i32:
+ tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_divu_i32:
+ tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_rem_i32:
+ tcg_out32 (s, DIVW | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+
+ case INDEX_op_remu_i32:
+ tcg_out32 (s, DIVWU | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+
+ case INDEX_op_mulu2_i32:
+ if (args[0] == args[2] || args[0] == args[3]) {
+ tcg_out32 (s, MULLW | TAB (0, args[2], args[3]));
+ tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+ }
+ else {
+ tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3]));
+ tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
+ }
+ break;
+
+ case INDEX_op_shl_i32:
+ if (const_args[2]) {
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (args[2])
+ | MB (0)
+ | ME (31 - args[2])
+ )
+ );
+ }
+ else
+ tcg_out32 (s, SLW | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_shr_i32:
+ if (const_args[2]) {
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (32 - args[2])
+ | MB (args[2])
+ | ME (31)
+ )
+ );
+ }
+ else
+ tcg_out32 (s, SRW | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_sar_i32:
+ if (const_args[2])
+ tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2]));
+ else
+ tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_rotl_i32:
+ {
+ int op = 0
+ | RA (args[0])
+ | RS (args[1])
+ | MB (0)
+ | ME (31)
+ | (const_args[2] ? RLWINM | SH (args[2])
+ : RLWNM | RB (args[2]))
+ ;
+ tcg_out32 (s, op);
+ }
+ break;
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ if (!args[2]) {
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], args[1]);
+ }
+ else {
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (32 - args[2])
+ | MB (0)
+ | ME (31)
+ );
+ }
+ }
+ else {
+ tcg_out32 (s, SUBFIC | RT (0) | RA (args[2]) | 32);
+ tcg_out32 (s, RLWNM
+ | RA (args[0])
+ | RS (args[1])
+ | RB (0)
+ | MB (0)
+ | ME (31)
+ );
+ }
+ break;
+
+ case INDEX_op_add2_i32:
+ if (args[0] == args[3] || args[0] == args[5]) {
+ tcg_out32 (s, ADDC | TAB (0, args[2], args[4]));
+ tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5]));
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+ }
+ else {
+ tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4]));
+ tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5]));
+ }
+ break;
+ case INDEX_op_sub2_i32:
+ if (args[0] == args[3] || args[0] == args[5]) {
+ tcg_out32 (s, SUBFC | TAB (0, args[4], args[2]));
+ tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3]));
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
+ }
+ else {
+ tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2]));
+ tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3]));
+ }
+ break;
+
+ case INDEX_op_brcond_i32:
+ /*
+ args[0] = r0
+ args[1] = r1
+ args[2] = cond
+ args[3] = r1 is const
+ args[4] = label_index
+ */
+ tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]);
+ break;
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args, const_args);
+ break;
+
+ case INDEX_op_neg_i32:
+ tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
+ break;
+
+ case INDEX_op_not_i32:
+ tcg_out32 (s, NOR | SAB (args[1], args[0], args[1]));
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ case INDEX_op_ext8s_i32:
+ tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0]));
+ break;
+ case INDEX_op_ext8u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (24)
+ | ME (31)
+ );
+ break;
+ case INDEX_op_ext16s_i32:
+ tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0]));
+ break;
+ case INDEX_op_ext16u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (16)
+ | ME (31)
+ );
+ break;
+
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond (s, args[3], args[0], args[1], args[2], const_args[2]);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2 (s, args, const_args);
+ break;
+
+ case INDEX_op_bswap16_i32:
+ /* Stolen from gcc's builtin_bswap16 */
+
+ /* a1 = abcd */
+
+ /* r0 = (a1 << 8) & 0xff00 # 00d0 */
+ tcg_out32 (s, RLWINM
+ | RA (0)
+ | RS (args[1])
+ | SH (8)
+ | MB (16)
+ | ME (23)
+ );
+
+ /* a0 = rotate_left (a1, 24) & 0xff # 000c */
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (24)
+ | MB (24)
+ | ME (31)
+ );
+
+ /* a0 = a0 | r0 # 00dc */
+ tcg_out32 (s, OR | SAB (0, args[0], args[0]));
+ break;
+
+ case INDEX_op_bswap32_i32:
+ /* Stolen from gcc's builtin_bswap32 */
+ {
+ int a0 = args[0];
+
+ /* a1 = args[1] # abcd */
+
+ if (a0 == args[1]) {
+ a0 = 0;
+ }
+
+ /* a0 = rotate_left (a1, 8) # bcda */
+ tcg_out32 (s, RLWINM
+ | RA (a0)
+ | RS (args[1])
+ | SH (8)
+ | MB (0)
+ | ME (31)
+ );
+
+ /* a0 = (a0 & ~0xff000000) | ((a1 << 24) & 0xff000000) # dcda */
+ tcg_out32 (s, RLWIMI
+ | RA (a0)
+ | RS (args[1])
+ | SH (24)
+ | MB (0)
+ | ME (7)
+ );
+
+ /* a0 = (a0 & ~0x0000ff00) | ((a1 << 24) & 0x0000ff00) # dcba */
+ tcg_out32 (s, RLWIMI
+ | RA (a0)
+ | RS (args[1])
+ | SH (24)
+ | MB (16)
+ | ME (23)
+ );
+
+ if (!a0) {
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], a0);
+ }
+ }
+ break;
+
+ default:
+ tcg_dump_ops (s, stderr);
+ tcg_abort ();
+ }
+}
+
+static const TCGTargetOpDef ppc_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "r", "ri" } },
+ { INDEX_op_mul_i32, { "r", "r", "ri" } },
+ { INDEX_op_div_i32, { "r", "r", "r" } },
+ { INDEX_op_divu_i32, { "r", "r", "r" } },
+ { INDEX_op_rem_i32, { "r", "r", "r" } },
+ { INDEX_op_remu_i32, { "r", "r", "r" } },
+ { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
+ { INDEX_op_sub_i32, { "r", "r", "ri" } },
+ { INDEX_op_and_i32, { "r", "r", "ri" } },
+ { INDEX_op_or_i32, { "r", "r", "ri" } },
+ { INDEX_op_xor_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_shl_i32, { "r", "r", "ri" } },
+ { INDEX_op_shr_i32, { "r", "r", "ri" } },
+ { INDEX_op_sar_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_brcond_i32, { "r", "ri" } },
+
+ { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
+ { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
+ { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
+
+ { INDEX_op_neg_i32, { "r", "r" } },
+ { INDEX_op_not_i32, { "r", "r" } },
+
+ { INDEX_op_andc_i32, { "r", "r", "r" } },
+ { INDEX_op_orc_i32, { "r", "r", "r" } },
+ { INDEX_op_eqv_i32, { "r", "r", "r" } },
+ { INDEX_op_nand_i32, { "r", "r", "r" } },
+ { INDEX_op_nor_i32, { "r", "r", "r" } },
+
+ { INDEX_op_setcond_i32, { "r", "r", "ri" } },
+ { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+
+ { INDEX_op_bswap16_i32, { "r", "r" } },
+ { INDEX_op_bswap32_i32, { "r", "r" } },
+
+#if TARGET_LONG_BITS == 32
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "K", "K" } },
+ { INDEX_op_qemu_st16, { "K", "K" } },
+ { INDEX_op_qemu_st32, { "K", "K" } },
+ { INDEX_op_qemu_st64, { "M", "M", "M" } },
+#else
+ { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
+
+ { INDEX_op_qemu_st8, { "K", "K", "K" } },
+ { INDEX_op_qemu_st16, { "K", "K", "K" } },
+ { INDEX_op_qemu_st32, { "K", "K", "K" } },
+ { INDEX_op_qemu_st64, { "M", "M", "M", "M" } },
+#endif
+
+ { INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext8u_i32, { "r", "r" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
+
+ { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+ tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+ (1 << TCG_REG_R0) |
+#ifdef _CALL_DARWIN
+ (1 << TCG_REG_R2) |
+#endif
+ (1 << TCG_REG_R3) |
+ (1 << TCG_REG_R4) |
+ (1 << TCG_REG_R5) |
+ (1 << TCG_REG_R6) |
+ (1 << TCG_REG_R7) |
+ (1 << TCG_REG_R8) |
+ (1 << TCG_REG_R9) |
+ (1 << TCG_REG_R10) |
+ (1 << TCG_REG_R11) |
+ (1 << TCG_REG_R12)
+ );
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);
+#ifndef _CALL_DARWIN
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
+#endif
+#ifdef _CALL_SYSV
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
+#endif
+
+ tcg_add_target_add_op_defs(ppc_op_defs);
+}
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
new file mode 100644
index 0000000..a1f8599
--- /dev/null
+++ b/tcg/ppc/tcg-target.h
@@ -0,0 +1,98 @@
+/*
+ * 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_PPC 1
+
+#define TCG_TARGET_REG_BITS 32
+#define TCG_TARGET_WORDS_BIGENDIAN
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31
+};
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R1
+#define TCG_TARGET_STACK_ALIGN 16
+#if defined _CALL_DARWIN || defined __APPLE__
+#define TCG_TARGET_CALL_STACK_OFFSET 24
+#elif defined _CALL_AIX
+#define TCG_TARGET_CALL_STACK_OFFSET 52
+#elif defined _CALL_SYSV
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_CALL_STACK_OFFSET 8
+#else
+#error Unsupported system
+#endif
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_eqv_i32
+#define TCG_TARGET_HAS_nand_i32
+#define TCG_TARGET_HAS_nor_i32
+
+#define TCG_AREG0 TCG_REG_R27
+
+#define TCG_TARGET_HAS_GUEST_BASE
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
new file mode 100644
index 0000000..ebbee34
--- /dev/null
+++ b/tcg/ppc64/tcg-target.c
@@ -0,0 +1,1699 @@
+/*
+ * 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_CT_CONST_U32 0x100
+
+static uint8_t *tb_ret_addr;
+
+#define FAST_PATH
+
+#if TARGET_LONG_BITS == 32
+#define LD_ADDR LWZU
+#define CMP_L 0
+#else
+#define LD_ADDR LDU
+#define CMP_L (1<<21)
+#endif
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG 30
+#else
+#define TCG_GUEST_BASE_REG 0
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "r0",
+ "r1",
+ "r2",
+ "r3",
+ "r4",
+ "r5",
+ "r6",
+ "r7",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "r16",
+ "r17",
+ "r18",
+ "r19",
+ "r20",
+ "r21",
+ "r22",
+ "r23",
+ "r24",
+ "r25",
+ "r26",
+ "r27",
+ "r28",
+ "r29",
+ "r30",
+ "r31"
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31,
+#ifdef __APPLE__
+ TCG_REG_R2,
+#endif
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+#ifndef __APPLE__
+ TCG_REG_R11,
+#endif
+ TCG_REG_R12,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_R3
+};
+
+static const int tcg_target_callee_save_regs[] = {
+#ifdef __APPLE__
+ TCG_REG_R11,
+#endif
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ /* TCG_REG_R27, */ /* currently used for the global env, so no
+ need to save */
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31
+};
+
+static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) pc;
+ if ((disp << 38) >> 38 != disp)
+ tcg_abort ();
+
+ return disp & 0x3fffffc;
+}
+
+static void reloc_pc24 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc)
+ | reloc_pc24_val (pc, target);
+}
+
+static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) pc;
+ if (disp != (int16_t) disp)
+ tcg_abort ();
+
+ return disp & 0xfffc;
+}
+
+static void reloc_pc14 (void *pc, tcg_target_long target)
+{
+ *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc)
+ | reloc_pc14_val (pc, target);
+}
+
+static void patch_reloc (uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch (type) {
+ case R_PPC_REL14:
+ reloc_pc14 (code_ptr, value);
+ break;
+ case R_PPC_REL24:
+ reloc_pc24 (code_ptr, value);
+ break;
+ default:
+ tcg_abort ();
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static int tcg_target_get_call_iarg_regs_count (int flags)
+{
+ return ARRAY_SIZE (tcg_target_call_iarg_regs);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch (ct_str[0]) {
+ case 'A': case 'B': case 'C': case 'D':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A');
+ break;
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+ break;
+ case 'L': /* qemu_ld constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+#ifdef CONFIG_SOFTMMU
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
+#endif
+ break;
+ case 'S': /* qemu_st constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+#ifdef CONFIG_SOFTMMU
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5);
+#endif
+ break;
+ case 'Z':
+ ct->ct |= TCG_CT_CONST_U32;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match (tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else if ((ct & TCG_CT_CONST_U32) && (val == (uint32_t) val))
+ return 1;
+ return 0;
+}
+
+#define OPCD(opc) ((opc)<<26)
+#define XO19(opc) (OPCD(19)|((opc)<<1))
+#define XO30(opc) (OPCD(30)|((opc)<<2))
+#define XO31(opc) (OPCD(31)|((opc)<<1))
+#define XO58(opc) (OPCD(58)|(opc))
+#define XO62(opc) (OPCD(62)|(opc))
+
+#define B OPCD( 18)
+#define BC OPCD( 16)
+#define LBZ OPCD( 34)
+#define LHZ OPCD( 40)
+#define LHA OPCD( 42)
+#define LWZ OPCD( 32)
+#define STB OPCD( 38)
+#define STH OPCD( 44)
+#define STW OPCD( 36)
+
+#define STD XO62( 0)
+#define STDU XO62( 1)
+#define STDX XO31(149)
+
+#define LD XO58( 0)
+#define LDX XO31( 21)
+#define LDU XO58( 1)
+#define LWA XO58( 2)
+#define LWAX XO31(341)
+
+#define ADDIC OPCD( 12)
+#define ADDI OPCD( 14)
+#define ADDIS OPCD( 15)
+#define ORI OPCD( 24)
+#define ORIS OPCD( 25)
+#define XORI OPCD( 26)
+#define XORIS OPCD( 27)
+#define ANDI OPCD( 28)
+#define ANDIS OPCD( 29)
+#define MULLI OPCD( 7)
+#define CMPLI OPCD( 10)
+#define CMPI OPCD( 11)
+
+#define LWZU OPCD( 33)
+#define STWU OPCD( 37)
+
+#define RLWINM OPCD( 21)
+
+#define RLDICL XO30( 0)
+#define RLDICR XO30( 1)
+#define RLDIMI XO30( 3)
+
+#define BCLR XO19( 16)
+#define BCCTR XO19(528)
+#define CRAND XO19(257)
+#define CRANDC XO19(129)
+#define CRNAND XO19(225)
+#define CROR XO19(449)
+#define CRNOR XO19( 33)
+
+#define EXTSB XO31(954)
+#define EXTSH XO31(922)
+#define EXTSW XO31(986)
+#define ADD XO31(266)
+#define ADDE XO31(138)
+#define ADDC XO31( 10)
+#define AND XO31( 28)
+#define SUBF XO31( 40)
+#define SUBFC XO31( 8)
+#define SUBFE XO31(136)
+#define OR XO31(444)
+#define XOR XO31(316)
+#define MULLW XO31(235)
+#define MULHWU XO31( 11)
+#define DIVW XO31(491)
+#define DIVWU XO31(459)
+#define CMP XO31( 0)
+#define CMPL XO31( 32)
+#define LHBRX XO31(790)
+#define LWBRX XO31(534)
+#define STHBRX XO31(918)
+#define STWBRX XO31(662)
+#define MFSPR XO31(339)
+#define MTSPR XO31(467)
+#define SRAWI XO31(824)
+#define NEG XO31(104)
+#define MFCR XO31( 19)
+#define CNTLZW XO31( 26)
+#define CNTLZD XO31( 58)
+
+#define MULLD XO31(233)
+#define MULHD XO31( 73)
+#define MULHDU XO31( 9)
+#define DIVD XO31(489)
+#define DIVDU XO31(457)
+
+#define LBZX XO31( 87)
+#define LHZX XO31(279)
+#define LHAX XO31(343)
+#define LWZX XO31( 23)
+#define STBX XO31(215)
+#define STHX XO31(407)
+#define STWX XO31(151)
+
+#define SPR(a,b) ((((a)<<5)|(b))<<11)
+#define LR SPR(8, 0)
+#define CTR SPR(9, 0)
+
+#define SLW XO31( 24)
+#define SRW XO31(536)
+#define SRAW XO31(792)
+
+#define SLD XO31( 27)
+#define SRD XO31(539)
+#define SRAD XO31(794)
+#define SRADI XO31(413<<1)
+
+#define TW XO31( 4)
+#define TRAP (TW | TO (31))
+
+#define RT(r) ((r)<<21)
+#define RS(r) ((r)<<21)
+#define RA(r) ((r)<<16)
+#define RB(r) ((r)<<11)
+#define TO(t) ((t)<<21)
+#define SH(s) ((s)<<11)
+#define MB(b) ((b)<<6)
+#define ME(e) ((e)<<1)
+#define BO(o) ((o)<<21)
+#define MB64(b) ((b)<<5)
+
+#define LK 1
+
+#define TAB(t,a,b) (RT(t) | RA(a) | RB(b))
+#define SAB(s,a,b) (RS(s) | RA(a) | RB(b))
+
+#define BF(n) ((n)<<23)
+#define BI(n, c) (((c)+((n)*4))<<16)
+#define BT(n, c) (((c)+((n)*4))<<21)
+#define BA(n, c) (((c)+((n)*4))<<16)
+#define BB(n, c) (((c)+((n)*4))<<11)
+
+#define BO_COND_TRUE BO (12)
+#define BO_COND_FALSE BO ( 4)
+#define BO_ALWAYS BO (20)
+
+enum {
+ CR_LT,
+ CR_GT,
+ CR_EQ,
+ CR_SO
+};
+
+static const uint32_t tcg_to_bc[10] = {
+ [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE,
+ [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE,
+ [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+ [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+};
+
+static void tcg_out_mov (TCGContext *s, TCGType type, int ret, int arg)
+{
+ tcg_out32 (s, OR | SAB (arg, ret, arg));
+}
+
+static void tcg_out_rld (TCGContext *s, int op, int ra, int rs, int sh, int mb)
+{
+ sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1);
+ mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f));
+ tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb);
+}
+
+static void tcg_out_movi32 (TCGContext *s, int ret, int32_t arg)
+{
+ if (arg == (int16_t) arg)
+ tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
+ else {
+ tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff));
+ if (arg & 0xffff)
+ tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff));
+ }
+}
+
+static void tcg_out_movi (TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ int32_t arg32 = arg;
+ arg = type == TCG_TYPE_I32 ? arg & 0xffffffff : arg;
+
+ if (arg == arg32) {
+ tcg_out_movi32 (s, ret, arg32);
+ }
+ else {
+ if ((uint64_t) arg >> 32) {
+ uint16_t h16 = arg >> 16;
+ uint16_t l16 = arg;
+
+ tcg_out_movi32 (s, ret, arg >> 32);
+ tcg_out_rld (s, RLDICR, ret, ret, 32, 31);
+ if (h16) tcg_out32 (s, ORIS | RS (ret) | RA (ret) | h16);
+ if (l16) tcg_out32 (s, ORI | RS (ret) | RA (ret) | l16);
+ }
+ else {
+ tcg_out_movi32 (s, ret, arg32);
+ if (arg32 < 0)
+ tcg_out_rld (s, RLDICL, ret, ret, 0, 32);
+ }
+ }
+}
+
+static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
+{
+ tcg_target_long disp;
+
+ disp = target - (tcg_target_long) s->code_ptr;
+ if ((disp << 38) >> 38 == disp)
+ tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
+ else {
+ tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target);
+ tcg_out32 (s, MTSPR | RS (0) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS | mask);
+ }
+}
+
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+{
+#ifdef __APPLE__
+ if (const_arg) {
+ tcg_out_b (s, LK, arg);
+ }
+ else {
+ tcg_out32 (s, MTSPR | RS (arg) | LR);
+ tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+ }
+#else
+ int reg;
+
+ if (const_arg) {
+ reg = 2;
+ tcg_out_movi (s, TCG_TYPE_I64, reg, arg);
+ }
+ else reg = arg;
+
+ tcg_out32 (s, LD | RT (0) | RA (reg));
+ tcg_out32 (s, MTSPR | RA (0) | CTR);
+ tcg_out32 (s, LD | RT (11) | RA (reg) | 16);
+ tcg_out32 (s, LD | RT (2) | RA (reg) | 8);
+ tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+#endif
+}
+
+static void tcg_out_ldst (TCGContext *s, int ret, int addr,
+ int offset, int op1, int op2)
+{
+ if (offset == (int16_t) offset)
+ tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I64, 0, offset);
+ tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+ }
+}
+
+static void tcg_out_ldsta (TCGContext *s, int ret, int addr,
+ int offset, int op1, int op2)
+{
+ if (offset == (int16_t) (offset & ~3))
+ tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I64, 0, offset);
+ tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+ }
+}
+
+#if defined (CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+
+static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2,
+ int addr_reg, int s_bits, int offset)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+
+ tcg_out32 (s, (RLWINM
+ | RA (r0)
+ | RS (addr_reg)
+ | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+ | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
+ | ME (31 - CPU_TLB_ENTRY_BITS)
+ )
+ );
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
+ tcg_out32 (s, (LWZU | RT (r1) | RA (r0) | offset));
+ tcg_out32 (s, (RLWINM
+ | RA (r2)
+ | RS (addr_reg)
+ | SH (0)
+ | MB ((32 - s_bits) & 31)
+ | ME (31 - TARGET_PAGE_BITS)
+ )
+ );
+#else
+ tcg_out_rld (s, RLDICL, r0, addr_reg,
+ 64 - TARGET_PAGE_BITS,
+ 64 - CPU_TLB_BITS);
+ tcg_out_rld (s, RLDICR, r0, r0,
+ CPU_TLB_ENTRY_BITS,
+ 63 - CPU_TLB_ENTRY_BITS);
+
+ tcg_out32 (s, ADD | TAB (r0, r0, TCG_AREG0));
+ tcg_out32 (s, LD_ADDR | RT (r1) | RA (r0) | offset);
+
+ if (!s_bits) {
+ tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS);
+ }
+ else {
+ tcg_out_rld (s, RLDICL, r2, addr_reg,
+ 64 - TARGET_PAGE_BITS,
+ TARGET_PAGE_BITS - s_bits);
+ tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0);
+ }
+#endif
+}
+#endif
+
+static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, r0, r1, rbase, mem_index, s_bits, bswap;
+#ifdef CONFIG_SOFTMMU
+ int r2;
+ void *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+ s_bits = opc & 3;
+
+#ifdef CONFIG_SOFTMMU
+ r0 = 3;
+ r1 = 4;
+ r2 = 0;
+ rbase = 0;
+
+ tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits,
+ offsetof (CPUState, tlb_table[mem_index][0].addr_read));
+
+ tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
+
+ label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+ tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+ /* slow path */
+ tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
+ tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index);
+
+ tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+
+ switch (opc) {
+ case 0|4:
+ tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
+ break;
+ case 1|4:
+ tcg_out32 (s, EXTSH | RA (data_reg) | RS (3));
+ break;
+ case 2|4:
+ tcg_out32 (s, EXTSW | RA (data_reg) | RS (3));
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ if (data_reg != 3)
+ tcg_out_mov (s, TCG_TYPE_I64, data_reg, 3);
+ break;
+ }
+ label2_ptr = s->code_ptr;
+ tcg_out32 (s, B);
+
+ /* label1: fast path */
+#ifdef FAST_PATH
+ reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+ /* r0 now contains &env->tlb_table[mem_index][index].addr_read */
+ tcg_out32 (s, (LD
+ | RT (r0)
+ | RA (r0)
+ | (offsetof (CPUTLBEntry, addend)
+ - offsetof (CPUTLBEntry, addr_read))
+ ));
+ /* r0 = env->tlb_table[mem_index][index].addend */
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+ /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else /* !CONFIG_SOFTMMU */
+#if TARGET_LONG_BITS == 32
+ tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+#endif
+ r0 = addr_reg;
+ r1 = 3;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 0;
+#else
+ bswap = 1;
+#endif
+ switch (opc) {
+ default:
+ case 0:
+ tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+ break;
+ case 0|4:
+ tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg));
+ break;
+ case 1:
+ if (bswap)
+ tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0));
+ break;
+ case 1|4:
+ if (bswap) {
+ tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
+ }
+ else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
+ break;
+ case 2:
+ if (bswap)
+ tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0));
+ break;
+ case 2|4:
+ if (bswap) {
+ tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, EXTSW | RA (data_reg) | RS (data_reg));
+ }
+ else tcg_out32 (s, LWAX | TAB (data_reg, rbase, r0));
+ break;
+ case 3:
+#ifdef CONFIG_USE_GUEST_BASE
+ if (bswap) {
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
+ tcg_out32 (s, LWBRX | TAB ( r1, rbase, r1));
+ tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
+ }
+ else tcg_out32 (s, LDX | TAB (data_reg, rbase, r0));
+#else
+ if (bswap) {
+ tcg_out_movi32 (s, 0, 4);
+ tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
+ tcg_out32 (s, LWBRX | RT ( r1) | RA (r0));
+ tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
+ }
+ else tcg_out32 (s, LD | RT (data_reg) | RA (r0));
+#endif
+ break;
+ }
+
+#ifdef CONFIG_SOFTMMU
+ reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, r0, r1, rbase, data_reg, mem_index, bswap;
+#ifdef CONFIG_SOFTMMU
+ int r2;
+ void *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+
+#ifdef CONFIG_SOFTMMU
+ r0 = 3;
+ r1 = 4;
+ r2 = 0;
+ rbase = 0;
+
+ tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc,
+ offsetof (CPUState, tlb_table[mem_index][0].addr_write));
+
+ tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
+
+ label1_ptr = s->code_ptr;
+#ifdef FAST_PATH
+ tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
+#endif
+
+ /* slow path */
+ tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
+ tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc)));
+ tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index);
+
+ tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
+
+ label2_ptr = s->code_ptr;
+ tcg_out32 (s, B);
+
+ /* label1: fast path */
+#ifdef FAST_PATH
+ reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+#endif
+
+ tcg_out32 (s, (LD
+ | RT (r0)
+ | RA (r0)
+ | (offsetof (CPUTLBEntry, addend)
+ - offsetof (CPUTLBEntry, addr_write))
+ ));
+ /* r0 = env->tlb_table[mem_index][index].addend */
+ tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
+ /* r0 = env->tlb_table[mem_index][index].addend + addr */
+
+#else /* !CONFIG_SOFTMMU */
+#if TARGET_LONG_BITS == 32
+ tcg_out_rld (s, RLDICL, addr_reg, addr_reg, 0, 32);
+#endif
+ r1 = 3;
+ r0 = addr_reg;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 0;
+#else
+ bswap = 1;
+#endif
+ switch (opc) {
+ case 0:
+ tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
+ break;
+ case 1:
+ if (bswap)
+ tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, STHX | SAB (data_reg, rbase, r0));
+ break;
+ case 2:
+ if (bswap)
+ tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+ else
+ tcg_out32 (s, STWX | SAB (data_reg, rbase, r0));
+ break;
+ case 3:
+ if (bswap) {
+ tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
+ tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
+ tcg_out_rld (s, RLDICL, 0, data_reg, 32, 0);
+ tcg_out32 (s, STWBRX | SAB (0, rbase, r1));
+ }
+ else tcg_out32 (s, STDX | SAB (data_reg, rbase, r0));
+ break;
+ }
+
+#ifdef CONFIG_SOFTMMU
+ reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_target_qemu_prologue (TCGContext *s)
+{
+ int i, frame_size;
+#ifndef __APPLE__
+ uint64_t addr;
+#endif
+
+ frame_size = 0
+ + 8 /* back chain */
+ + 8 /* CR */
+ + 8 /* LR */
+ + 8 /* compiler doubleword */
+ + 8 /* link editor doubleword */
+ + 8 /* TOC save area */
+ + TCG_STATIC_CALL_ARGS_SIZE
+ + ARRAY_SIZE (tcg_target_callee_save_regs) * 8
+ ;
+ frame_size = (frame_size + 15) & ~15;
+
+#ifndef __APPLE__
+ /* First emit adhoc function descriptor */
+ addr = (uint64_t) s->code_ptr + 24;
+ tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */
+ s->code_ptr += 16; /* skip TOC and environment pointer */
+#endif
+
+ /* Prologue */
+ tcg_out32 (s, MFSPR | RT (0) | LR);
+ tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff));
+ for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+ tcg_out32 (s, (STD
+ | RS (tcg_target_callee_save_regs[i])
+ | RA (1)
+ | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
+ )
+ );
+ tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16));
+
+#ifdef CONFIG_USE_GUEST_BASE
+ if (GUEST_BASE) {
+ tcg_out_movi (s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+ }
+#endif
+
+ tcg_out32 (s, MTSPR | RS (3) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS);
+
+ /* Epilogue */
+ tb_ret_addr = s->code_ptr;
+
+ for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
+ tcg_out32 (s, (LD
+ | RT (tcg_target_callee_save_regs[i])
+ | RA (1)
+ | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
+ )
+ );
+ tcg_out32 (s, LD | RT (0) | RA (1) | (frame_size + 16));
+ tcg_out32 (s, MTSPR | RS (0) | LR);
+ tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size);
+ tcg_out32 (s, BCLR | BO_ALWAYS);
+}
+
+static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1,
+ tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32)
+ tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
+ else
+ tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX);
+}
+
+static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
+ tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32)
+ tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
+ else
+ tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX);
+}
+
+static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+ if (!si && rt == ra)
+ return;
+
+ if (si == (int16_t) si)
+ tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff));
+ else {
+ uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15);
+ tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h);
+ tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff));
+ }
+}
+
+static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si)
+{
+ /* XXX: suboptimal */
+ if (si == (int16_t) si
+ || ((((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0))
+ ppc_addi32 (s, rt, ra, si);
+ else {
+ tcg_out_movi (s, TCG_TYPE_I64, 0, si);
+ tcg_out32 (s, ADD | RT (rt) | RA (ra));
+ }
+}
+
+static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val)
+{
+ ppc_addi64 (s, reg, reg, val);
+}
+
+static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
+ int const_arg2, int cr, int arch64)
+{
+ int imm;
+ uint32_t op;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ if (const_arg2) {
+ if ((int16_t) arg2 == arg2) {
+ op = CMPI;
+ imm = 1;
+ break;
+ }
+ else if ((uint16_t) arg2 == arg2) {
+ op = CMPLI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMPL;
+ imm = 0;
+ break;
+
+ case TCG_COND_LT:
+ case TCG_COND_GE:
+ case TCG_COND_LE:
+ case TCG_COND_GT:
+ if (const_arg2) {
+ if ((int16_t) arg2 == arg2) {
+ op = CMPI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMP;
+ imm = 0;
+ break;
+
+ case TCG_COND_LTU:
+ case TCG_COND_GEU:
+ case TCG_COND_LEU:
+ case TCG_COND_GTU:
+ if (const_arg2) {
+ if ((uint16_t) arg2 == arg2) {
+ op = CMPLI;
+ imm = 1;
+ break;
+ }
+ }
+ op = CMPL;
+ imm = 0;
+ break;
+
+ default:
+ tcg_abort ();
+ }
+ op |= BF (cr) | (arch64 << 21);
+
+ if (imm)
+ tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff));
+ else {
+ if (const_arg2) {
+ tcg_out_movi (s, TCG_TYPE_I64, 0, arg2);
+ tcg_out32 (s, op | RA (arg1) | RB (0));
+ }
+ else
+ tcg_out32 (s, op | RA (arg1) | RB (arg2));
+ }
+
+}
+
+static void tcg_out_setcond (TCGContext *s, TCGType type, TCGCond cond,
+ TCGArg arg0, TCGArg arg1, TCGArg arg2,
+ int const_arg2)
+{
+ int crop, sh, arg;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ if (const_arg2) {
+ if (!arg2) {
+ arg = arg1;
+ }
+ else {
+ arg = 0;
+ if ((uint16_t) arg2 == arg2) {
+ tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+ }
+ else {
+ tcg_out_movi (s, type, 0, arg2);
+ tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+ }
+ }
+ }
+ else {
+ arg = 0;
+ tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+ }
+
+ if (type == TCG_TYPE_I64) {
+ tcg_out32 (s, CNTLZD | RS (arg) | RA (0));
+ tcg_out_rld (s, RLDICL, arg0, 0, 58, 6);
+ }
+ else {
+ tcg_out32 (s, CNTLZW | RS (arg) | RA (0));
+ tcg_out32 (s, (RLWINM
+ | RA (arg0)
+ | RS (0)
+ | SH (27)
+ | MB (5)
+ | ME (31)
+ )
+ );
+ }
+ break;
+
+ case TCG_COND_NE:
+ if (const_arg2) {
+ if (!arg2) {
+ arg = arg1;
+ }
+ else {
+ arg = 0;
+ if ((uint16_t) arg2 == arg2) {
+ tcg_out32 (s, XORI | RS (arg1) | RA (0) | arg2);
+ }
+ else {
+ tcg_out_movi (s, type, 0, arg2);
+ tcg_out32 (s, XOR | SAB (arg1, 0, 0));
+ }
+ }
+ }
+ else {
+ arg = 0;
+ tcg_out32 (s, XOR | SAB (arg1, 0, arg2));
+ }
+
+ if (arg == arg1 && arg1 == arg0) {
+ tcg_out32 (s, ADDIC | RT (0) | RA (arg) | 0xffff);
+ tcg_out32 (s, SUBFE | TAB (arg0, 0, arg));
+ }
+ else {
+ tcg_out32 (s, ADDIC | RT (arg0) | RA (arg) | 0xffff);
+ tcg_out32 (s, SUBFE | TAB (arg0, arg0, arg));
+ }
+ break;
+
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ sh = 30;
+ crop = 0;
+ goto crtest;
+
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ sh = 29;
+ crop = 0;
+ goto crtest;
+
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ sh = 31;
+ crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_LT) | BB (7, CR_LT);
+ goto crtest;
+
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ sh = 31;
+ crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_GT) | BB (7, CR_GT);
+ crtest:
+ tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, type == TCG_TYPE_I64);
+ if (crop) tcg_out32 (s, crop);
+ tcg_out32 (s, MFCR | RT (0));
+ tcg_out32 (s, (RLWINM
+ | RA (arg0)
+ | RS (0)
+ | SH (sh)
+ | MB (31)
+ | ME (31)
+ )
+ );
+ break;
+
+ default:
+ tcg_abort ();
+ }
+}
+
+static void tcg_out_bc (TCGContext *s, int bc, int label_index)
+{
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value)
+ tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value));
+ else {
+ uint16_t val = *(uint16_t *) &s->code_ptr[2];
+
+ /* Thanks to Andrzej Zaborowski */
+ tcg_out32 (s, bc | (val & 0xfffc));
+ tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0);
+ }
+}
+
+static void tcg_out_brcond (TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index, int arch64)
+{
+ tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7, arch64);
+ tcg_out_bc (s, tcg_to_bc[cond], label_index);
+}
+
+void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr)
+{
+ TCGContext s;
+ unsigned long patch_size;
+
+ s.code_ptr = (uint8_t *) jmp_addr;
+ tcg_out_b (&s, 0, addr);
+ patch_size = s.code_ptr - (uint8_t *) jmp_addr;
+ flush_icache_range (jmp_addr, jmp_addr + patch_size);
+}
+
+static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args)
+{
+ int c;
+
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]);
+ tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr);
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ s->code_ptr += 28;
+ }
+ else {
+ tcg_abort ();
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_br:
+ {
+ TCGLabel *l = &s->labels[args[0]];
+
+ if (l->has_value) {
+ tcg_out_b (s, 0, l->u.value);
+ }
+ else {
+ uint32_t val = *(uint32_t *) s->code_ptr;
+
+ /* Thanks to Andrzej Zaborowski */
+ tcg_out32 (s, B | (val & 0x3fffffc));
+ tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0);
+ }
+ }
+ break;
+ case INDEX_op_call:
+ tcg_out_call (s, args[0], const_args[0]);
+ break;
+ case INDEX_op_jmp:
+ if (const_args[0]) {
+ tcg_out_b (s, 0, args[0]);
+ }
+ else {
+ tcg_out32 (s, MTSPR | RS (args[0]) | CTR);
+ tcg_out32 (s, BCCTR | BO_ALWAYS);
+ }
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_movi_i64:
+ tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ld8u_i32:
+ case INDEX_op_ld8u_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+ break;
+ case INDEX_op_ld8s_i32:
+ case INDEX_op_ld8s_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+ tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0]));
+ break;
+ case INDEX_op_ld16u_i32:
+ case INDEX_op_ld16u_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX);
+ break;
+ case INDEX_op_ld16s_i32:
+ case INDEX_op_ld16s_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX);
+ break;
+ case INDEX_op_ld_i32:
+ case INDEX_op_ld32u_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX);
+ break;
+ case INDEX_op_st8_i32:
+ case INDEX_op_st8_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX);
+ break;
+ case INDEX_op_st16_i32:
+ case INDEX_op_st16_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX);
+ break;
+ case INDEX_op_st_i32:
+ case INDEX_op_st32_i64:
+ tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX);
+ break;
+
+ case INDEX_op_add_i32:
+ if (const_args[2])
+ ppc_addi32 (s, args[0], args[1], args[2]);
+ else
+ tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_sub_i32:
+ if (const_args[2])
+ ppc_addi32 (s, args[0], args[1], -args[2]);
+ else
+ tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+ break;
+
+ case INDEX_op_and_i64:
+ case INDEX_op_and_i32:
+ if (const_args[2]) {
+ if ((args[2] & 0xffff) == args[2])
+ tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]);
+ else if ((args[2] & 0xffff0000) == args[2])
+ tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ else {
+ tcg_out_movi (s, (opc == INDEX_op_and_i32
+ ? TCG_TYPE_I32
+ : TCG_TYPE_I64),
+ 0, args[2]);
+ tcg_out32 (s, AND | SAB (args[1], args[0], 0));
+ }
+ }
+ else
+ tcg_out32 (s, AND | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_or_i64:
+ case INDEX_op_or_i32:
+ if (const_args[2]) {
+ if (args[2] & 0xffff) {
+ tcg_out32 (s, ORI | RS (args[1]) | RA (args[0])
+ | (args[2] & 0xffff));
+ if (args[2] >> 16)
+ tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ }
+ else {
+ tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ }
+ }
+ else
+ tcg_out32 (s, OR | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_xor_i64:
+ case INDEX_op_xor_i32:
+ if (const_args[2]) {
+ if ((args[2] & 0xffff) == args[2])
+ tcg_out32 (s, XORI | RS (args[1]) | RA (args[0])
+ | (args[2] & 0xffff));
+ else if ((args[2] & 0xffff0000) == args[2])
+ tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0])
+ | ((args[2] >> 16) & 0xffff));
+ else {
+ tcg_out_movi (s, (opc == INDEX_op_and_i32
+ ? TCG_TYPE_I32
+ : TCG_TYPE_I64),
+ 0, args[2]);
+ tcg_out32 (s, XOR | SAB (args[1], args[0], 0));
+ }
+ }
+ else
+ tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
+ break;
+
+ case INDEX_op_mul_i32:
+ if (const_args[2]) {
+ if (args[2] == (int16_t) args[2])
+ tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1])
+ | (args[2] & 0xffff));
+ else {
+ tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+ tcg_out32 (s, MULLW | TAB (args[0], args[1], 0));
+ }
+ }
+ else
+ tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_div_i32:
+ tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_divu_i32:
+ tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2]));
+ break;
+
+ case INDEX_op_rem_i32:
+ tcg_out32 (s, DIVW | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+
+ case INDEX_op_remu_i32:
+ tcg_out32 (s, DIVWU | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLW | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+
+ case INDEX_op_shl_i32:
+ if (const_args[2]) {
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (args[2])
+ | MB (0)
+ | ME (31 - args[2])
+ )
+ );
+ }
+ else
+ tcg_out32 (s, SLW | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_shr_i32:
+ if (const_args[2]) {
+ tcg_out32 (s, (RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (32 - args[2])
+ | MB (args[2])
+ | ME (31)
+ )
+ );
+ }
+ else
+ tcg_out32 (s, SRW | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_sar_i32:
+ if (const_args[2])
+ tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2]));
+ else
+ tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 0);
+ break;
+
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3], 1);
+ break;
+
+ case INDEX_op_neg_i32:
+ case INDEX_op_neg_i64:
+ tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
+ break;
+
+ case INDEX_op_add_i64:
+ if (const_args[2])
+ ppc_addi64 (s, args[0], args[1], args[2]);
+ else
+ tcg_out32 (s, ADD | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_sub_i64:
+ if (const_args[2])
+ ppc_addi64 (s, args[0], args[1], -args[2]);
+ else
+ tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1]));
+ break;
+
+ case INDEX_op_shl_i64:
+ if (const_args[2])
+ tcg_out_rld (s, RLDICR, args[0], args[1], args[2], 63 - args[2]);
+ else
+ tcg_out32 (s, SLD | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_shr_i64:
+ if (const_args[2])
+ tcg_out_rld (s, RLDICL, args[0], args[1], 64 - args[2], args[2]);
+ else
+ tcg_out32 (s, SRD | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_sar_i64:
+ if (const_args[2]) {
+ int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1);
+ tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh);
+ }
+ else
+ tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2]));
+ break;
+
+ case INDEX_op_mul_i64:
+ tcg_out32 (s, MULLD | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_div_i64:
+ tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_divu_i64:
+ tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2]));
+ break;
+ case INDEX_op_rem_i64:
+ tcg_out32 (s, DIVD | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLD | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+ case INDEX_op_remu_i64:
+ tcg_out32 (s, DIVDU | TAB (0, args[1], args[2]));
+ tcg_out32 (s, MULLD | TAB (0, 0, args[2]));
+ tcg_out32 (s, SUBF | TAB (args[0], 0, args[1]));
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld (s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld (s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld (s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld (s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+ case INDEX_op_qemu_ld32u:
+ tcg_out_qemu_ld (s, args, 2);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld (s, args, 2 | 4);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld (s, args, 3);
+ break;
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st (s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st (s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st (s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st (s, args, 3);
+ break;
+
+ case INDEX_op_ext8s_i32:
+ case INDEX_op_ext8s_i64:
+ c = EXTSB;
+ goto gen_ext;
+ case INDEX_op_ext16s_i32:
+ case INDEX_op_ext16s_i64:
+ c = EXTSH;
+ goto gen_ext;
+ case INDEX_op_ext32s_i64:
+ c = EXTSW;
+ goto gen_ext;
+ gen_ext:
+ tcg_out32 (s, c | RS (args[1]) | RA (args[0]));
+ break;
+
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond (s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
+ const_args[2]);
+ break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond (s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
+ const_args[2]);
+ break;
+
+ default:
+ tcg_dump_ops (s, stderr);
+ tcg_abort ();
+ }
+}
+
+static const TCGTargetOpDef ppc_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "r", "ri" } },
+ { INDEX_op_mul_i32, { "r", "r", "ri" } },
+ { INDEX_op_div_i32, { "r", "r", "r" } },
+ { INDEX_op_divu_i32, { "r", "r", "r" } },
+ { INDEX_op_rem_i32, { "r", "r", "r" } },
+ { INDEX_op_remu_i32, { "r", "r", "r" } },
+ { INDEX_op_sub_i32, { "r", "r", "ri" } },
+ { INDEX_op_and_i32, { "r", "r", "ri" } },
+ { INDEX_op_or_i32, { "r", "r", "ri" } },
+ { INDEX_op_xor_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_shl_i32, { "r", "r", "ri" } },
+ { INDEX_op_shr_i32, { "r", "r", "ri" } },
+ { INDEX_op_sar_i32, { "r", "r", "ri" } },
+
+ { INDEX_op_brcond_i32, { "r", "ri" } },
+ { INDEX_op_brcond_i64, { "r", "ri" } },
+
+ { INDEX_op_neg_i32, { "r", "r" } },
+
+ { INDEX_op_add_i64, { "r", "r", "ri" } },
+ { INDEX_op_sub_i64, { "r", "r", "ri" } },
+ { INDEX_op_and_i64, { "r", "r", "rZ" } },
+ { INDEX_op_or_i64, { "r", "r", "rZ" } },
+ { INDEX_op_xor_i64, { "r", "r", "rZ" } },
+
+ { INDEX_op_shl_i64, { "r", "r", "ri" } },
+ { INDEX_op_shr_i64, { "r", "r", "ri" } },
+ { INDEX_op_sar_i64, { "r", "r", "ri" } },
+
+ { INDEX_op_mul_i64, { "r", "r", "r" } },
+ { INDEX_op_div_i64, { "r", "r", "r" } },
+ { INDEX_op_divu_i64, { "r", "r", "r" } },
+ { INDEX_op_rem_i64, { "r", "r", "r" } },
+ { INDEX_op_remu_i64, { "r", "r", "r" } },
+
+ { INDEX_op_neg_i64, { "r", "r" } },
+
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "S", "S" } },
+ { INDEX_op_qemu_st16, { "S", "S" } },
+ { INDEX_op_qemu_st32, { "S", "S" } },
+ { INDEX_op_qemu_st64, { "S", "S" } },
+
+ { INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext8s_i64, { "r", "r" } },
+ { INDEX_op_ext16s_i64, { "r", "r" } },
+ { INDEX_op_ext32s_i64, { "r", "r" } },
+
+ { INDEX_op_setcond_i32, { "r", "r", "ri" } },
+ { INDEX_op_setcond_i64, { "r", "r", "ri" } },
+
+ { -1 },
+};
+
+static void tcg_target_init (TCGContext *s)
+{
+ tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+ tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+ tcg_regset_set32 (tcg_target_call_clobber_regs, 0,
+ (1 << TCG_REG_R0) |
+#ifdef __APPLE__
+ (1 << TCG_REG_R2) |
+#endif
+ (1 << TCG_REG_R3) |
+ (1 << TCG_REG_R4) |
+ (1 << TCG_REG_R5) |
+ (1 << TCG_REG_R6) |
+ (1 << TCG_REG_R7) |
+ (1 << TCG_REG_R8) |
+ (1 << TCG_REG_R9) |
+ (1 << TCG_REG_R10) |
+ (1 << TCG_REG_R11) |
+ (1 << TCG_REG_R12)
+ );
+
+ tcg_regset_clear (s->reserved_regs);
+ tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0);
+ tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1);
+#ifndef __APPLE__
+ tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2);
+#endif
+ tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13);
+
+ tcg_add_target_add_op_defs (ppc_op_defs);
+}
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
new file mode 100644
index 0000000..8a6db11
--- /dev/null
+++ b/tcg/ppc64/tcg-target.h
@@ -0,0 +1,109 @@
+/*
+ * 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_PPC64 1
+
+#define TCG_TARGET_REG_BITS 64
+#define TCG_TARGET_WORDS_BIGENDIAN
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R16,
+ TCG_REG_R17,
+ TCG_REG_R18,
+ TCG_REG_R19,
+ TCG_REG_R20,
+ TCG_REG_R21,
+ TCG_REG_R22,
+ TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27,
+ TCG_REG_R28,
+ TCG_REG_R29,
+ TCG_REG_R30,
+ TCG_REG_R31
+};
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R1
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 48
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+/* #define TCG_TARGET_HAS_rot_i32 */
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+/* #define TCG_TARGET_HAS_ext8u_i32 */
+/* #define TCG_TARGET_HAS_ext16u_i32 */
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+/* #define TCG_TARGET_HAS_not_i32 */
+#define TCG_TARGET_HAS_neg_i32
+/* #define TCG_TARGET_HAS_andc_i32 */
+/* #define TCG_TARGET_HAS_orc_i32 */
+/* #define TCG_TARGET_HAS_eqv_i32 */
+/* #define TCG_TARGET_HAS_nand_i32 */
+/* #define TCG_TARGET_HAS_nor_i32 */
+
+#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i64 */
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+/* #define TCG_TARGET_HAS_ext8u_i64 */
+/* #define TCG_TARGET_HAS_ext16u_i64 */
+/* #define TCG_TARGET_HAS_ext32u_i64 */
+/* #define TCG_TARGET_HAS_bswap16_i64 */
+/* #define TCG_TARGET_HAS_bswap32_i64 */
+/* #define TCG_TARGET_HAS_bswap64_i64 */
+/* #define TCG_TARGET_HAS_not_i64 */
+#define TCG_TARGET_HAS_neg_i64
+/* #define TCG_TARGET_HAS_andc_i64 */
+/* #define TCG_TARGET_HAS_orc_i64 */
+/* #define TCG_TARGET_HAS_eqv_i64 */
+/* #define TCG_TARGET_HAS_nand_i64 */
+/* #define TCG_TARGET_HAS_nor_i64 */
+
+#define TCG_AREG0 TCG_REG_R27
+
+#define TCG_TARGET_HAS_GUEST_BASE
+#define TCG_TARGET_EXTEND_ARGS 1
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
new file mode 100644
index 0000000..450fcab
--- /dev/null
+++ b/tcg/s390/tcg-target.c
@@ -0,0 +1,2324 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009 Ulrich Hecht <uli@suse.de>
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ * Copyright (c) 2010 Richard Henderson <rth@twiddle.net>
+ *
+ * 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.
+ */
+
+/* ??? The translation blocks produced by TCG are generally small enough to
+ be entirely reachable with a 16-bit displacement. Leaving the option for
+ a 32-bit displacement here Just In Case. */
+#define USE_LONG_BRANCHES 0
+
+#define TCG_CT_CONST_32 0x0100
+#define TCG_CT_CONST_NEG 0x0200
+#define TCG_CT_CONST_ADDI 0x0400
+#define TCG_CT_CONST_MULI 0x0800
+#define TCG_CT_CONST_ANDI 0x1000
+#define TCG_CT_CONST_ORI 0x2000
+#define TCG_CT_CONST_XORI 0x4000
+#define TCG_CT_CONST_CMPI 0x8000
+
+/* Several places within the instruction set 0 means "no register"
+ rather than TCG_REG_R0. */
+#define TCG_REG_NONE 0
+
+/* A scratch register that may be be used throughout the backend. */
+#define TCG_TMP0 TCG_REG_R14
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG TCG_REG_R13
+#else
+#define TCG_GUEST_BASE_REG TCG_REG_R0
+#endif
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+
+/* All of the following instructions are prefixed with their instruction
+ format, and are defined as 8- or 16-bit quantities, even when the two
+ halves of the 16-bit quantity may appear 32 bits apart in the insn.
+ This makes it easy to copy the values from the tables in Appendix B. */
+typedef enum S390Opcode {
+ RIL_AFI = 0xc209,
+ RIL_AGFI = 0xc208,
+ RIL_ALGFI = 0xc20a,
+ RIL_BRASL = 0xc005,
+ RIL_BRCL = 0xc004,
+ RIL_CFI = 0xc20d,
+ RIL_CGFI = 0xc20c,
+ RIL_CLFI = 0xc20f,
+ RIL_CLGFI = 0xc20e,
+ RIL_IIHF = 0xc008,
+ RIL_IILF = 0xc009,
+ RIL_LARL = 0xc000,
+ RIL_LGFI = 0xc001,
+ RIL_LGRL = 0xc408,
+ RIL_LLIHF = 0xc00e,
+ RIL_LLILF = 0xc00f,
+ RIL_LRL = 0xc40d,
+ RIL_MSFI = 0xc201,
+ RIL_MSGFI = 0xc200,
+ RIL_NIHF = 0xc00a,
+ RIL_NILF = 0xc00b,
+ RIL_OIHF = 0xc00c,
+ RIL_OILF = 0xc00d,
+ RIL_XIHF = 0xc006,
+ RIL_XILF = 0xc007,
+
+ RI_AGHI = 0xa70b,
+ RI_AHI = 0xa70a,
+ RI_BRC = 0xa704,
+ RI_IIHH = 0xa500,
+ RI_IIHL = 0xa501,
+ RI_IILH = 0xa502,
+ RI_IILL = 0xa503,
+ RI_LGHI = 0xa709,
+ RI_LLIHH = 0xa50c,
+ RI_LLIHL = 0xa50d,
+ RI_LLILH = 0xa50e,
+ RI_LLILL = 0xa50f,
+ RI_MGHI = 0xa70d,
+ RI_MHI = 0xa70c,
+ RI_NIHH = 0xa504,
+ RI_NIHL = 0xa505,
+ RI_NILH = 0xa506,
+ RI_NILL = 0xa507,
+ RI_OIHH = 0xa508,
+ RI_OIHL = 0xa509,
+ RI_OILH = 0xa50a,
+ RI_OILL = 0xa50b,
+
+ RIE_CGIJ = 0xec7c,
+ RIE_CGRJ = 0xec64,
+ RIE_CIJ = 0xec7e,
+ RIE_CLGRJ = 0xec65,
+ RIE_CLIJ = 0xec7f,
+ RIE_CLGIJ = 0xec7d,
+ RIE_CLRJ = 0xec77,
+ RIE_CRJ = 0xec76,
+
+ RRE_AGR = 0xb908,
+ RRE_CGR = 0xb920,
+ RRE_CLGR = 0xb921,
+ RRE_DLGR = 0xb987,
+ RRE_DLR = 0xb997,
+ RRE_DSGFR = 0xb91d,
+ RRE_DSGR = 0xb90d,
+ RRE_LGBR = 0xb906,
+ RRE_LCGR = 0xb903,
+ RRE_LGFR = 0xb914,
+ RRE_LGHR = 0xb907,
+ RRE_LGR = 0xb904,
+ RRE_LLGCR = 0xb984,
+ RRE_LLGFR = 0xb916,
+ RRE_LLGHR = 0xb985,
+ RRE_LRVR = 0xb91f,
+ RRE_LRVGR = 0xb90f,
+ RRE_LTGR = 0xb902,
+ RRE_MSGR = 0xb90c,
+ RRE_MSR = 0xb252,
+ RRE_NGR = 0xb980,
+ RRE_OGR = 0xb981,
+ RRE_SGR = 0xb909,
+ RRE_XGR = 0xb982,
+
+ RR_AR = 0x1a,
+ RR_BASR = 0x0d,
+ RR_BCR = 0x07,
+ RR_CLR = 0x15,
+ RR_CR = 0x19,
+ RR_DR = 0x1d,
+ RR_LCR = 0x13,
+ RR_LR = 0x18,
+ RR_LTR = 0x12,
+ RR_NR = 0x14,
+ RR_OR = 0x16,
+ RR_SR = 0x1b,
+ RR_XR = 0x17,
+
+ RSY_RLL = 0xeb1d,
+ RSY_RLLG = 0xeb1c,
+ RSY_SLLG = 0xeb0d,
+ RSY_SRAG = 0xeb0a,
+ RSY_SRLG = 0xeb0c,
+
+ RS_SLL = 0x89,
+ RS_SRA = 0x8a,
+ RS_SRL = 0x88,
+
+ RXY_AG = 0xe308,
+ RXY_AY = 0xe35a,
+ RXY_CG = 0xe320,
+ RXY_CY = 0xe359,
+ RXY_LB = 0xe376,
+ RXY_LG = 0xe304,
+ RXY_LGB = 0xe377,
+ RXY_LGF = 0xe314,
+ RXY_LGH = 0xe315,
+ RXY_LHY = 0xe378,
+ RXY_LLGC = 0xe390,
+ RXY_LLGF = 0xe316,
+ RXY_LLGH = 0xe391,
+ RXY_LMG = 0xeb04,
+ RXY_LRV = 0xe31e,
+ RXY_LRVG = 0xe30f,
+ RXY_LRVH = 0xe31f,
+ RXY_LY = 0xe358,
+ RXY_STCY = 0xe372,
+ RXY_STG = 0xe324,
+ RXY_STHY = 0xe370,
+ RXY_STMG = 0xeb24,
+ RXY_STRV = 0xe33e,
+ RXY_STRVG = 0xe32f,
+ RXY_STRVH = 0xe33f,
+ RXY_STY = 0xe350,
+
+ RX_A = 0x5a,
+ RX_C = 0x59,
+ RX_L = 0x58,
+ RX_LH = 0x48,
+ RX_ST = 0x50,
+ RX_STC = 0x42,
+ RX_STH = 0x40,
+} S390Opcode;
+
+#define LD_SIGNED 0x04
+#define LD_UINT8 0x00
+#define LD_INT8 (LD_UINT8 | LD_SIGNED)
+#define LD_UINT16 0x01
+#define LD_INT16 (LD_UINT16 | LD_SIGNED)
+#define LD_UINT32 0x02
+#define LD_INT32 (LD_UINT32 | LD_SIGNED)
+#define LD_UINT64 0x03
+#define LD_INT64 (LD_UINT64 | LD_SIGNED)
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
+ "%r8", "%r9", "%r10" "%r11" "%r12" "%r13" "%r14" "%r15"
+};
+#endif
+
+/* Since R6 is a potential argument register, choose it last of the
+ call-saved registers. Likewise prefer the call-clobbered registers
+ in reverse order to maximize the chance of avoiding the arguments. */
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_R13,
+ TCG_REG_R12,
+ TCG_REG_R11,
+ TCG_REG_R10,
+ TCG_REG_R9,
+ TCG_REG_R8,
+ TCG_REG_R7,
+ TCG_REG_R6,
+ TCG_REG_R14,
+ TCG_REG_R0,
+ TCG_REG_R1,
+ TCG_REG_R5,
+ TCG_REG_R4,
+ TCG_REG_R3,
+ TCG_REG_R2,
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+};
+
+static const int tcg_target_call_oarg_regs[] = {
+ TCG_REG_R2,
+ TCG_REG_R3,
+};
+
+#define S390_CC_EQ 8
+#define S390_CC_LT 4
+#define S390_CC_GT 2
+#define S390_CC_OV 1
+#define S390_CC_NE (S390_CC_LT | S390_CC_GT)
+#define S390_CC_LE (S390_CC_LT | S390_CC_EQ)
+#define S390_CC_GE (S390_CC_GT | S390_CC_EQ)
+#define S390_CC_NEVER 0
+#define S390_CC_ALWAYS 15
+
+/* Condition codes that result from a COMPARE and COMPARE LOGICAL. */
+static const uint8_t tcg_cond_to_s390_cond[10] = {
+ [TCG_COND_EQ] = S390_CC_EQ,
+ [TCG_COND_NE] = S390_CC_NE,
+ [TCG_COND_LT] = S390_CC_LT,
+ [TCG_COND_LE] = S390_CC_LE,
+ [TCG_COND_GT] = S390_CC_GT,
+ [TCG_COND_GE] = S390_CC_GE,
+ [TCG_COND_LTU] = S390_CC_LT,
+ [TCG_COND_LEU] = S390_CC_LE,
+ [TCG_COND_GTU] = S390_CC_GT,
+ [TCG_COND_GEU] = S390_CC_GE,
+};
+
+/* Condition codes that result from a LOAD AND TEST. Here, we have no
+ unsigned instruction variation, however since the test is vs zero we
+ can re-map the outcomes appropriately. */
+static const uint8_t tcg_cond_to_ltr_cond[10] = {
+ [TCG_COND_EQ] = S390_CC_EQ,
+ [TCG_COND_NE] = S390_CC_NE,
+ [TCG_COND_LT] = S390_CC_LT,
+ [TCG_COND_LE] = S390_CC_LE,
+ [TCG_COND_GT] = S390_CC_GT,
+ [TCG_COND_GE] = S390_CC_GE,
+ [TCG_COND_LTU] = S390_CC_NEVER,
+ [TCG_COND_LEU] = S390_CC_EQ,
+ [TCG_COND_GTU] = S390_CC_NE,
+ [TCG_COND_GEU] = S390_CC_ALWAYS,
+};
+
+#ifdef CONFIG_SOFTMMU
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+#endif
+
+static uint8_t *tb_ret_addr;
+
+/* A list of relevant facilities used by this translator. Some of these
+ are required for proper operation, and these are checked at startup. */
+
+#define FACILITY_ZARCH_ACTIVE (1ULL << (63 - 2))
+#define FACILITY_LONG_DISP (1ULL << (63 - 18))
+#define FACILITY_EXT_IMM (1ULL << (63 - 21))
+#define FACILITY_GEN_INST_EXT (1ULL << (63 - 34))
+
+static uint64_t facilities;
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ tcg_target_long code_ptr_tl = (tcg_target_long)code_ptr;
+ tcg_target_long pcrel2;
+
+ /* ??? Not the usual definition of "addend". */
+ pcrel2 = (value - (code_ptr_tl + addend)) >> 1;
+
+ switch (type) {
+ case R_390_PC16DBL:
+ assert(pcrel2 == (int16_t)pcrel2);
+ *(int16_t *)code_ptr = pcrel2;
+ break;
+ case R_390_PC32DBL:
+ assert(pcrel2 == (int32_t)pcrel2);
+ *(int32_t *)code_ptr = pcrel2;
+ break;
+ default:
+ tcg_abort();
+ break;
+ }
+}
+
+static int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return sizeof(tcg_target_call_iarg_regs) / sizeof(int);
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str = *pct_str;
+
+ switch (ct_str[0]) {
+ case 'r': /* all registers */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ break;
+ case 'R': /* not R0 */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
+ break;
+ case 'L': /* qemu_ld/st constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R2);
+ tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+ break;
+ case 'a': /* force R2 for division */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_clear(ct->u.regs);
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_R2);
+ break;
+ case 'b': /* force R3 for division */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_clear(ct->u.regs);
+ tcg_regset_set_reg(ct->u.regs, TCG_REG_R3);
+ break;
+ case 'N': /* force immediate negate */
+ ct->ct |= TCG_CT_CONST_NEG;
+ break;
+ case 'W': /* force 32-bit ("word") immediate */
+ ct->ct |= TCG_CT_CONST_32;
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_ADDI;
+ break;
+ case 'K':
+ ct->ct |= TCG_CT_CONST_MULI;
+ break;
+ case 'A':
+ ct->ct |= TCG_CT_CONST_ANDI;
+ break;
+ case 'O':
+ ct->ct |= TCG_CT_CONST_ORI;
+ break;
+ case 'X':
+ ct->ct |= TCG_CT_CONST_XORI;
+ break;
+ case 'C':
+ ct->ct |= TCG_CT_CONST_CMPI;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+
+ return 0;
+}
+
+/* Immediates to be used with logical AND. This is an optimization only,
+ since a full 64-bit immediate AND can always be performed with 4 sequential
+ NI[LH][LH] instructions. What we're looking for is immediates that we
+ can load efficiently, and the immediate load plus the reg-reg AND is
+ smaller than the sequential NI's. */
+
+static int tcg_match_andi(int ct, tcg_target_ulong val)
+{
+ int i;
+
+ if (facilities & FACILITY_EXT_IMM) {
+ if (ct & TCG_CT_CONST_32) {
+ /* All 32-bit ANDs can be performed with 1 48-bit insn. */
+ return 1;
+ }
+
+ /* Zero-extensions. */
+ if (val == 0xff || val == 0xffff || val == 0xffffffff) {
+ return 1;
+ }
+ } else {
+ if (ct & TCG_CT_CONST_32) {
+ val = (uint32_t)val;
+ } else if (val == 0xffffffff) {
+ return 1;
+ }
+ }
+
+ /* Try all 32-bit insns that can perform it in one go. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = ~(0xffffull << i*16);
+ if ((val & mask) == mask) {
+ return 1;
+ }
+ }
+
+ /* Look for 16-bit values performing the mask. These are better
+ to load with LLI[LH][LH]. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = 0xffffull << i*16;
+ if ((val & mask) == val) {
+ return 0;
+ }
+ }
+
+ /* Look for 32-bit values performing the 64-bit mask. These
+ are better to load with LLI[LH]F, or if extended immediates
+ not available, with a pair of LLI insns. */
+ if ((ct & TCG_CT_CONST_32) == 0) {
+ if (val <= 0xffffffff || (val & 0xffffffff) == 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Immediates to be used with logical OR. This is an optimization only,
+ since a full 64-bit immediate OR can always be performed with 4 sequential
+ OI[LH][LH] instructions. What we're looking for is immediates that we
+ can load efficiently, and the immediate load plus the reg-reg OR is
+ smaller than the sequential OI's. */
+
+static int tcg_match_ori(int ct, tcg_target_long val)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ if (ct & TCG_CT_CONST_32) {
+ /* All 32-bit ORs can be performed with 1 48-bit insn. */
+ return 1;
+ }
+ }
+
+ /* Look for negative values. These are best to load with LGHI. */
+ if (val < 0) {
+ if (val == (int16_t)val) {
+ return 0;
+ }
+ if (facilities & FACILITY_EXT_IMM) {
+ if (val == (int32_t)val) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* Immediates to be used with logical XOR. This is almost, but not quite,
+ only an optimization. XOR with immediate is only supported with the
+ extended-immediate facility. That said, there are a few patterns for
+ which it is better to load the value into a register first. */
+
+static int tcg_match_xori(int ct, tcg_target_long val)
+{
+ if ((facilities & FACILITY_EXT_IMM) == 0) {
+ return 0;
+ }
+
+ if (ct & TCG_CT_CONST_32) {
+ /* All 32-bit XORs can be performed with 1 48-bit insn. */
+ return 1;
+ }
+
+ /* Look for negative values. These are best to load with LGHI. */
+ if (val < 0 && val == (int32_t)val) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Imediates to be used with comparisons. */
+
+static int tcg_match_cmpi(int ct, tcg_target_long val)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ /* The COMPARE IMMEDIATE instruction is available. */
+ if (ct & TCG_CT_CONST_32) {
+ /* We have a 32-bit immediate and can compare against anything. */
+ return 1;
+ } else {
+ /* ??? We have no insight here into whether the comparison is
+ signed or unsigned. The COMPARE IMMEDIATE insn uses a 32-bit
+ signed immediate, and the COMPARE LOGICAL IMMEDIATE insn uses
+ a 32-bit unsigned immediate. If we were to use the (semi)
+ obvious "val == (int32_t)val" we would be enabling unsigned
+ comparisons vs very large numbers. The only solution is to
+ take the intersection of the ranges. */
+ /* ??? Another possible solution is to simply lie and allow all
+ constants here and force the out-of-range values into a temp
+ register in tgen_cmp when we have knowledge of the actual
+ comparison code in use. */
+ return val >= 0 && val <= 0x7fffffff;
+ }
+ } else {
+ /* Only the LOAD AND TEST instruction is available. */
+ return val == 0;
+ }
+}
+
+/* Test if a constant matches the constraint. */
+static int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct = arg_ct->ct;
+
+ if (ct & TCG_CT_CONST) {
+ return 1;
+ }
+
+ /* Handle the modifiers. */
+ if (ct & TCG_CT_CONST_NEG) {
+ val = -val;
+ }
+ if (ct & TCG_CT_CONST_32) {
+ val = (int32_t)val;
+ }
+
+ /* The following are mutually exclusive. */
+ if (ct & TCG_CT_CONST_ADDI) {
+ /* Immediates that may be used with add. If we have the
+ extended-immediates facility then we have ADD IMMEDIATE
+ with signed and unsigned 32-bit, otherwise we have only
+ ADD HALFWORD IMMEDIATE with a signed 16-bit. */
+ if (facilities & FACILITY_EXT_IMM) {
+ return val == (int32_t)val || val == (uint32_t)val;
+ } else {
+ return val == (int16_t)val;
+ }
+ } else if (ct & TCG_CT_CONST_MULI) {
+ /* Immediates that may be used with multiply. If we have the
+ general-instruction-extensions, then we have MULTIPLY SINGLE
+ IMMEDIATE with a signed 32-bit, otherwise we have only
+ MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */
+ if (facilities & FACILITY_GEN_INST_EXT) {
+ return val == (int32_t)val;
+ } else {
+ return val == (int16_t)val;
+ }
+ } else if (ct & TCG_CT_CONST_ANDI) {
+ return tcg_match_andi(ct, val);
+ } else if (ct & TCG_CT_CONST_ORI) {
+ return tcg_match_ori(ct, val);
+ } else if (ct & TCG_CT_CONST_XORI) {
+ return tcg_match_xori(ct, val);
+ } else if (ct & TCG_CT_CONST_CMPI) {
+ return tcg_match_cmpi(ct, val);
+ }
+
+ return 0;
+}
+
+/* Emit instructions according to the given instruction format. */
+
+static void tcg_out_insn_RR(TCGContext *s, S390Opcode op, TCGReg r1, TCGReg r2)
+{
+ tcg_out16(s, (op << 8) | (r1 << 4) | r2);
+}
+
+static void tcg_out_insn_RRE(TCGContext *s, S390Opcode op,
+ TCGReg r1, TCGReg r2)
+{
+ tcg_out32(s, (op << 16) | (r1 << 4) | r2);
+}
+
+static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
+{
+ tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff));
+}
+
+static void tcg_out_insn_RIL(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
+{
+ tcg_out16(s, op | (r1 << 4));
+ tcg_out32(s, i2);
+}
+
+static void tcg_out_insn_RS(TCGContext *s, S390Opcode op, TCGReg r1,
+ TCGReg b2, TCGReg r3, int disp)
+{
+ tcg_out32(s, (op << 24) | (r1 << 20) | (r3 << 16) | (b2 << 12)
+ | (disp & 0xfff));
+}
+
+static void tcg_out_insn_RSY(TCGContext *s, S390Opcode op, TCGReg r1,
+ TCGReg b2, TCGReg r3, int disp)
+{
+ tcg_out16(s, (op & 0xff00) | (r1 << 4) | r3);
+ tcg_out32(s, (op & 0xff) | (b2 << 28)
+ | ((disp & 0xfff) << 16) | ((disp & 0xff000) >> 4));
+}
+
+#define tcg_out_insn_RX tcg_out_insn_RS
+#define tcg_out_insn_RXY tcg_out_insn_RSY
+
+/* Emit an opcode with "type-checking" of the format. */
+#define tcg_out_insn(S, FMT, OP, ...) \
+ glue(tcg_out_insn_,FMT)(S, glue(glue(FMT,_),OP), ## __VA_ARGS__)
+
+
+/* emit 64-bit shifts */
+static void tcg_out_sh64(TCGContext* s, S390Opcode op, TCGReg dest,
+ TCGReg src, TCGReg sh_reg, int sh_imm)
+{
+ tcg_out_insn_RSY(s, op, dest, sh_reg, src, sh_imm);
+}
+
+/* emit 32-bit shifts */
+static void tcg_out_sh32(TCGContext* s, S390Opcode op, TCGReg dest,
+ TCGReg sh_reg, int sh_imm)
+{
+ tcg_out_insn_RS(s, op, dest, sh_reg, 0, sh_imm);
+}
+
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
+{
+ if (src != dst) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, LR, dst, src);
+ } else {
+ tcg_out_insn(s, RRE, LGR, dst, src);
+ }
+ }
+}
+
+/* load a register with an immediate value */
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ TCGReg ret, tcg_target_long sval)
+{
+ static const S390Opcode lli_insns[4] = {
+ RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH
+ };
+
+ tcg_target_ulong uval = sval;
+ int i;
+
+ if (type == TCG_TYPE_I32) {
+ uval = (uint32_t)sval;
+ sval = (int32_t)sval;
+ }
+
+ /* Try all 32-bit insns that can load it in one go. */
+ if (sval >= -0x8000 && sval < 0x8000) {
+ tcg_out_insn(s, RI, LGHI, ret, sval);
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ tcg_target_long mask = 0xffffull << i*16;
+ if ((uval & mask) == uval) {
+ tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16);
+ return;
+ }
+ }
+
+ /* Try all 48-bit insns that can load it in one go. */
+ if (facilities & FACILITY_EXT_IMM) {
+ if (sval == (int32_t)sval) {
+ tcg_out_insn(s, RIL, LGFI, ret, sval);
+ return;
+ }
+ if (uval <= 0xffffffff) {
+ tcg_out_insn(s, RIL, LLILF, ret, uval);
+ return;
+ }
+ if ((uval & 0xffffffff) == 0) {
+ tcg_out_insn(s, RIL, LLIHF, ret, uval >> 31 >> 1);
+ return;
+ }
+ }
+
+ /* Try for PC-relative address load. */
+ if ((sval & 1) == 0) {
+ intptr_t off = (sval - (intptr_t)s->code_ptr) >> 1;
+ if (off == (int32_t)off) {
+ tcg_out_insn(s, RIL, LARL, ret, off);
+ return;
+ }
+ }
+
+ /* If extended immediates are not present, then we may have to issue
+ several instructions to load the low 32 bits. */
+ if (!(facilities & FACILITY_EXT_IMM)) {
+ /* A 32-bit unsigned value can be loaded in 2 insns. And given
+ that the lli_insns loop above did not succeed, we know that
+ both insns are required. */
+ if (uval <= 0xffffffff) {
+ tcg_out_insn(s, RI, LLILL, ret, uval);
+ tcg_out_insn(s, RI, IILH, ret, uval >> 16);
+ return;
+ }
+
+ /* If all high bits are set, the value can be loaded in 2 or 3 insns.
+ We first want to make sure that all the high bits get set. With
+ luck the low 16-bits can be considered negative to perform that for
+ free, otherwise we load an explicit -1. */
+ if (sval >> 31 >> 1 == -1) {
+ if (uval & 0x8000) {
+ tcg_out_insn(s, RI, LGHI, ret, uval);
+ } else {
+ tcg_out_insn(s, RI, LGHI, ret, -1);
+ tcg_out_insn(s, RI, IILL, ret, uval);
+ }
+ tcg_out_insn(s, RI, IILH, ret, uval >> 16);
+ return;
+ }
+ }
+
+ /* If we get here, both the high and low parts have non-zero bits. */
+
+ /* Recurse to load the lower 32-bits. */
+ tcg_out_movi(s, TCG_TYPE_I32, ret, sval);
+
+ /* Insert data into the high 32-bits. */
+ uval = uval >> 31 >> 1;
+ if (facilities & FACILITY_EXT_IMM) {
+ if (uval < 0x10000) {
+ tcg_out_insn(s, RI, IIHL, ret, uval);
+ } else if ((uval & 0xffff) == 0) {
+ tcg_out_insn(s, RI, IIHH, ret, uval >> 16);
+ } else {
+ tcg_out_insn(s, RIL, IIHF, ret, uval);
+ }
+ } else {
+ if (uval & 0xffff) {
+ tcg_out_insn(s, RI, IIHL, ret, uval);
+ }
+ if (uval & 0xffff0000) {
+ tcg_out_insn(s, RI, IIHH, ret, uval >> 16);
+ }
+ }
+}
+
+
+/* Emit a load/store type instruction. Inputs are:
+ DATA: The register to be loaded or stored.
+ BASE+OFS: The effective address.
+ OPC_RX: If the operation has an RX format opcode (e.g. STC), otherwise 0.
+ OPC_RXY: The RXY format opcode for the operation (e.g. STCY). */
+
+static void tcg_out_mem(TCGContext *s, S390Opcode opc_rx, S390Opcode opc_rxy,
+ TCGReg data, TCGReg base, TCGReg index,
+ tcg_target_long ofs)
+{
+ if (ofs < -0x80000 || ofs >= 0x80000) {
+ /* Combine the low 16 bits of the offset with the actual load insn;
+ the high 48 bits must come from an immediate load. */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, ofs & ~0xffff);
+ ofs &= 0xffff;
+
+ /* If we were already given an index register, add it in. */
+ if (index != TCG_REG_NONE) {
+ tcg_out_insn(s, RRE, AGR, TCG_TMP0, index);
+ }
+ index = TCG_TMP0;
+ }
+
+ if (opc_rx && ofs >= 0 && ofs < 0x1000) {
+ tcg_out_insn_RX(s, opc_rx, data, base, index, ofs);
+ } else {
+ tcg_out_insn_RXY(s, opc_rxy, data, base, index, ofs);
+ }
+}
+
+
+/* load data without address translation or endianness conversion */
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, tcg_target_long ofs)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_mem(s, RX_L, RXY_LY, data, base, TCG_REG_NONE, ofs);
+ } else {
+ tcg_out_mem(s, 0, RXY_LG, data, base, TCG_REG_NONE, ofs);
+ }
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, tcg_target_long ofs)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_mem(s, RX_ST, RXY_STY, data, base, TCG_REG_NONE, ofs);
+ } else {
+ tcg_out_mem(s, 0, RXY_STG, data, base, TCG_REG_NONE, ofs);
+ }
+}
+
+/* load data from an absolute host address */
+static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
+{
+ tcg_target_long addr = (tcg_target_long)abs;
+
+ if (facilities & FACILITY_GEN_INST_EXT) {
+ tcg_target_long disp = (addr - (tcg_target_long)s->code_ptr) >> 1;
+ if (disp == (int32_t)disp) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RIL, LRL, dest, disp);
+ } else {
+ tcg_out_insn(s, RIL, LGRL, dest, disp);
+ }
+ return;
+ }
+ }
+
+ tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff);
+ tcg_out_ld(s, type, dest, dest, addr & 0xffff);
+}
+
+static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ tcg_out_insn(s, RRE, LGBR, dest, src);
+ return;
+ }
+
+ if (type == TCG_TYPE_I32) {
+ if (dest == src) {
+ tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 24);
+ } else {
+ tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 24);
+ }
+ tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 24);
+ } else {
+ tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 56);
+ tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 56);
+ }
+}
+
+static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ tcg_out_insn(s, RRE, LLGCR, dest, src);
+ return;
+ }
+
+ if (dest == src) {
+ tcg_out_movi(s, type, TCG_TMP0, 0xff);
+ src = TCG_TMP0;
+ } else {
+ tcg_out_movi(s, type, dest, 0xff);
+ }
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, NR, dest, src);
+ } else {
+ tcg_out_insn(s, RRE, NGR, dest, src);
+ }
+}
+
+static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ tcg_out_insn(s, RRE, LGHR, dest, src);
+ return;
+ }
+
+ if (type == TCG_TYPE_I32) {
+ if (dest == src) {
+ tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 16);
+ } else {
+ tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 16);
+ }
+ tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 16);
+ } else {
+ tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 48);
+ tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 48);
+ }
+}
+
+static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+ if (facilities & FACILITY_EXT_IMM) {
+ tcg_out_insn(s, RRE, LLGHR, dest, src);
+ return;
+ }
+
+ if (dest == src) {
+ tcg_out_movi(s, type, TCG_TMP0, 0xffff);
+ src = TCG_TMP0;
+ } else {
+ tcg_out_movi(s, type, dest, 0xffff);
+ }
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, NR, dest, src);
+ } else {
+ tcg_out_insn(s, RRE, NGR, dest, src);
+ }
+}
+
+static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src)
+{
+ tcg_out_insn(s, RRE, LGFR, dest, src);
+}
+
+static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src)
+{
+ tcg_out_insn(s, RRE, LLGFR, dest, src);
+}
+
+static inline void tgen32_addi(TCGContext *s, TCGReg dest, int32_t val)
+{
+ if (val == (int16_t)val) {
+ tcg_out_insn(s, RI, AHI, dest, val);
+ } else {
+ tcg_out_insn(s, RIL, AFI, dest, val);
+ }
+}
+
+static inline void tgen64_addi(TCGContext *s, TCGReg dest, int64_t val)
+{
+ if (val == (int16_t)val) {
+ tcg_out_insn(s, RI, AGHI, dest, val);
+ } else if (val == (int32_t)val) {
+ tcg_out_insn(s, RIL, AGFI, dest, val);
+ } else if (val == (uint32_t)val) {
+ tcg_out_insn(s, RIL, ALGFI, dest, val);
+ } else {
+ tcg_abort();
+ }
+
+}
+
+static void tgen64_andi(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+ static const S390Opcode ni_insns[4] = {
+ RI_NILL, RI_NILH, RI_NIHL, RI_NIHH
+ };
+ static const S390Opcode nif_insns[2] = {
+ RIL_NILF, RIL_NIHF
+ };
+
+ int i;
+
+ /* Look for no-op. */
+ if (val == -1) {
+ return;
+ }
+
+ /* Look for the zero-extensions. */
+ if (val == 0xffffffff) {
+ tgen_ext32u(s, dest, dest);
+ return;
+ }
+
+ if (facilities & FACILITY_EXT_IMM) {
+ if (val == 0xff) {
+ tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
+ return;
+ }
+ if (val == 0xffff) {
+ tgen_ext16u(s, TCG_TYPE_I64, dest, dest);
+ return;
+ }
+
+ /* Try all 32-bit insns that can perform it in one go. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = ~(0xffffull << i*16);
+ if ((val & mask) == mask) {
+ tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16);
+ return;
+ }
+ }
+
+ /* Try all 48-bit insns that can perform it in one go. */
+ if (facilities & FACILITY_EXT_IMM) {
+ for (i = 0; i < 2; i++) {
+ tcg_target_ulong mask = ~(0xffffffffull << i*32);
+ if ((val & mask) == mask) {
+ tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
+ return;
+ }
+ }
+ }
+
+ /* Perform the AND via sequential modifications to the high and low
+ parts. Do this via recursion to handle 16-bit vs 32-bit masks in
+ each half. */
+ tgen64_andi(s, dest, val | 0xffffffff00000000ull);
+ tgen64_andi(s, dest, val | 0x00000000ffffffffull);
+ } else {
+ /* With no extended-immediate facility, just emit the sequence. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = 0xffffull << i*16;
+ if ((val & mask) != mask) {
+ tcg_out_insn_RI(s, ni_insns[i], dest, val >> i*16);
+ }
+ }
+ }
+}
+
+static void tgen64_ori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+ static const S390Opcode oi_insns[4] = {
+ RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
+ };
+ static const S390Opcode nif_insns[2] = {
+ RIL_OILF, RIL_OIHF
+ };
+
+ int i;
+
+ /* Look for no-op. */
+ if (val == 0) {
+ return;
+ }
+
+ if (facilities & FACILITY_EXT_IMM) {
+ /* Try all 32-bit insns that can perform it in one go. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = (0xffffull << i*16);
+ if ((val & mask) != 0 && (val & ~mask) == 0) {
+ tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
+ return;
+ }
+ }
+
+ /* Try all 48-bit insns that can perform it in one go. */
+ for (i = 0; i < 2; i++) {
+ tcg_target_ulong mask = (0xffffffffull << i*32);
+ if ((val & mask) != 0 && (val & ~mask) == 0) {
+ tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i*32);
+ return;
+ }
+ }
+
+ /* Perform the OR via sequential modifications to the high and
+ low parts. Do this via recursion to handle 16-bit vs 32-bit
+ masks in each half. */
+ tgen64_ori(s, dest, val & 0x00000000ffffffffull);
+ tgen64_ori(s, dest, val & 0xffffffff00000000ull);
+ } else {
+ /* With no extended-immediate facility, we don't need to be so
+ clever. Just iterate over the insns and mask in the constant. */
+ for (i = 0; i < 4; i++) {
+ tcg_target_ulong mask = (0xffffull << i*16);
+ if ((val & mask) != 0) {
+ tcg_out_insn_RI(s, oi_insns[i], dest, val >> i*16);
+ }
+ }
+ }
+}
+
+static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+ /* Perform the xor by parts. */
+ if (val & 0xffffffff) {
+ tcg_out_insn(s, RIL, XILF, dest, val);
+ }
+ if (val > 0xffffffff) {
+ tcg_out_insn(s, RIL, XIHF, dest, val >> 31 >> 1);
+ }
+}
+
+static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+ TCGArg c2, int c2const)
+{
+ bool is_unsigned = (c > TCG_COND_GT);
+ if (c2const) {
+ if (c2 == 0) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, LTR, r1, r1);
+ } else {
+ tcg_out_insn(s, RRE, LTGR, r1, r1);
+ }
+ return tcg_cond_to_ltr_cond[c];
+ } else {
+ if (is_unsigned) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RIL, CLFI, r1, c2);
+ } else {
+ tcg_out_insn(s, RIL, CLGFI, r1, c2);
+ }
+ } else {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RIL, CFI, r1, c2);
+ } else {
+ tcg_out_insn(s, RIL, CGFI, r1, c2);
+ }
+ }
+ }
+ } else {
+ if (is_unsigned) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, CLR, r1, c2);
+ } else {
+ tcg_out_insn(s, RRE, CLGR, r1, c2);
+ }
+ } else {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, CR, r1, c2);
+ } else {
+ tcg_out_insn(s, RRE, CGR, r1, c2);
+ }
+ }
+ }
+ return tcg_cond_to_s390_cond[c];
+}
+
+static void tgen_setcond(TCGContext *s, TCGType type, TCGCond c,
+ TCGReg dest, TCGReg r1, TCGArg c2, int c2const)
+{
+ int cc = tgen_cmp(s, type, c, r1, c2, c2const);
+
+ /* Emit: r1 = 1; if (cc) goto over; r1 = 0; over: */
+ tcg_out_movi(s, type, dest, 1);
+ tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
+ tcg_out_movi(s, type, dest, 0);
+}
+
+static void tgen_gotoi(TCGContext *s, int cc, tcg_target_long dest)
+{
+ tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
+ if (off > -0x8000 && off < 0x7fff) {
+ tcg_out_insn(s, RI, BRC, cc, off);
+ } else if (off == (int32_t)off) {
+ tcg_out_insn(s, RIL, BRCL, cc, off);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest);
+ tcg_out_insn(s, RR, BCR, cc, TCG_TMP0);
+ }
+}
+
+static void tgen_branch(TCGContext *s, int cc, int labelno)
+{
+ TCGLabel* l = &s->labels[labelno];
+ if (l->has_value) {
+ tgen_gotoi(s, cc, l->u.value);
+ } else if (USE_LONG_BRANCHES) {
+ tcg_out16(s, RIL_BRCL | (cc << 4));
+ tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, labelno, -2);
+ s->code_ptr += 4;
+ } else {
+ tcg_out16(s, RI_BRC | (cc << 4));
+ tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, labelno, -2);
+ s->code_ptr += 2;
+ }
+}
+
+static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
+ TCGReg r1, TCGReg r2, int labelno)
+{
+ TCGLabel* l = &s->labels[labelno];
+ tcg_target_long off;
+
+ if (l->has_value) {
+ off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1;
+ } else {
+ /* We need to keep the offset unchanged for retranslation. */
+ off = ((int16_t *)s->code_ptr)[1];
+ tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2);
+ }
+
+ tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2);
+ tcg_out16(s, off);
+ tcg_out16(s, cc << 12 | (opc & 0xff));
+}
+
+static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
+ TCGReg r1, int i2, int labelno)
+{
+ TCGLabel* l = &s->labels[labelno];
+ tcg_target_long off;
+
+ if (l->has_value) {
+ off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1;
+ } else {
+ /* We need to keep the offset unchanged for retranslation. */
+ off = ((int16_t *)s->code_ptr)[1];
+ tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2);
+ }
+
+ tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc);
+ tcg_out16(s, off);
+ tcg_out16(s, (i2 << 8) | (opc & 0xff));
+}
+
+static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
+ TCGReg r1, TCGArg c2, int c2const, int labelno)
+{
+ int cc;
+
+ if (facilities & FACILITY_GEN_INST_EXT) {
+ bool is_unsigned = (c > TCG_COND_GT);
+ bool in_range;
+ S390Opcode opc;
+
+ cc = tcg_cond_to_s390_cond[c];
+
+ if (!c2const) {
+ opc = (type == TCG_TYPE_I32
+ ? (is_unsigned ? RIE_CLRJ : RIE_CRJ)
+ : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ));
+ tgen_compare_branch(s, opc, cc, r1, c2, labelno);
+ return;
+ }
+
+ /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field.
+ If the immediate we've been given does not fit that range, we'll
+ fall back to separate compare and branch instructions using the
+ larger comparison range afforded by COMPARE IMMEDIATE. */
+ if (type == TCG_TYPE_I32) {
+ if (is_unsigned) {
+ opc = RIE_CLIJ;
+ in_range = (uint32_t)c2 == (uint8_t)c2;
+ } else {
+ opc = RIE_CIJ;
+ in_range = (int32_t)c2 == (int8_t)c2;
+ }
+ } else {
+ if (is_unsigned) {
+ opc = RIE_CLGIJ;
+ in_range = (uint64_t)c2 == (uint8_t)c2;
+ } else {
+ opc = RIE_CGIJ;
+ in_range = (int64_t)c2 == (int8_t)c2;
+ }
+ }
+ if (in_range) {
+ tgen_compare_imm_branch(s, opc, cc, r1, c2, labelno);
+ return;
+ }
+ }
+
+ cc = tgen_cmp(s, type, c, r1, c2, c2const);
+ tgen_branch(s, cc, labelno);
+}
+
+static void tgen_calli(TCGContext *s, tcg_target_long dest)
+{
+ tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
+ if (off == (int32_t)off) {
+ tcg_out_insn(s, RIL, BRASL, TCG_REG_R14, off);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest);
+ tcg_out_insn(s, RR, BASR, TCG_REG_R14, TCG_TMP0);
+ }
+}
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data,
+ TCGReg base, TCGReg index, int disp)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 0;
+#else
+ const int bswap = 1;
+#endif
+ switch (opc) {
+ case LD_UINT8:
+ tcg_out_insn(s, RXY, LLGC, data, base, index, disp);
+ break;
+ case LD_INT8:
+ tcg_out_insn(s, RXY, LGB, data, base, index, disp);
+ break;
+ case LD_UINT16:
+ if (bswap) {
+ /* swapped unsigned halfword load with upper bits zeroed */
+ tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
+ tgen_ext16u(s, TCG_TYPE_I64, data, data);
+ } else {
+ tcg_out_insn(s, RXY, LLGH, data, base, index, disp);
+ }
+ break;
+ case LD_INT16:
+ if (bswap) {
+ /* swapped sign-extended halfword load */
+ tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
+ tgen_ext16s(s, TCG_TYPE_I64, data, data);
+ } else {
+ tcg_out_insn(s, RXY, LGH, data, base, index, disp);
+ }
+ break;
+ case LD_UINT32:
+ if (bswap) {
+ /* swapped unsigned int load with upper bits zeroed */
+ tcg_out_insn(s, RXY, LRV, data, base, index, disp);
+ tgen_ext32u(s, data, data);
+ } else {
+ tcg_out_insn(s, RXY, LLGF, data, base, index, disp);
+ }
+ break;
+ case LD_INT32:
+ if (bswap) {
+ /* swapped sign-extended int load */
+ tcg_out_insn(s, RXY, LRV, data, base, index, disp);
+ tgen_ext32s(s, data, data);
+ } else {
+ tcg_out_insn(s, RXY, LGF, data, base, index, disp);
+ }
+ break;
+ case LD_UINT64:
+ if (bswap) {
+ tcg_out_insn(s, RXY, LRVG, data, base, index, disp);
+ } else {
+ tcg_out_insn(s, RXY, LG, data, base, index, disp);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data,
+ TCGReg base, TCGReg index, int disp)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ const int bswap = 0;
+#else
+ const int bswap = 1;
+#endif
+ switch (opc) {
+ case LD_UINT8:
+ if (disp >= 0 && disp < 0x1000) {
+ tcg_out_insn(s, RX, STC, data, base, index, disp);
+ } else {
+ tcg_out_insn(s, RXY, STCY, data, base, index, disp);
+ }
+ break;
+ case LD_UINT16:
+ if (bswap) {
+ tcg_out_insn(s, RXY, STRVH, data, base, index, disp);
+ } else if (disp >= 0 && disp < 0x1000) {
+ tcg_out_insn(s, RX, STH, data, base, index, disp);
+ } else {
+ tcg_out_insn(s, RXY, STHY, data, base, index, disp);
+ }
+ break;
+ case LD_UINT32:
+ if (bswap) {
+ tcg_out_insn(s, RXY, STRV, data, base, index, disp);
+ } else if (disp >= 0 && disp < 0x1000) {
+ tcg_out_insn(s, RX, ST, data, base, index, disp);
+ } else {
+ tcg_out_insn(s, RXY, STY, data, base, index, disp);
+ }
+ break;
+ case LD_UINT64:
+ if (bswap) {
+ tcg_out_insn(s, RXY, STRVG, data, base, index, disp);
+ } else {
+ tcg_out_insn(s, RXY, STG, data, base, index, disp);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+#if defined(CONFIG_SOFTMMU)
+static void tgen64_andi_tmp(TCGContext *s, TCGReg dest, tcg_target_ulong val)
+{
+ if (tcg_match_andi(0, val)) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, val);
+ tcg_out_insn(s, RRE, NGR, dest, TCG_TMP0);
+ } else {
+ tgen64_andi(s, dest, val);
+ }
+}
+
+static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
+ TCGReg addr_reg, int mem_index, int opc,
+ uint16_t **label2_ptr_p, int is_store)
+{
+ const TCGReg arg0 = TCG_REG_R2;
+ const TCGReg arg1 = TCG_REG_R3;
+ int s_bits = opc & 3;
+ uint16_t *label1_ptr;
+ tcg_target_long ofs;
+
+ if (TARGET_LONG_BITS == 32) {
+ tgen_ext32u(s, arg0, addr_reg);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I64, arg0, addr_reg);
+ }
+
+ tcg_out_sh64(s, RSY_SRLG, arg1, addr_reg, TCG_REG_NONE,
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+
+ tgen64_andi_tmp(s, arg0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+ tgen64_andi_tmp(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+ if (is_store) {
+ ofs = offsetof(CPUState, tlb_table[mem_index][0].addr_write);
+ } else {
+ ofs = offsetof(CPUState, tlb_table[mem_index][0].addr_read);
+ }
+ assert(ofs < 0x80000);
+
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_mem(s, RX_C, RXY_CY, arg0, arg1, TCG_AREG0, ofs);
+ } else {
+ tcg_out_mem(s, 0, RXY_CG, arg0, arg1, TCG_AREG0, ofs);
+ }
+
+ if (TARGET_LONG_BITS == 32) {
+ tgen_ext32u(s, arg0, addr_reg);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I64, arg0, addr_reg);
+ }
+
+ label1_ptr = (uint16_t*)s->code_ptr;
+
+ /* je label1 (offset will be patched in later) */
+ tcg_out_insn(s, RI, BRC, S390_CC_EQ, 0);
+
+ /* call load/store helper */
+ if (is_store) {
+ /* Make sure to zero-extend the value to the full register
+ for the calling convention. */
+ switch (opc) {
+ case LD_UINT8:
+ tgen_ext8u(s, TCG_TYPE_I64, arg1, data_reg);
+ break;
+ case LD_UINT16:
+ tgen_ext16u(s, TCG_TYPE_I64, arg1, data_reg);
+ break;
+ case LD_UINT32:
+ tgen_ext32u(s, arg1, data_reg);
+ break;
+ case LD_UINT64:
+ tcg_out_mov(s, TCG_TYPE_I64, arg1, data_reg);
+ break;
+ default:
+ tcg_abort();
+ }
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index);
+ tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+ tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]);
+
+ /* sign extension */
+ switch (opc) {
+ case LD_INT8:
+ tgen_ext8s(s, TCG_TYPE_I64, data_reg, arg0);
+ break;
+ case LD_INT16:
+ tgen_ext16s(s, TCG_TYPE_I64, data_reg, arg0);
+ break;
+ case LD_INT32:
+ tgen_ext32s(s, data_reg, arg0);
+ break;
+ default:
+ /* unsigned -> just copy */
+ tcg_out_mov(s, TCG_TYPE_I64, data_reg, arg0);
+ break;
+ }
+ }
+
+ /* jump to label2 (end) */
+ *label2_ptr_p = (uint16_t*)s->code_ptr;
+
+ tcg_out_insn(s, RI, BRC, S390_CC_ALWAYS, 0);
+
+ /* this is label1, patch branch */
+ *(label1_ptr + 1) = ((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr) >> 1;
+
+ ofs = offsetof(CPUState, tlb_table[mem_index][0].addend);
+ assert(ofs < 0x80000);
+
+ tcg_out_mem(s, 0, RXY_AG, arg0, arg1, TCG_AREG0, ofs);
+}
+
+static void tcg_finish_qemu_ldst(TCGContext* s, uint16_t *label2_ptr)
+{
+ /* patch branch */
+ *(label2_ptr + 1) = ((unsigned long)s->code_ptr -
+ (unsigned long)label2_ptr) >> 1;
+}
+#else
+static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg,
+ TCGReg *index_reg, tcg_target_long *disp)
+{
+ if (TARGET_LONG_BITS == 32) {
+ tgen_ext32u(s, TCG_TMP0, *addr_reg);
+ *addr_reg = TCG_TMP0;
+ }
+ if (GUEST_BASE < 0x80000) {
+ *index_reg = TCG_REG_NONE;
+ *disp = GUEST_BASE;
+ } else {
+ *index_reg = TCG_GUEST_BASE_REG;
+ *disp = 0;
+ }
+}
+#endif /* CONFIG_SOFTMMU */
+
+/* load data with address translation (if applicable)
+ and endianness conversion */
+static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc)
+{
+ TCGReg addr_reg, data_reg;
+#if defined(CONFIG_SOFTMMU)
+ int mem_index;
+ uint16_t *label2_ptr;
+#else
+ TCGReg index_reg;
+ tcg_target_long disp;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+ mem_index = *args;
+
+ tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index,
+ opc, &label2_ptr, 0);
+
+ tcg_out_qemu_ld_direct(s, opc, data_reg, TCG_REG_R2, TCG_REG_NONE, 0);
+
+ tcg_finish_qemu_ldst(s, label2_ptr);
+#else
+ tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
+ tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, index_reg, disp);
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc)
+{
+ TCGReg addr_reg, data_reg;
+#if defined(CONFIG_SOFTMMU)
+ int mem_index;
+ uint16_t *label2_ptr;
+#else
+ TCGReg index_reg;
+ tcg_target_long disp;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+ mem_index = *args;
+
+ tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index,
+ opc, &label2_ptr, 1);
+
+ tcg_out_qemu_st_direct(s, opc, data_reg, TCG_REG_R2, TCG_REG_NONE, 0);
+
+ tcg_finish_qemu_ldst(s, label2_ptr);
+#else
+ tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
+ tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, index_reg, disp);
+#endif
+}
+
+#if TCG_TARGET_REG_BITS == 64
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_,x),_i32): \
+ case glue(glue(INDEX_op_,x),_i64)
+#else
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_,x),_i32)
+#endif
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ S390Opcode op;
+
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ /* return value */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]);
+ tgen_gotoi(s, S390_CC_ALWAYS, (unsigned long)tb_ret_addr);
+ break;
+
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ tcg_abort();
+ } else {
+ /* load address stored at s->tb_next + args[0] */
+ tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_TMP0, s->tb_next + args[0]);
+ /* and go there */
+ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_TMP0);
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+
+ case INDEX_op_call:
+ if (const_args[0]) {
+ tgen_calli(s, args[0]);
+ } else {
+ tcg_out_insn(s, RR, BASR, TCG_REG_R14, args[0]);
+ }
+ break;
+
+ case INDEX_op_mov_i32:
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+
+ OP_32_64(ld8u):
+ /* ??? LLC (RXY format) is only present with the extended-immediate
+ facility, whereas LLGC is always present. */
+ tcg_out_mem(s, 0, RXY_LLGC, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+
+ OP_32_64(ld8s):
+ /* ??? LB is no smaller than LGB, so no point to using it. */
+ tcg_out_mem(s, 0, RXY_LGB, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+
+ OP_32_64(ld16u):
+ /* ??? LLH (RXY format) is only present with the extended-immediate
+ facility, whereas LLGH is always present. */
+ tcg_out_mem(s, 0, RXY_LLGH, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+
+ case INDEX_op_ld16s_i32:
+ tcg_out_mem(s, RX_LH, RXY_LHY, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+
+ case INDEX_op_ld_i32:
+ tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+ break;
+
+ OP_32_64(st8):
+ tcg_out_mem(s, RX_STC, RXY_STCY, args[0], args[1],
+ TCG_REG_NONE, args[2]);
+ break;
+
+ OP_32_64(st16):
+ tcg_out_mem(s, RX_STH, RXY_STHY, args[0], args[1],
+ TCG_REG_NONE, args[2]);
+ break;
+
+ case INDEX_op_st_i32:
+ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_add_i32:
+ if (const_args[2]) {
+ tgen32_addi(s, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RR, AR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_sub_i32:
+ if (const_args[2]) {
+ tgen32_addi(s, args[0], -args[2]);
+ } else {
+ tcg_out_insn(s, RR, SR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_and_i32:
+ if (const_args[2]) {
+ tgen64_andi(s, args[0], args[2] | 0xffffffff00000000ull);
+ } else {
+ tcg_out_insn(s, RR, NR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_or_i32:
+ if (const_args[2]) {
+ tgen64_ori(s, args[0], args[2] & 0xffffffff);
+ } else {
+ tcg_out_insn(s, RR, OR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_xor_i32:
+ if (const_args[2]) {
+ tgen64_xori(s, args[0], args[2] & 0xffffffff);
+ } else {
+ tcg_out_insn(s, RR, XR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_neg_i32:
+ tcg_out_insn(s, RR, LCR, args[0], args[1]);
+ break;
+
+ case INDEX_op_mul_i32:
+ if (const_args[2]) {
+ if ((int32_t)args[2] == (int16_t)args[2]) {
+ tcg_out_insn(s, RI, MHI, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RIL, MSFI, args[0], args[2]);
+ }
+ } else {
+ tcg_out_insn(s, RRE, MSR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_div2_i32:
+ tcg_out_insn(s, RR, DR, TCG_REG_R2, args[4]);
+ break;
+ case INDEX_op_divu2_i32:
+ tcg_out_insn(s, RRE, DLR, TCG_REG_R2, args[4]);
+ break;
+
+ case INDEX_op_shl_i32:
+ op = RS_SLL;
+ do_shift32:
+ if (const_args[2]) {
+ tcg_out_sh32(s, op, args[0], TCG_REG_NONE, args[2]);
+ } else {
+ tcg_out_sh32(s, op, args[0], args[2], 0);
+ }
+ break;
+ case INDEX_op_shr_i32:
+ op = RS_SRL;
+ goto do_shift32;
+ case INDEX_op_sar_i32:
+ op = RS_SRA;
+ goto do_shift32;
+
+ case INDEX_op_rotl_i32:
+ /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol. */
+ if (const_args[2]) {
+ tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_REG_NONE, args[2]);
+ } else {
+ tcg_out_sh64(s, RSY_RLL, args[0], args[1], args[2], 0);
+ }
+ break;
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ tcg_out_sh64(s, RSY_RLL, args[0], args[1],
+ TCG_REG_NONE, (32 - args[2]) & 31);
+ } else {
+ tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
+ tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_TMP0, 0);
+ }
+ break;
+
+ case INDEX_op_ext8s_i32:
+ tgen_ext8s(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i32:
+ tgen_ext16s(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_ext8u_i32:
+ tgen_ext8u(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_ext16u_i32:
+ tgen_ext16u(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+
+ OP_32_64(bswap16):
+ /* The TCG bswap definition requires bits 0-47 already be zero.
+ Thus we don't need the G-type insns to implement bswap16_i64. */
+ tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
+ tcg_out_sh32(s, RS_SRL, args[0], TCG_REG_NONE, 16);
+ break;
+ OP_32_64(bswap32):
+ tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
+ break;
+
+ case INDEX_op_br:
+ tgen_branch(s, S390_CC_ALWAYS, args[0]);
+ break;
+
+ case INDEX_op_brcond_i32:
+ tgen_brcond(s, TCG_TYPE_I32, args[2], args[0],
+ args[1], const_args[1], args[3]);
+ break;
+ case INDEX_op_setcond_i32:
+ tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, LD_UINT8);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, LD_INT8);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, LD_UINT16);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, LD_INT16);
+ break;
+ case INDEX_op_qemu_ld32:
+ /* ??? Technically we can use a non-extending instruction. */
+ tcg_out_qemu_ld(s, args, LD_UINT32);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, LD_UINT64);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, LD_UINT8);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, LD_UINT16);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, LD_UINT32);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, LD_UINT64);
+ break;
+
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_mov_i64:
+ tcg_out_mov(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_movi_i64:
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+
+ case INDEX_op_ld16s_i64:
+ tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+ case INDEX_op_ld32u_i64:
+ tcg_out_mem(s, 0, RXY_LLGF, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_mem(s, 0, RXY_LGF, args[0], args[1], TCG_REG_NONE, args[2]);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_st32_i64:
+ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+
+ case INDEX_op_add_i64:
+ if (const_args[2]) {
+ tgen64_addi(s, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RRE, AGR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_sub_i64:
+ if (const_args[2]) {
+ tgen64_addi(s, args[0], -args[2]);
+ } else {
+ tcg_out_insn(s, RRE, SGR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_and_i64:
+ if (const_args[2]) {
+ tgen64_andi(s, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RRE, NGR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_or_i64:
+ if (const_args[2]) {
+ tgen64_ori(s, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RRE, OGR, args[0], args[2]);
+ }
+ break;
+ case INDEX_op_xor_i64:
+ if (const_args[2]) {
+ tgen64_xori(s, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RRE, XGR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_neg_i64:
+ tcg_out_insn(s, RRE, LCGR, args[0], args[1]);
+ break;
+ case INDEX_op_bswap64_i64:
+ tcg_out_insn(s, RRE, LRVGR, args[0], args[1]);
+ break;
+
+ case INDEX_op_mul_i64:
+ if (const_args[2]) {
+ if (args[2] == (int16_t)args[2]) {
+ tcg_out_insn(s, RI, MGHI, args[0], args[2]);
+ } else {
+ tcg_out_insn(s, RIL, MSGFI, args[0], args[2]);
+ }
+ } else {
+ tcg_out_insn(s, RRE, MSGR, args[0], args[2]);
+ }
+ break;
+
+ case INDEX_op_div2_i64:
+ /* ??? We get an unnecessary sign-extension of the dividend
+ into R3 with this definition, but as we do in fact always
+ produce both quotient and remainder using INDEX_op_div_i64
+ instead requires jumping through even more hoops. */
+ tcg_out_insn(s, RRE, DSGR, TCG_REG_R2, args[4]);
+ break;
+ case INDEX_op_divu2_i64:
+ tcg_out_insn(s, RRE, DLGR, TCG_REG_R2, args[4]);
+ break;
+
+ case INDEX_op_shl_i64:
+ op = RSY_SLLG;
+ do_shift64:
+ if (const_args[2]) {
+ tcg_out_sh64(s, op, args[0], args[1], TCG_REG_NONE, args[2]);
+ } else {
+ tcg_out_sh64(s, op, args[0], args[1], args[2], 0);
+ }
+ break;
+ case INDEX_op_shr_i64:
+ op = RSY_SRLG;
+ goto do_shift64;
+ case INDEX_op_sar_i64:
+ op = RSY_SRAG;
+ goto do_shift64;
+
+ case INDEX_op_rotl_i64:
+ if (const_args[2]) {
+ tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
+ TCG_REG_NONE, args[2]);
+ } else {
+ tcg_out_sh64(s, RSY_RLLG, args[0], args[1], args[2], 0);
+ }
+ break;
+ case INDEX_op_rotr_i64:
+ if (const_args[2]) {
+ tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
+ TCG_REG_NONE, (64 - args[2]) & 63);
+ } else {
+ /* We can use the smaller 32-bit negate because only the
+ low 6 bits are examined for the rotate. */
+ tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
+ tcg_out_sh64(s, RSY_RLLG, args[0], args[1], TCG_TMP0, 0);
+ }
+ break;
+
+ case INDEX_op_ext8s_i64:
+ tgen_ext8s(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ext16s_i64:
+ tgen_ext16s(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ext32s_i64:
+ tgen_ext32s(s, args[0], args[1]);
+ break;
+ case INDEX_op_ext8u_i64:
+ tgen_ext8u(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ext16u_i64:
+ tgen_ext16u(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ext32u_i64:
+ tgen_ext32u(s, args[0], args[1]);
+ break;
+
+ case INDEX_op_brcond_i64:
+ tgen_brcond(s, TCG_TYPE_I64, args[2], args[0],
+ args[1], const_args[1], args[3]);
+ break;
+ case INDEX_op_setcond_i64:
+ tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_qemu_ld32u:
+ tcg_out_qemu_ld(s, args, LD_UINT32);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, LD_INT32);
+ break;
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+ case INDEX_op_jmp:
+ /* This one is obsolete and never emitted. */
+ tcg_abort();
+ break;
+
+ default:
+ fprintf(stderr,"unimplemented opc 0x%x\n",opc);
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef s390_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "0", "rWI" } },
+ { INDEX_op_sub_i32, { "r", "0", "rWNI" } },
+ { INDEX_op_mul_i32, { "r", "0", "rK" } },
+
+ { INDEX_op_div2_i32, { "b", "a", "0", "1", "r" } },
+ { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } },
+
+ { INDEX_op_and_i32, { "r", "0", "rWA" } },
+ { INDEX_op_or_i32, { "r", "0", "rWO" } },
+ { INDEX_op_xor_i32, { "r", "0", "rWX" } },
+
+ { INDEX_op_neg_i32, { "r", "r" } },
+
+ { INDEX_op_shl_i32, { "r", "0", "Ri" } },
+ { INDEX_op_shr_i32, { "r", "0", "Ri" } },
+ { INDEX_op_sar_i32, { "r", "0", "Ri" } },
+
+ { INDEX_op_rotl_i32, { "r", "r", "Ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "Ri" } },
+
+ { INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext8u_i32, { "r", "r" } },
+ { INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
+
+ { INDEX_op_bswap16_i32, { "r", "r" } },
+ { INDEX_op_bswap32_i32, { "r", "r" } },
+
+ { INDEX_op_brcond_i32, { "r", "rWC" } },
+ { INDEX_op_setcond_i32, { "r", "r", "rWC" } },
+
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L" } },
+
+#if defined(__s390x__)
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+
+ { INDEX_op_add_i64, { "r", "0", "rI" } },
+ { INDEX_op_sub_i64, { "r", "0", "rNI" } },
+ { INDEX_op_mul_i64, { "r", "0", "rK" } },
+
+ { INDEX_op_div2_i64, { "b", "a", "0", "1", "r" } },
+ { INDEX_op_divu2_i64, { "b", "a", "0", "1", "r" } },
+
+ { INDEX_op_and_i64, { "r", "0", "rA" } },
+ { INDEX_op_or_i64, { "r", "0", "rO" } },
+ { INDEX_op_xor_i64, { "r", "0", "rX" } },
+
+ { INDEX_op_neg_i64, { "r", "r" } },
+
+ { INDEX_op_shl_i64, { "r", "r", "Ri" } },
+ { INDEX_op_shr_i64, { "r", "r", "Ri" } },
+ { INDEX_op_sar_i64, { "r", "r", "Ri" } },
+
+ { INDEX_op_rotl_i64, { "r", "r", "Ri" } },
+ { INDEX_op_rotr_i64, { "r", "r", "Ri" } },
+
+ { INDEX_op_ext8s_i64, { "r", "r" } },
+ { INDEX_op_ext8u_i64, { "r", "r" } },
+ { INDEX_op_ext16s_i64, { "r", "r" } },
+ { INDEX_op_ext16u_i64, { "r", "r" } },
+ { INDEX_op_ext32s_i64, { "r", "r" } },
+ { INDEX_op_ext32u_i64, { "r", "r" } },
+
+ { INDEX_op_bswap16_i64, { "r", "r" } },
+ { INDEX_op_bswap32_i64, { "r", "r" } },
+ { INDEX_op_bswap64_i64, { "r", "r" } },
+
+ { INDEX_op_brcond_i64, { "r", "rC" } },
+ { INDEX_op_setcond_i64, { "r", "r", "rC" } },
+
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
+
+ { -1 },
+};
+
+/* ??? Linux kernels provide an AUXV entry AT_HWCAP that provides most of
+ this information. However, getting at that entry is not easy this far
+ away from main. Our options are: start searching from environ, but
+ that fails as soon as someone does a setenv in between. Read the data
+ from /proc/self/auxv. Or do the probing ourselves. The only thing
+ extra that AT_HWCAP gives us is HWCAP_S390_HIGH_GPRS, which indicates
+ that the kernel saves all 64-bits of the registers around traps while
+ in 31-bit mode. But this is true of all "recent" kernels (ought to dig
+ back and see from when this might not be true). */
+
+#include <signal.h>
+
+static volatile sig_atomic_t got_sigill;
+
+static void sigill_handler(int sig)
+{
+ got_sigill = 1;
+}
+
+static void query_facilities(void)
+{
+ struct sigaction sa_old, sa_new;
+ register int r0 __asm__("0");
+ register void *r1 __asm__("1");
+ int fail;
+
+ memset(&sa_new, 0, sizeof(sa_new));
+ sa_new.sa_handler = sigill_handler;
+ sigaction(SIGILL, &sa_new, &sa_old);
+
+ /* First, try STORE FACILITY LIST EXTENDED. If this is present, then
+ we need not do any more probing. Unfortunately, this itself is an
+ extension and the original STORE FACILITY LIST instruction is
+ kernel-only, storing its results at absolute address 200. */
+ /* stfle 0(%r1) */
+ r1 = &facilities;
+ asm volatile(".word 0xb2b0,0x1000"
+ : "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
+
+ if (got_sigill) {
+ /* STORE FACILITY EXTENDED is not available. Probe for one of each
+ kind of instruction that we're interested in. */
+ /* ??? Possibly some of these are in practice never present unless
+ the store-facility-extended facility is also present. But since
+ that isn't documented it's just better to probe for each. */
+
+ /* Test for z/Architecture. Required even in 31-bit mode. */
+ got_sigill = 0;
+ /* agr %r0,%r0 */
+ asm volatile(".word 0xb908,0x0000" : "=r"(r0) : : "cc");
+ if (!got_sigill) {
+ facilities |= FACILITY_ZARCH_ACTIVE;
+ }
+
+ /* Test for long displacement. */
+ got_sigill = 0;
+ /* ly %r0,0(%r1) */
+ r1 = &facilities;
+ asm volatile(".word 0xe300,0x1000,0x0058"
+ : "=r"(r0) : "r"(r1) : "cc");
+ if (!got_sigill) {
+ facilities |= FACILITY_LONG_DISP;
+ }
+
+ /* Test for extended immediates. */
+ got_sigill = 0;
+ /* afi %r0,0 */
+ asm volatile(".word 0xc209,0x0000,0x0000" : : : "cc");
+ if (!got_sigill) {
+ facilities |= FACILITY_EXT_IMM;
+ }
+
+ /* Test for general-instructions-extension. */
+ got_sigill = 0;
+ /* msfi %r0,1 */
+ asm volatile(".word 0xc201,0x0000,0x0001");
+ if (!got_sigill) {
+ facilities |= FACILITY_GEN_INST_EXT;
+ }
+ }
+
+ sigaction(SIGILL, &sa_old, NULL);
+
+ /* The translator currently uses these extensions unconditionally.
+ Pruning this back to the base ESA/390 architecture doesn't seem
+ worthwhile, since even the KVM target requires z/Arch. */
+ fail = 0;
+ if ((facilities & FACILITY_ZARCH_ACTIVE) == 0) {
+ fprintf(stderr, "TCG: z/Arch facility is required.\n");
+ fprintf(stderr, "TCG: Boot with a 64-bit enabled kernel.\n");
+ fail = 1;
+ }
+ if ((facilities & FACILITY_LONG_DISP) == 0) {
+ fprintf(stderr, "TCG: long-displacement facility is required.\n");
+ fail = 1;
+ }
+
+ /* So far there's just enough support for 31-bit mode to let the
+ compile succeed. This is good enough to run QEMU with KVM. */
+ if (sizeof(void *) != 8) {
+ fprintf(stderr, "TCG: 31-bit mode is not supported.\n");
+ fail = 1;
+ }
+
+ if (fail) {
+ exit(-1);
+ }
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* fail safe */
+ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) {
+ tcg_abort();
+ }
+#endif
+
+ query_facilities();
+
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
+
+ tcg_regset_clear(tcg_target_call_clobber_regs);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R1);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R4);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R5);
+ /* The return register can be considered call-clobbered. */
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_TMP0);
+ /* XXX many insns can't be used with R0, so we better avoid it for now */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
+
+ tcg_add_target_add_op_defs(s390_op_defs);
+}
+
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ /* stmg %r6,%r15,48(%r15) (save registers) */
+ tcg_out_insn(s, RXY, STMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 48);
+
+ /* aghi %r15,-160 (stack frame) */
+ tcg_out_insn(s, RI, AGHI, TCG_REG_R15, -160);
+
+ if (GUEST_BASE >= 0x80000) {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+ }
+
+ /* br %r2 (go to TB) */
+ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R2);
+
+ tb_ret_addr = s->code_ptr;
+
+ /* lmg %r6,%r15,208(%r15) (restore registers) */
+ tcg_out_insn(s, RXY, LMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 208);
+
+ /* br %r14 (return) */
+ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ tcg_abort();
+}
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
new file mode 100644
index 0000000..4e45cf3
--- /dev/null
+++ b/tcg/s390/tcg-target.h
@@ -0,0 +1,109 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2009 Ulrich Hecht <uli@suse.de>
+ *
+ * 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_S390 1
+
+#ifdef __s390x__
+#define TCG_TARGET_REG_BITS 64
+#else
+#define TCG_TARGET_REG_BITS 32
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+typedef enum TCGReg {
+ TCG_REG_R0 = 0,
+ TCG_REG_R1,
+ TCG_REG_R2,
+ TCG_REG_R3,
+ TCG_REG_R4,
+ TCG_REG_R5,
+ TCG_REG_R6,
+ TCG_REG_R7,
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15
+} TCGReg;
+
+#define TCG_TARGET_NB_REGS 16
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div2_i32
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div2_i64
+#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+// #define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_neg_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+#define TCG_TARGET_HAS_GUEST_BASE
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_R15
+#define TCG_TARGET_STACK_ALIGN 8
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+#define TCG_TARGET_EXTEND_ARGS 1
+
+enum {
+ /* Note: must be synced with dyngen-exec.h */
+ TCG_AREG0 = TCG_REG_R10,
+};
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
new file mode 100644
index 0000000..5f1353a
--- /dev/null
+++ b/tcg/sparc/tcg-target.c
@@ -0,0 +1,1569 @@
+/*
+ * 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.
+ */
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "%g0",
+ "%g1",
+ "%g2",
+ "%g3",
+ "%g4",
+ "%g5",
+ "%g6",
+ "%g7",
+ "%o0",
+ "%o1",
+ "%o2",
+ "%o3",
+ "%o4",
+ "%o5",
+ "%o6",
+ "%o7",
+ "%l0",
+ "%l1",
+ "%l2",
+ "%l3",
+ "%l4",
+ "%l5",
+ "%l6",
+ "%l7",
+ "%i0",
+ "%i1",
+ "%i2",
+ "%i3",
+ "%i4",
+ "%i5",
+ "%i6",
+ "%i7",
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_L0,
+ TCG_REG_L1,
+ TCG_REG_L2,
+ TCG_REG_L3,
+ TCG_REG_L4,
+ TCG_REG_L5,
+ TCG_REG_L6,
+ TCG_REG_L7,
+ TCG_REG_I0,
+ TCG_REG_I1,
+ TCG_REG_I2,
+ TCG_REG_I3,
+ TCG_REG_I4,
+};
+
+static const int tcg_target_call_iarg_regs[6] = {
+ TCG_REG_O0,
+ TCG_REG_O1,
+ TCG_REG_O2,
+ TCG_REG_O3,
+ TCG_REG_O4,
+ TCG_REG_O5,
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_O0,
+ TCG_REG_O1,
+};
+
+static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
+{
+ return (val << ((sizeof(tcg_target_long) * 8 - bits))
+ >> (sizeof(tcg_target_long) * 8 - bits)) == val;
+}
+
+static inline int check_fit_i32(uint32_t val, unsigned int bits)
+{
+ return ((val << (32 - bits)) >> (32 - bits)) == val;
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend)
+{
+ value += addend;
+ switch (type) {
+ case R_SPARC_32:
+ if (value != (uint32_t)value)
+ tcg_abort();
+ *(uint32_t *)code_ptr = value;
+ break;
+ case R_SPARC_WDISP22:
+ value -= (long)code_ptr;
+ value >>= 2;
+ if (!check_fit_tl(value, 22))
+ tcg_abort();
+ *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value;
+ break;
+ case R_SPARC_WDISP19:
+ value -= (long)code_ptr;
+ value >>= 2;
+ if (!check_fit_tl(value, 19))
+ tcg_abort();
+ *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value;
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 6;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str;
+
+ ct_str = *pct_str;
+ switch (ct_str[0]) {
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ break;
+ case 'L': /* qemu_ld/st constraint */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ // Helper args
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2);
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_S11;
+ break;
+ case 'J':
+ ct->ct |= TCG_CT_CONST_S13;
+ break;
+ default:
+ return -1;
+ }
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct;
+
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11))
+ return 1;
+ else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13))
+ return 1;
+ else
+ return 0;
+}
+
+#define INSN_OP(x) ((x) << 30)
+#define INSN_OP2(x) ((x) << 22)
+#define INSN_OP3(x) ((x) << 19)
+#define INSN_OPF(x) ((x) << 5)
+#define INSN_RD(x) ((x) << 25)
+#define INSN_RS1(x) ((x) << 14)
+#define INSN_RS2(x) (x)
+#define INSN_ASI(x) ((x) << 5)
+
+#define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff))
+#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
+#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
+#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
+
+#define INSN_COND(x, a) (((x) << 25) | ((a) << 29))
+#define COND_N 0x0
+#define COND_E 0x1
+#define COND_LE 0x2
+#define COND_L 0x3
+#define COND_LEU 0x4
+#define COND_CS 0x5
+#define COND_NEG 0x6
+#define COND_VS 0x7
+#define COND_A 0x8
+#define COND_NE 0x9
+#define COND_G 0xa
+#define COND_GE 0xb
+#define COND_GU 0xc
+#define COND_CC 0xd
+#define COND_POS 0xe
+#define COND_VC 0xf
+#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2))
+
+#define MOVCC_ICC (1 << 18)
+#define MOVCC_XCC (1 << 18 | 1 << 12)
+
+#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00))
+#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
+#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
+#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02))
+#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
+#define ARITH_ORN (INSN_OP(2) | INSN_OP3(0x06))
+#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03))
+#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04))
+#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14))
+#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10))
+#define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c))
+#define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a))
+#define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e))
+#define ARITH_SDIV (INSN_OP(2) | INSN_OP3(0x0f))
+#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
+#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d))
+#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d))
+#define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c))
+
+#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25))
+#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26))
+#define SHIFT_SRA (INSN_OP(2) | INSN_OP3(0x27))
+
+#define SHIFT_SLLX (INSN_OP(2) | INSN_OP3(0x25) | (1 << 12))
+#define SHIFT_SRLX (INSN_OP(2) | INSN_OP3(0x26) | (1 << 12))
+#define SHIFT_SRAX (INSN_OP(2) | INSN_OP3(0x27) | (1 << 12))
+
+#define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0))
+#define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0))
+#define JMPL (INSN_OP(2) | INSN_OP3(0x38))
+#define SAVE (INSN_OP(2) | INSN_OP3(0x3c))
+#define RESTORE (INSN_OP(2) | INSN_OP3(0x3d))
+#define SETHI (INSN_OP(0) | INSN_OP2(0x4))
+#define CALL INSN_OP(1)
+#define LDUB (INSN_OP(3) | INSN_OP3(0x01))
+#define LDSB (INSN_OP(3) | INSN_OP3(0x09))
+#define LDUH (INSN_OP(3) | INSN_OP3(0x02))
+#define LDSH (INSN_OP(3) | INSN_OP3(0x0a))
+#define LDUW (INSN_OP(3) | INSN_OP3(0x00))
+#define LDSW (INSN_OP(3) | INSN_OP3(0x08))
+#define LDX (INSN_OP(3) | INSN_OP3(0x0b))
+#define STB (INSN_OP(3) | INSN_OP3(0x05))
+#define STH (INSN_OP(3) | INSN_OP3(0x06))
+#define STW (INSN_OP(3) | INSN_OP3(0x04))
+#define STX (INSN_OP(3) | INSN_OP3(0x0e))
+#define LDUBA (INSN_OP(3) | INSN_OP3(0x11))
+#define LDSBA (INSN_OP(3) | INSN_OP3(0x19))
+#define LDUHA (INSN_OP(3) | INSN_OP3(0x12))
+#define LDSHA (INSN_OP(3) | INSN_OP3(0x1a))
+#define LDUWA (INSN_OP(3) | INSN_OP3(0x10))
+#define LDSWA (INSN_OP(3) | INSN_OP3(0x18))
+#define LDXA (INSN_OP(3) | INSN_OP3(0x1b))
+#define STBA (INSN_OP(3) | INSN_OP3(0x15))
+#define STHA (INSN_OP(3) | INSN_OP3(0x16))
+#define STWA (INSN_OP(3) | INSN_OP3(0x14))
+#define STXA (INSN_OP(3) | INSN_OP3(0x1e))
+
+#ifndef ASI_PRIMARY_LITTLE
+#define ASI_PRIMARY_LITTLE 0x88
+#endif
+
+static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2,
+ int op)
+{
+ tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
+ INSN_RS2(rs2));
+}
+
+static inline void tcg_out_arithi(TCGContext *s, int rd, int rs1,
+ uint32_t offset, int op)
+{
+ tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) |
+ INSN_IMM13(offset));
+}
+
+static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
+ int val2, int val2const, int op)
+{
+ tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1)
+ | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
+}
+
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
+{
+ tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR);
+}
+
+static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg)
+{
+ tcg_out32(s, SETHI | INSN_RD(ret) | ((arg & 0xfffffc00) >> 10));
+}
+
+static inline void tcg_out_movi_imm13(TCGContext *s, int ret, uint32_t arg)
+{
+ tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR);
+}
+
+static inline void tcg_out_movi_imm32(TCGContext *s, int ret, uint32_t arg)
+{
+ if (check_fit_tl(arg, 13))
+ tcg_out_movi_imm13(s, ret, arg);
+ else {
+ tcg_out_sethi(s, ret, arg);
+ if (arg & 0x3ff)
+ tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
+ }
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
+{
+ /* All 32-bit constants, as well as 64-bit constants with
+ no high bits set go through movi_imm32. */
+ if (TCG_TARGET_REG_BITS == 32
+ || type == TCG_TYPE_I32
+ || (arg & ~(tcg_target_long)0xffffffff) == 0) {
+ tcg_out_movi_imm32(s, ret, arg);
+ } else if (check_fit_tl(arg, 13)) {
+ /* A 13-bit constant sign-extended to 64-bits. */
+ tcg_out_movi_imm13(s, ret, arg);
+ } else if (check_fit_tl(arg, 32)) {
+ /* A 32-bit constant sign-extended to 64-bits. */
+ tcg_out_sethi(s, ret, ~arg);
+ tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR);
+ } else {
+ tcg_out_movi_imm32(s, TCG_REG_I4, arg >> (TCG_TARGET_REG_BITS / 2));
+ tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX);
+ tcg_out_movi_imm32(s, ret, arg);
+ tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR);
+ }
+}
+
+static inline void tcg_out_ld_raw(TCGContext *s, int ret,
+ tcg_target_long arg)
+{
+ tcg_out_sethi(s, ret, arg);
+ tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
+ INSN_IMM13(arg & 0x3ff));
+}
+
+static inline void tcg_out_ld_ptr(TCGContext *s, int ret,
+ tcg_target_long arg)
+{
+ if (!check_fit_tl(arg, 10))
+ tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) |
+ INSN_IMM13(arg & 0x3ff));
+ } else {
+ tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
+ INSN_IMM13(arg & 0x3ff));
+ }
+}
+
+static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op)
+{
+ if (check_fit_tl(offset, 13))
+ tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
+ INSN_IMM13(offset));
+ else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
+ tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
+ INSN_RS2(addr));
+ }
+}
+
+static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr,
+ int offset, int op, int asi)
+{
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
+ tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
+ INSN_ASI(asi) | INSN_RS2(addr));
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
+ int arg1, tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32)
+ tcg_out_ldst(s, ret, arg1, arg2, LDUW);
+ else
+ tcg_out_ldst(s, ret, arg1, arg2, LDX);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+ int arg1, tcg_target_long arg2)
+{
+ if (type == TCG_TYPE_I32)
+ tcg_out_ldst(s, arg, arg1, arg2, STW);
+ else
+ tcg_out_ldst(s, arg, arg1, arg2, STX);
+}
+
+static inline void tcg_out_sety(TCGContext *s, int rs)
+{
+ tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
+}
+
+static inline void tcg_out_rdy(TCGContext *s, int rd)
+{
+ tcg_out32(s, RDY | INSN_RD(rd));
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val != 0) {
+ if (check_fit_tl(val, 13))
+ tcg_out_arithi(s, reg, reg, val, ARITH_ADD);
+ else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val);
+ tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD);
+ }
+ }
+}
+
+static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val != 0) {
+ if (check_fit_tl(val, 13))
+ tcg_out_arithi(s, reg, reg, val, ARITH_AND);
+ else {
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val);
+ tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND);
+ }
+ }
+}
+
+static void tcg_out_div32(TCGContext *s, int rd, int rs1,
+ int val2, int val2const, int uns)
+{
+ /* Load Y with the sign/zero extension of RS1 to 64-bits. */
+ if (uns) {
+ tcg_out_sety(s, TCG_REG_G0);
+ } else {
+ tcg_out_arithi(s, TCG_REG_I5, rs1, 31, SHIFT_SRA);
+ tcg_out_sety(s, TCG_REG_I5);
+ }
+
+ tcg_out_arithc(s, rd, rs1, val2, val2const,
+ uns ? ARITH_UDIV : ARITH_SDIV);
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+ tcg_out_sethi(s, TCG_REG_G0, 0);
+}
+
+static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
+{
+ int32_t val;
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value) {
+ val = l->u.value - (tcg_target_long)s->code_ptr;
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2)
+ | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr)));
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0);
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0));
+ }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index)
+{
+ int32_t val;
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value) {
+ val = l->u.value - (tcg_target_long)s->code_ptr;
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) |
+ INSN_OFF19(l->u.value - (unsigned long)s->code_ptr)));
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0);
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | 0));
+ }
+}
+#endif
+
+static const uint8_t tcg_cond_to_bcond[10] = {
+ [TCG_COND_EQ] = COND_E,
+ [TCG_COND_NE] = COND_NE,
+ [TCG_COND_LT] = COND_L,
+ [TCG_COND_GE] = COND_GE,
+ [TCG_COND_LE] = COND_LE,
+ [TCG_COND_GT] = COND_G,
+ [TCG_COND_LTU] = COND_CS,
+ [TCG_COND_GEU] = COND_CC,
+ [TCG_COND_LEU] = COND_LEU,
+ [TCG_COND_GTU] = COND_GU,
+};
+
+static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const)
+{
+ tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC);
+}
+
+static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2);
+ tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index);
+ tcg_out_nop(s);
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2);
+ tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index);
+ tcg_out_nop(s);
+}
+#else
+static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond,
+ TCGArg al, TCGArg ah,
+ TCGArg bl, int blconst,
+ TCGArg bh, int bhconst, int label_dest)
+{
+ int cc, label_next = gen_new_label();
+
+ tcg_out_cmp(s, ah, bh, bhconst);
+
+ /* Note that we fill one of the delay slots with the second compare. */
+ switch (cond) {
+ case TCG_COND_EQ:
+ cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+ tcg_out_branch_i32(s, cc, label_next);
+ tcg_out_cmp(s, al, bl, blconst);
+ cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_EQ], 0);
+ tcg_out_branch_i32(s, cc, label_dest);
+ break;
+
+ case TCG_COND_NE:
+ cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+ tcg_out_branch_i32(s, cc, label_dest);
+ tcg_out_cmp(s, al, bl, blconst);
+ tcg_out_branch_i32(s, cc, label_dest);
+ break;
+
+ default:
+ /* ??? One could fairly easily special-case 64-bit unsigned
+ compares against 32-bit zero-extended constants. For instance,
+ we know that (unsigned)AH < 0 is false and need not emit it.
+ Similarly, (unsigned)AH > 0 being true implies AH != 0, so the
+ second branch will never be taken. */
+ cc = INSN_COND(tcg_cond_to_bcond[cond], 0);
+ tcg_out_branch_i32(s, cc, label_dest);
+ tcg_out_nop(s);
+ cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0);
+ tcg_out_branch_i32(s, cc, label_next);
+ tcg_out_cmp(s, al, bl, blconst);
+ cc = INSN_COND(tcg_cond_to_bcond[tcg_unsigned_cond(cond)], 0);
+ tcg_out_branch_i32(s, cc, label_dest);
+ break;
+ }
+ tcg_out_nop(s);
+
+ tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
+}
+#endif
+
+static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ TCGArg t;
+
+ /* For 32-bit comparisons, we can play games with ADDX/SUBX. */
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ if (c2 != 0) {
+ tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR);
+ }
+ c1 = TCG_REG_G0, c2 = ret, c2const = 0;
+ cond = (cond == TCG_COND_EQ ? TCG_COND_LEU : TCG_COND_LTU);
+ break;
+
+ case TCG_COND_GTU:
+ case TCG_COND_GEU:
+ if (c2const && c2 != 0) {
+ tcg_out_movi_imm13(s, TCG_REG_I5, c2);
+ c2 = TCG_REG_I5;
+ }
+ t = c1, c1 = c2, c2 = t, c2const = 0;
+ cond = tcg_swap_cond(cond);
+ break;
+
+ case TCG_COND_LTU:
+ case TCG_COND_LEU:
+ break;
+
+ default:
+ tcg_out_cmp(s, c1, c2, c2const);
+#if defined(__sparc_v9__) || defined(__sparc_v8plus__)
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+ | INSN_RS1(tcg_cond_to_bcond[cond])
+ | MOVCC_ICC | INSN_IMM11(1));
+#else
+ t = gen_new_label();
+ tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t);
+ tcg_out_movi_imm13(s, ret, 1);
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out_label(s, t, (tcg_target_long)s->code_ptr);
+#endif
+ return;
+ }
+
+ tcg_out_cmp(s, c1, c2, c2const);
+ if (cond == TCG_COND_LTU) {
+ tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDX);
+ } else {
+ tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBX);
+ }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ tcg_out_cmp(s, c1, c2, c2const);
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+ | INSN_RS1(tcg_cond_to_bcond[cond])
+ | MOVCC_XCC | INSN_IMM11(1));
+}
+#else
+static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
+ TCGArg al, TCGArg ah,
+ TCGArg bl, int blconst,
+ TCGArg bh, int bhconst)
+{
+ int lab;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_I5, al, bl, blconst);
+ tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst);
+ tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_AND);
+ break;
+
+ case TCG_COND_NE:
+ tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_I5, al, al, blconst);
+ tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst);
+ tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR);
+ break;
+
+ default:
+ lab = gen_new_label();
+
+ tcg_out_cmp(s, ah, bh, bhconst);
+ tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), lab);
+ tcg_out_movi_imm13(s, ret, 1);
+ tcg_out_branch_i32(s, INSN_COND(COND_NE, 1), lab);
+ tcg_out_movi_imm13(s, ret, 0);
+
+ tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), ret, al, bl, blconst);
+
+ tcg_out_label(s, lab, (tcg_target_long)s->code_ptr);
+ break;
+ }
+}
+#endif
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
+ INSN_IMM13(-TCG_TARGET_STACK_MINFRAME));
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) |
+ INSN_RS2(TCG_REG_G0));
+ tcg_out_nop(s);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static const void * const qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static const void * const qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+#endif
+
+#if TARGET_LONG_BITS == 32
+#define TARGET_LD_OP LDUW
+#else
+#define TARGET_LD_OP LDX
+#endif
+
+#if defined(CONFIG_SOFTMMU)
+#if HOST_LONG_BITS == 32
+#define TARGET_ADDEND_LD_OP LDUW
+#else
+#define TARGET_ADDEND_LD_OP LDX
+#endif
+#endif
+
+#ifdef __arch64__
+#define HOST_LD_OP LDX
+#define HOST_ST_OP STX
+#define HOST_SLL_OP SHIFT_SLLX
+#define HOST_SRA_OP SHIFT_SRAX
+#else
+#define HOST_LD_OP LDUW
+#define HOST_ST_OP STW
+#define HOST_SLL_OP SHIFT_SLL
+#define HOST_SRA_OP SHIFT_SRA
+#endif
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+ uint32_t *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+ s_bits = opc & 3;
+
+ arg0 = TCG_REG_O0;
+ arg1 = TCG_REG_O1;
+ arg2 = TCG_REG_O2;
+
+#if defined(CONFIG_SOFTMMU)
+ /* srl addr_reg, x, arg1 */
+ tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS,
+ SHIFT_SRL);
+ /* and addr_reg, x, arg0 */
+ tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+ ARITH_AND);
+
+ /* and arg1, x, arg1 */
+ tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+ /* add arg1, x, arg1 */
+ tcg_out_addi(s, arg1, offsetof(CPUState,
+ tlb_table[mem_index][0].addr_read));
+
+ /* add env, arg1, arg1 */
+ tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD);
+
+ /* ld [arg1], arg2 */
+ tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) |
+ INSN_RS2(TCG_REG_G0));
+
+ /* subcc arg0, arg2, %g0 */
+ tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
+
+ /* will become:
+ be label1
+ or
+ be,pt %xcc label1 */
+ label1_ptr = (uint32_t *)s->code_ptr;
+ tcg_out32(s, 0);
+
+ /* mov (delay slot) */
+ tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
+
+ /* mov */
+ tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+
+ /* XXX: move that code at the end of the TB */
+ /* qemu_ld_helper[s_bits](arg0, arg1) */
+ tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits]
+ - (tcg_target_ulong)s->code_ptr) >> 2)
+ & 0x3fffffff));
+ /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+ global registers */
+ // delay slot
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
+
+ /* data_reg = sign_extend(arg0) */
+ switch(opc) {
+ case 0 | 4:
+ /* sll arg0, 24/56, data_reg */
+ tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8,
+ HOST_SLL_OP);
+ /* sra data_reg, 24/56, data_reg */
+ tcg_out_arithi(s, data_reg, data_reg,
+ (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP);
+ break;
+ case 1 | 4:
+ /* sll arg0, 16/48, data_reg */
+ tcg_out_arithi(s, data_reg, arg0,
+ (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP);
+ /* sra data_reg, 16/48, data_reg */
+ tcg_out_arithi(s, data_reg, data_reg,
+ (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP);
+ break;
+ case 2 | 4:
+ /* sll arg0, 32, data_reg */
+ tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP);
+ /* sra data_reg, 32, data_reg */
+ tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP);
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ default:
+ /* mov */
+ tcg_out_mov(s, TCG_TYPE_REG, data_reg, arg0);
+ break;
+ }
+
+ /* will become:
+ ba label2 */
+ label2_ptr = (uint32_t *)s->code_ptr;
+ tcg_out32(s, 0);
+
+ /* nop (delay slot */
+ tcg_out_nop(s);
+
+ /* label1: */
+#if TARGET_LONG_BITS == 32
+ /* be label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
+ INSN_OFF22((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#else
+ /* be,pt %xcc label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#endif
+
+ /* ld [arg1 + x], arg1 */
+ tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
+ offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP);
+
+#if TARGET_LONG_BITS == 32
+ /* and addr_reg, x, arg0 */
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff);
+ tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND);
+ /* add arg0, arg1, arg0 */
+ tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD);
+#else
+ /* add addr_reg, arg1, arg0 */
+ tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD);
+#endif
+
+#else
+ arg0 = addr_reg;
+#endif
+
+ switch(opc) {
+ case 0:
+ /* ldub [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDUB);
+ break;
+ case 0 | 4:
+ /* ldsb [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDSB);
+ break;
+ case 1:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* lduh [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDUH);
+#else
+ /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 1 | 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* ldsh [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDSH);
+#else
+ /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 2:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* lduw [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDUW);
+#else
+ /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 2 | 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* ldsw [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDSW);
+#else
+ /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 3:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* ldx [arg0], data_reg */
+ tcg_out_ldst(s, data_reg, arg0, 0, LDX);
+#else
+ /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ /* label2: */
+ *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) |
+ INSN_OFF22((unsigned long)s->code_ptr -
+ (unsigned long)label2_ptr));
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+ int opc)
+{
+ int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+ uint32_t *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+
+ s_bits = opc;
+
+ arg0 = TCG_REG_O0;
+ arg1 = TCG_REG_O1;
+ arg2 = TCG_REG_O2;
+
+#if defined(CONFIG_SOFTMMU)
+ /* srl addr_reg, x, arg1 */
+ tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS,
+ SHIFT_SRL);
+
+ /* and addr_reg, x, arg0 */
+ tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
+ ARITH_AND);
+
+ /* and arg1, x, arg1 */
+ tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+
+ /* add arg1, x, arg1 */
+ tcg_out_addi(s, arg1, offsetof(CPUState,
+ tlb_table[mem_index][0].addr_write));
+
+ /* add env, arg1, arg1 */
+ tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD);
+
+ /* ld [arg1], arg2 */
+ tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) |
+ INSN_RS2(TCG_REG_G0));
+
+ /* subcc arg0, arg2, %g0 */
+ tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
+
+ /* will become:
+ be label1
+ or
+ be,pt %xcc label1 */
+ label1_ptr = (uint32_t *)s->code_ptr;
+ tcg_out32(s, 0);
+
+ /* mov (delay slot) */
+ tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
+
+ /* mov */
+ tcg_out_mov(s, TCG_TYPE_REG, arg1, data_reg);
+
+ /* mov */
+ tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index);
+
+ /* XXX: move that code at the end of the TB */
+ /* qemu_st_helper[s_bits](arg0, arg1, arg2) */
+ tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits]
+ - (tcg_target_ulong)s->code_ptr) >> 2)
+ & 0x3fffffff));
+ /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+ global registers */
+ // delay slot
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
+
+ /* will become:
+ ba label2 */
+ label2_ptr = (uint32_t *)s->code_ptr;
+ tcg_out32(s, 0);
+
+ /* nop (delay slot) */
+ tcg_out_nop(s);
+
+#if TARGET_LONG_BITS == 32
+ /* be label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
+ INSN_OFF22((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#else
+ /* be,pt %xcc label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#endif
+
+ /* ld [arg1 + x], arg1 */
+ tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
+ offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP);
+
+#if TARGET_LONG_BITS == 32
+ /* and addr_reg, x, arg0 */
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff);
+ tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND);
+ /* add arg0, arg1, arg0 */
+ tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD);
+#else
+ /* add addr_reg, arg1, arg0 */
+ tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD);
+#endif
+
+#else
+ arg0 = addr_reg;
+#endif
+
+ switch(opc) {
+ case 0:
+ /* stb data_reg, [arg0] */
+ tcg_out_ldst(s, data_reg, arg0, 0, STB);
+ break;
+ case 1:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* sth data_reg, [arg0] */
+ tcg_out_ldst(s, data_reg, arg0, 0, STH);
+#else
+ /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 2:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* stw data_reg, [arg0] */
+ tcg_out_ldst(s, data_reg, arg0, 0, STW);
+#else
+ /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ case 3:
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* stx data_reg, [arg0] */
+ tcg_out_ldst(s, data_reg, arg0, 0, STX);
+#else
+ /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */
+ tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE);
+#endif
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ /* label2: */
+ *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) |
+ INSN_OFF22((unsigned long)s->code_ptr -
+ (unsigned long)label2_ptr));
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args)
+{
+ int c;
+
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, args[0]);
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I7) |
+ INSN_IMM13(8));
+ tcg_out32(s, RESTORE | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_G0) |
+ INSN_RS2(TCG_REG_G0));
+ break;
+ case INDEX_op_goto_tb:
+ if (s->tb_jmp_offset) {
+ /* direct jump method */
+ tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000);
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
+ INSN_IMM13((args[0] & 0x1fff)));
+ s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
+ } else {
+ /* indirect jump method */
+ tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0]));
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) |
+ INSN_RS2(TCG_REG_G0));
+ }
+ tcg_out_nop(s);
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+ case INDEX_op_call:
+ if (const_args[0])
+ tcg_out32(s, CALL | ((((tcg_target_ulong)args[0]
+ - (tcg_target_ulong)s->code_ptr) >> 2)
+ & 0x3fffffff));
+ else {
+ tcg_out_ld_ptr(s, TCG_REG_I5,
+ (tcg_target_long)(s->tb_next + args[0]));
+ tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) |
+ INSN_RS2(TCG_REG_G0));
+ }
+ /* Store AREG0 in stack to avoid ugly glibc bugs that mangle
+ global registers */
+ // delay slot
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
+ tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
+ break;
+ case INDEX_op_jmp:
+ case INDEX_op_br:
+ tcg_out_branch_i32(s, COND_A, args[0]);
+ tcg_out_nop(s);
+ break;
+ case INDEX_op_movi_i32:
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
+ break;
+
+#if TCG_TARGET_REG_BITS == 64
+#define OP_32_64(x) \
+ glue(glue(case INDEX_op_, x), _i32): \
+ glue(glue(case INDEX_op_, x), _i64)
+#else
+#define OP_32_64(x) \
+ glue(glue(case INDEX_op_, x), _i32)
+#endif
+ OP_32_64(ld8u):
+ tcg_out_ldst(s, args[0], args[1], args[2], LDUB);
+ break;
+ OP_32_64(ld8s):
+ tcg_out_ldst(s, args[0], args[1], args[2], LDSB);
+ break;
+ OP_32_64(ld16u):
+ tcg_out_ldst(s, args[0], args[1], args[2], LDUH);
+ break;
+ OP_32_64(ld16s):
+ tcg_out_ldst(s, args[0], args[1], args[2], LDSH);
+ break;
+ case INDEX_op_ld_i32:
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_ld32u_i64:
+#endif
+ tcg_out_ldst(s, args[0], args[1], args[2], LDUW);
+ break;
+ OP_32_64(st8):
+ tcg_out_ldst(s, args[0], args[1], args[2], STB);
+ break;
+ OP_32_64(st16):
+ tcg_out_ldst(s, args[0], args[1], args[2], STH);
+ break;
+ case INDEX_op_st_i32:
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_st32_i64:
+#endif
+ tcg_out_ldst(s, args[0], args[1], args[2], STW);
+ break;
+ OP_32_64(add):
+ c = ARITH_ADD;
+ goto gen_arith;
+ OP_32_64(sub):
+ c = ARITH_SUB;
+ goto gen_arith;
+ OP_32_64(and):
+ c = ARITH_AND;
+ goto gen_arith;
+ OP_32_64(andc):
+ c = ARITH_ANDN;
+ goto gen_arith;
+ OP_32_64(or):
+ c = ARITH_OR;
+ goto gen_arith;
+ OP_32_64(orc):
+ c = ARITH_ORN;
+ goto gen_arith;
+ OP_32_64(xor):
+ c = ARITH_XOR;
+ goto gen_arith;
+ case INDEX_op_shl_i32:
+ c = SHIFT_SLL;
+ goto gen_arith;
+ case INDEX_op_shr_i32:
+ c = SHIFT_SRL;
+ goto gen_arith;
+ case INDEX_op_sar_i32:
+ c = SHIFT_SRA;
+ goto gen_arith;
+ case INDEX_op_mul_i32:
+ c = ARITH_UMUL;
+ goto gen_arith;
+
+ OP_32_64(neg):
+ c = ARITH_SUB;
+ goto gen_arith1;
+ OP_32_64(not):
+ c = ARITH_ORN;
+ goto gen_arith1;
+
+ case INDEX_op_div_i32:
+ tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
+ break;
+ case INDEX_op_divu_i32:
+ tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 1);
+ break;
+
+ case INDEX_op_rem_i32:
+ case INDEX_op_remu_i32:
+ tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2],
+ opc == INDEX_op_remu_i32);
+ tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2],
+ ARITH_UMUL);
+ tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB);
+ break;
+
+ case INDEX_op_brcond_i32:
+ tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
+ args[3]);
+ break;
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond_i32(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2_i32(s, args[4], args[0], args[1],
+ args[2], const_args[2],
+ args[3], const_args[3], args[5]);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
+ args[3], const_args[3],
+ args[4], const_args[4]);
+ break;
+ case INDEX_op_add2_i32:
+ tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
+ ARITH_ADDCC);
+ tcg_out_arithc(s, args[1], args[3], args[5], const_args[5],
+ ARITH_ADDX);
+ break;
+ case INDEX_op_sub2_i32:
+ tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
+ ARITH_SUBCC);
+ tcg_out_arithc(s, args[1], args[3], args[5], const_args[5],
+ ARITH_SUBX);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_arithc(s, args[0], args[2], args[3], const_args[3],
+ ARITH_UMUL);
+ tcg_out_rdy(s, args[1]);
+ break;
+#endif
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32:
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_qemu_ld32u:
+#endif
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, 2 | 4);
+ break;
+#endif
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_movi_i64:
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_ldst(s, args[0], args[1], args[2], LDSW);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ldst(s, args[0], args[1], args[2], LDX);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_ldst(s, args[0], args[1], args[2], STX);
+ break;
+ case INDEX_op_shl_i64:
+ c = SHIFT_SLLX;
+ goto gen_arith;
+ case INDEX_op_shr_i64:
+ c = SHIFT_SRLX;
+ goto gen_arith;
+ case INDEX_op_sar_i64:
+ c = SHIFT_SRAX;
+ goto gen_arith;
+ case INDEX_op_mul_i64:
+ c = ARITH_MULX;
+ goto gen_arith;
+ case INDEX_op_div_i64:
+ c = ARITH_SDIVX;
+ goto gen_arith;
+ case INDEX_op_divu_i64:
+ c = ARITH_UDIVX;
+ goto gen_arith;
+ case INDEX_op_rem_i64:
+ case INDEX_op_remu_i64:
+ tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2],
+ opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX);
+ tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2],
+ ARITH_MULX);
+ tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB);
+ break;
+ case INDEX_op_ext32s_i64:
+ if (const_args[1]) {
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], (int32_t)args[1]);
+ } else {
+ tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRA);
+ }
+ break;
+ case INDEX_op_ext32u_i64:
+ if (const_args[1]) {
+ tcg_out_movi_imm32(s, args[0], args[1]);
+ } else {
+ tcg_out_arithi(s, args[0], args[1], 0, SHIFT_SRL);
+ }
+ break;
+
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
+ args[3]);
+ break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond_i64(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+#endif
+ gen_arith:
+ tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
+ break;
+
+ gen_arith1:
+ tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
+ break;
+
+ default:
+ fprintf(stderr, "unknown opcode 0x%x\n", opc);
+ tcg_abort();
+ }
+}
+
+static const TCGTargetOpDef sparc_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "ri" } },
+ { INDEX_op_jmp, { "ri" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "r", "rJ" } },
+ { INDEX_op_mul_i32, { "r", "r", "rJ" } },
+ { INDEX_op_div_i32, { "r", "r", "rJ" } },
+ { INDEX_op_divu_i32, { "r", "r", "rJ" } },
+ { INDEX_op_rem_i32, { "r", "r", "rJ" } },
+ { INDEX_op_remu_i32, { "r", "r", "rJ" } },
+ { INDEX_op_sub_i32, { "r", "r", "rJ" } },
+ { INDEX_op_and_i32, { "r", "r", "rJ" } },
+ { INDEX_op_andc_i32, { "r", "r", "rJ" } },
+ { INDEX_op_or_i32, { "r", "r", "rJ" } },
+ { INDEX_op_orc_i32, { "r", "r", "rJ" } },
+ { INDEX_op_xor_i32, { "r", "r", "rJ" } },
+
+ { INDEX_op_shl_i32, { "r", "r", "rJ" } },
+ { INDEX_op_shr_i32, { "r", "r", "rJ" } },
+ { INDEX_op_sar_i32, { "r", "r", "rJ" } },
+
+ { INDEX_op_neg_i32, { "r", "rJ" } },
+ { INDEX_op_not_i32, { "r", "rJ" } },
+
+ { INDEX_op_brcond_i32, { "r", "rJ" } },
+ { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
+
+#if TCG_TARGET_REG_BITS == 32
+ { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } },
+ { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
+ { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
+ { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
+ { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } },
+#endif
+
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+#if TCG_TARGET_REG_BITS == 64
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
+
+ { INDEX_op_qemu_st8, { "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+
+#if TCG_TARGET_REG_BITS == 64
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+ { INDEX_op_qemu_ld64, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L" } },
+
+ { INDEX_op_add_i64, { "r", "r", "rJ" } },
+ { INDEX_op_mul_i64, { "r", "r", "rJ" } },
+ { INDEX_op_div_i64, { "r", "r", "rJ" } },
+ { INDEX_op_divu_i64, { "r", "r", "rJ" } },
+ { INDEX_op_rem_i64, { "r", "r", "rJ" } },
+ { INDEX_op_remu_i64, { "r", "r", "rJ" } },
+ { INDEX_op_sub_i64, { "r", "r", "rJ" } },
+ { INDEX_op_and_i64, { "r", "r", "rJ" } },
+ { INDEX_op_andc_i64, { "r", "r", "rJ" } },
+ { INDEX_op_or_i64, { "r", "r", "rJ" } },
+ { INDEX_op_orc_i64, { "r", "r", "rJ" } },
+ { INDEX_op_xor_i64, { "r", "r", "rJ" } },
+
+ { INDEX_op_shl_i64, { "r", "r", "rJ" } },
+ { INDEX_op_shr_i64, { "r", "r", "rJ" } },
+ { INDEX_op_sar_i64, { "r", "r", "rJ" } },
+
+ { INDEX_op_neg_i64, { "r", "rJ" } },
+ { INDEX_op_not_i64, { "r", "rJ" } },
+
+ { INDEX_op_ext32s_i64, { "r", "ri" } },
+ { INDEX_op_ext32u_i64, { "r", "ri" } },
+
+ { INDEX_op_brcond_i64, { "r", "rJ" } },
+ { INDEX_op_setcond_i64, { "r", "r", "rJ" } },
+#endif
+ { -1 },
+};
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+#if TCG_TARGET_REG_BITS == 64
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+#endif
+ tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+ (1 << TCG_REG_G1) |
+ (1 << TCG_REG_G2) |
+ (1 << TCG_REG_G3) |
+ (1 << TCG_REG_G4) |
+ (1 << TCG_REG_G5) |
+ (1 << TCG_REG_G6) |
+ (1 << TCG_REG_G7) |
+ (1 << TCG_REG_O0) |
+ (1 << TCG_REG_O1) |
+ (1 << TCG_REG_O2) |
+ (1 << TCG_REG_O3) |
+ (1 << TCG_REG_O4) |
+ (1 << TCG_REG_O5) |
+ (1 << TCG_REG_O7));
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0);
+#if TCG_TARGET_REG_BITS == 64
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use
+#endif
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7);
+ tcg_add_target_add_op_defs(sparc_op_defs);
+}
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
new file mode 100644
index 0000000..df0785e
--- /dev/null
+++ b/tcg/sparc/tcg-target.h
@@ -0,0 +1,150 @@
+/*
+ * 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_SPARC 1
+
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+#define TCG_TARGET_REG_BITS 64
+#else
+#define TCG_TARGET_REG_BITS 32
+#endif
+
+#define TCG_TARGET_WORDS_BIGENDIAN
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_G0 = 0,
+ TCG_REG_G1,
+ TCG_REG_G2,
+ TCG_REG_G3,
+ TCG_REG_G4,
+ TCG_REG_G5,
+ TCG_REG_G6,
+ TCG_REG_G7,
+ TCG_REG_O0,
+ TCG_REG_O1,
+ TCG_REG_O2,
+ TCG_REG_O3,
+ TCG_REG_O4,
+ TCG_REG_O5,
+ TCG_REG_O6,
+ TCG_REG_O7,
+ TCG_REG_L0,
+ TCG_REG_L1,
+ TCG_REG_L2,
+ TCG_REG_L3,
+ TCG_REG_L4,
+ TCG_REG_L5,
+ TCG_REG_L6,
+ TCG_REG_L7,
+ TCG_REG_I0,
+ TCG_REG_I1,
+ TCG_REG_I2,
+ TCG_REG_I3,
+ TCG_REG_I4,
+ TCG_REG_I5,
+ TCG_REG_I6,
+ TCG_REG_I7,
+};
+
+#define TCG_CT_CONST_S11 0x100
+#define TCG_CT_CONST_S13 0x200
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_I6
+#ifdef __arch64__
+// Reserve space for AREG0
+#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \
+ TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16)
+#define TCG_TARGET_STACK_ALIGN 16
+#else
+// AREG0 + one word for alignment
+#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \
+ TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME
+#define TCG_TARGET_STACK_ALIGN 8
+#endif
+
+#ifdef __arch64__
+#define TCG_TARGET_EXTEND_ARGS 1
+#endif
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_eqv_i32
+// #define TCG_TARGET_HAS_nand_i32
+// #define TCG_TARGET_HAS_nor_i32
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
+/* Note: must be synced with dyngen-exec.h */
+#ifdef CONFIG_SOLARIS
+#define TCG_AREG0 TCG_REG_G2
+#elif defined(__sparc_v9__)
+#define TCG_AREG0 TCG_REG_G5
+#else
+#define TCG_AREG0 TCG_REG_G6
+#endif
+
+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));
+}
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
new file mode 100644
index 0000000..207a89f
--- /dev/null
+++ b/tcg/tcg-op.h
@@ -0,0 +1,2533 @@
+/*
+ * 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.h"
+
+int gen_new_label(void);
+
+static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+}
+
+static inline void tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 arg1)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+}
+
+static inline void tcg_gen_op1i(TCGOpcode opc, TCGArg arg1)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = arg1;
+}
+
+static inline void tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+}
+
+static inline void tcg_gen_op2_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+}
+
+static inline void tcg_gen_op2i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGArg arg2)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op2i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGArg arg2)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op2ii(TCGOpcode opc, TCGArg arg1, TCGArg arg2)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = arg1;
+ *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op3_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+}
+
+static inline void tcg_gen_op3_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+}
+
+static inline void tcg_gen_op3i_i32(TCGOpcode opc, TCGv_i32 arg1,
+ TCGv_i32 arg2, TCGArg arg3)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = arg3;
+}
+
+static inline void tcg_gen_op3i_i64(TCGOpcode opc, TCGv_i64 arg1,
+ TCGv_i64 arg2, TCGArg arg3)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = arg3;
+}
+
+static inline void tcg_gen_ldst_op_i32(TCGOpcode opc, TCGv_i32 val,
+ TCGv_ptr base, TCGArg offset)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(val);
+ *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+ *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_ldst_op_i64(TCGOpcode opc, TCGv_i64 val,
+ TCGv_ptr base, TCGArg offset)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(val);
+ *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+ *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i32(TCGOpcode opc, TCGv_i64 val,
+ TCGv_i32 addr, TCGArg mem_index)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(val);
+ *gen_opparam_ptr++ = GET_TCGV_I32(addr);
+ *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i64(TCGOpcode opc, TCGv_i64 val,
+ TCGv_i64 addr, TCGArg mem_index)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(val);
+ *gen_opparam_ptr++ = GET_TCGV_I64(addr);
+ *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_op4_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGv_i32 arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+}
+
+static inline void tcg_gen_op4_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGv_i64 arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+}
+
+static inline void tcg_gen_op4i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGArg arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGArg arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGArg arg3, TCGArg arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = arg3;
+ *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGArg arg3, TCGArg arg4)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = arg3;
+ *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op5_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+}
+
+static inline void tcg_gen_op5_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+}
+
+static inline void tcg_gen_op5i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+ *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+ *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5ii_i32(TCGOpcode opc, TCGv_i32 arg1,
+ TCGv_i32 arg2, TCGv_i32 arg3,
+ TCGArg arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = arg4;
+ *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 arg1,
+ TCGv_i64 arg2, TCGv_i64 arg3,
+ TCGArg arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = arg4;
+ *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5,
+ TCGv_i32 arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg6);
+}
+
+static inline void tcg_gen_op6_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5,
+ TCGv_i64 arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg6);
+}
+
+static inline void tcg_gen_op6i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
+ TCGv_i32 arg3, TCGv_i32 arg4,
+ TCGv_i32 arg5, TCGArg arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+ *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
+ TCGv_i64 arg3, TCGv_i64 arg4,
+ TCGv_i64 arg5, TCGArg arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+ *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 arg1,
+ TCGv_i32 arg2, TCGv_i32 arg3,
+ TCGv_i32 arg4, TCGArg arg5, TCGArg arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+ *gen_opparam_ptr++ = arg5;
+ *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6ii_i64(TCGOpcode opc, TCGv_i64 arg1,
+ TCGv_i64 arg2, TCGv_i64 arg3,
+ TCGv_i64 arg4, TCGArg arg5, TCGArg arg6)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+ *gen_opparam_ptr++ = arg5;
+ *gen_opparam_ptr++ = arg6;
+}
+
+static inline void gen_set_label(int n)
+{
+ tcg_gen_op1i(INDEX_op_set_label, n);
+}
+
+static inline void tcg_gen_br(int label)
+{
+ tcg_gen_op1i(INDEX_op_br, label);
+}
+
+static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+ if (!TCGV_EQUAL_I32(ret, arg))
+ tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg);
+}
+
+static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg)
+{
+ tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg);
+}
+
+/* A version of dh_sizemask from def-helper.h that doesn't rely on
+ preprocessor magic. */
+static inline int tcg_gen_sizemask(int n, int is_64bit, int is_signed)
+{
+ return (is_64bit << n*2) | (is_signed << (n*2 + 1));
+}
+
+/* helper calls */
+static inline void tcg_gen_helperN(void *func, int flags, int sizemask,
+ TCGArg ret, int nargs, TCGArg *args)
+{
+ TCGv_ptr fn;
+ fn = tcg_const_ptr((tcg_target_long)func);
+ tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret,
+ nargs, args);
+ tcg_temp_free_ptr(fn);
+}
+
+/* Note: Both tcg_gen_helper32() and tcg_gen_helper64() are currently
+ reserved for helpers in tcg-runtime.c. These helpers are all const
+ and pure, hence the call to tcg_gen_callN() with TCG_CALL_CONST |
+ TCG_CALL_PURE. This may need to be adjusted if these functions
+ start to be used with other helpers. */
+static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret,
+ TCGv_i32 a, TCGv_i32 b)
+{
+ TCGv_ptr fn;
+ TCGArg args[2];
+ fn = tcg_const_ptr((tcg_target_long)func);
+ args[0] = GET_TCGV_I32(a);
+ args[1] = GET_TCGV_I32(b);
+ tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask,
+ GET_TCGV_I32(ret), 2, args);
+ tcg_temp_free_ptr(fn);
+}
+
+static inline void tcg_gen_helper64(void *func, int sizemask, TCGv_i64 ret,
+ TCGv_i64 a, TCGv_i64 b)
+{
+ TCGv_ptr fn;
+ TCGArg args[2];
+ fn = tcg_const_ptr((tcg_target_long)func);
+ args[0] = GET_TCGV_I64(a);
+ args[1] = GET_TCGV_I64(b);
+ tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask,
+ GET_TCGV_I64(ret), 2, args);
+ tcg_temp_free_ptr(fn);
+}
+
+/* 32 bit ops */
+
+static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset);
+}
+
+static inline void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_add_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2)
+{
+ TCGv_i32 t0 = tcg_const_i32(arg1);
+ tcg_gen_sub_i32(ret, t0, arg2);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_sub_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ if (TCGV_EQUAL_I32(arg1, arg2)) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_movi_i32(ret, 0);
+ } else if (arg2 == 0xffffffff) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_and_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ if (TCGV_EQUAL_I32(arg1, arg2)) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0xffffffff) {
+ tcg_gen_movi_i32(ret, 0xffffffff);
+ } else if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_or_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ if (TCGV_EQUAL_I32(arg1, arg2)) {
+ tcg_gen_movi_i32(ret, 0);
+ } else {
+ tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_xor_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_shl_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_shr_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_sar_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+ }
+}
+
+static inline void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1,
+ TCGv_i32 arg2, int label_index)
+{
+ tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index);
+}
+
+static inline void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1,
+ int32_t arg2, int label_index)
+{
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_brcond_i32(cond, arg1, t0, label_index);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret,
+ TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond);
+}
+
+static inline void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret,
+ TCGv_i32 arg1, int32_t arg2)
+{
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_setcond_i32(cond, ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_mul_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+}
+
+#ifdef TCG_TARGET_HAS_div_i32
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
+}
+#elif defined(TCG_TARGET_HAS_div2_i32)
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_sari_i32(t0, arg1, 31);
+ tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_sari_i32(t0, arg1, 31);
+ tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_movi_i32(t0, 0);
+ tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
+ tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_movi_i32(t0, 0);
+ tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
+ tcg_temp_free_i32(t0);
+}
+#else
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 32-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 0, 1);
+ sizemask |= tcg_gen_sizemask(1, 0, 1);
+ sizemask |= tcg_gen_sizemask(2, 0, 1);
+
+ tcg_gen_helper32(tcg_helper_div_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 32-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 0, 1);
+ sizemask |= tcg_gen_sizemask(1, 0, 1);
+ sizemask |= tcg_gen_sizemask(2, 0, 1);
+
+ tcg_gen_helper32(tcg_helper_rem_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 32-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 0, 0);
+ sizemask |= tcg_gen_sizemask(1, 0, 0);
+ sizemask |= tcg_gen_sizemask(2, 0, 0);
+
+ tcg_gen_helper32(tcg_helper_divu_i32, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 32-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 0, 0);
+ sizemask |= tcg_gen_sizemask(1, 0, 0);
+ sizemask |= tcg_gen_sizemask(2, 0, 0);
+
+ tcg_gen_helper32(tcg_helper_remu_i32, sizemask, ret, arg1, arg2);
+}
+#endif
+
+#if TCG_TARGET_REG_BITS == 32
+
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ if (!TCGV_EQUAL_I64(ret, arg)) {
+ tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+ }
+}
+
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
+{
+ tcg_gen_movi_i32(TCGV_LOW(ret), arg);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32);
+}
+
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), 31);
+}
+
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ /* since arg2 and ret have different types, they cannot be the
+ same temporary */
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
+ tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
+#else
+ tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+ tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4);
+#endif
+}
+
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
+}
+
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+ tcg_target_long offset)
+{
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
+ tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
+#else
+ tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
+ tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4);
+#endif
+}
+
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+ TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+ TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+ TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+ TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+ tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+ tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+}
+
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
+ tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
+}
+
+/* XXX: use generic code when basic block handling is OK or CPU
+ specific code (x86) */
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_shl_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0);
+}
+
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_shr_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0);
+}
+
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_sar_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1);
+}
+
+static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1,
+ TCGv_i64 arg2, int label_index)
+{
+ tcg_gen_op6ii_i32(INDEX_op_brcond2_i32,
+ TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+ TCGV_HIGH(arg2), cond, label_index);
+}
+
+static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
+ TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret),
+ TCGV_LOW(arg1), TCGV_HIGH(arg1),
+ TCGV_LOW(arg2), TCGV_HIGH(arg2), cond);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0;
+ TCGv_i32 t1;
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i32();
+
+ tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0),
+ TCGV_LOW(arg1), TCGV_LOW(arg2));
+
+ tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2));
+ tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
+ tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2));
+ tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
+
+ tcg_gen_mov_i64(ret, t0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i32(t1);
+}
+
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 1, 0);
+ sizemask |= tcg_gen_sizemask(1, 1, 0);
+ sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+ tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 1, 0);
+ sizemask |= tcg_gen_sizemask(1, 1, 0);
+ sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+ tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+}
+
+#else
+
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ if (!TCGV_EQUAL_I64(ret, arg))
+ tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg);
+}
+
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
+{
+ tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg);
+}
+
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset);
+}
+
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+ tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset)
+{
+ tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset);
+}
+
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ if (TCGV_EQUAL_I64(arg1, arg2)) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_and_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ if (TCGV_EQUAL_I64(arg1, arg2)) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_or_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ if (TCGV_EQUAL_I64(arg1, arg2)) {
+ tcg_gen_movi_i64(ret, 0);
+ } else {
+ tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2);
+ }
+}
+
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_xor_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_shl_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_shr_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_sar_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
+static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1,
+ TCGv_i64 arg2, int label_index)
+{
+ tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index);
+}
+
+static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
+ TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond);
+}
+
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2);
+}
+
+#ifdef TCG_TARGET_HAS_div_i64
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
+}
+#elif defined(TCG_TARGET_HAS_div2_i64)
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_sari_i64(t0, arg1, 63);
+ tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_sari_i64(t0, arg1, 63);
+ tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_movi_i64(t0, 0);
+ tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_movi_i64(t0, 0);
+ tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
+ tcg_temp_free_i64(t0);
+}
+#else
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and signed. */
+ sizemask |= tcg_gen_sizemask(0, 1, 1);
+ sizemask |= tcg_gen_sizemask(1, 1, 1);
+ sizemask |= tcg_gen_sizemask(2, 1, 1);
+
+ tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 1, 0);
+ sizemask |= tcg_gen_sizemask(1, 1, 0);
+ sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+ tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+}
+
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ int sizemask = 0;
+ /* Return value and both arguments are 64-bit and unsigned. */
+ sizemask |= tcg_gen_sizemask(0, 1, 0);
+ sizemask |= tcg_gen_sizemask(1, 1, 0);
+ sizemask |= tcg_gen_sizemask(2, 1, 0);
+
+ tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+}
+#endif
+
+#endif
+
+static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_add_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+
+static inline void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg1);
+ tcg_gen_sub_i64(ret, t0, arg2);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_sub_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+ }
+}
+static inline void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1,
+ int64_t arg2, int label_index)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_brcond_i64(cond, arg1, t0, label_index);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret,
+ TCGv_i64 arg1, int64_t arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_setcond_i64(cond, ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_mul_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+}
+
+
+/***************************************/
+/* optional operations */
+
+static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8s_i32
+ tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
+#else
+ tcg_gen_shli_i32(ret, arg, 24);
+ tcg_gen_sari_i32(ret, ret, 24);
+#endif
+}
+
+static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16s_i32
+ tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
+#else
+ tcg_gen_shli_i32(ret, arg, 16);
+ tcg_gen_sari_i32(ret, ret, 16);
+#endif
+}
+
+static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8u_i32
+ tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg);
+#else
+ tcg_gen_andi_i32(ret, arg, 0xffu);
+#endif
+}
+
+static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16u_i32
+ tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg);
+#else
+ tcg_gen_andi_i32(ret, arg, 0xffffu);
+#endif
+}
+
+/* Note: we assume the two high bytes are set to zero */
+static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap16_i32
+ tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
+#else
+ TCGv_i32 t0 = tcg_temp_new_i32();
+
+ tcg_gen_ext8u_i32(t0, arg);
+ tcg_gen_shli_i32(t0, t0, 8);
+ tcg_gen_shri_i32(ret, arg, 8);
+ tcg_gen_or_i32(ret, ret, t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap32_i32
+ tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
+#else
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+
+ tcg_gen_shli_i32(t0, arg, 24);
+
+ tcg_gen_andi_i32(t1, arg, 0x0000ff00);
+ tcg_gen_shli_i32(t1, t1, 8);
+ tcg_gen_or_i32(t0, t0, t1);
+
+ tcg_gen_shri_i32(t1, arg, 8);
+ tcg_gen_andi_i32(t1, t1, 0x0000ff00);
+ tcg_gen_or_i32(t0, t0, t1);
+
+ tcg_gen_shri_i32(t1, arg, 24);
+ tcg_gen_or_i32(ret, t0, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+#endif
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(ret, TCGV_LOW(arg));
+}
+
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+ tcg_gen_mov_i32(TCGV_LOW(ret), arg);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+}
+
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+ tcg_gen_mov_i32(TCGV_LOW(ret), arg);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+}
+
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+ tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
+
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+ tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+
+ tcg_gen_bswap32_i32(t0, TCGV_LOW(arg));
+ tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg));
+ tcg_gen_mov_i32(TCGV_LOW(ret), t1);
+ tcg_gen_mov_i32(TCGV_HIGH(ret), t0);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+}
+#else
+
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8s_i64
+ tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
+#else
+ tcg_gen_shli_i64(ret, arg, 56);
+ tcg_gen_sari_i64(ret, ret, 56);
+#endif
+}
+
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16s_i64
+ tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
+#else
+ tcg_gen_shli_i64(ret, arg, 48);
+ tcg_gen_sari_i64(ret, ret, 48);
+#endif
+}
+
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext32s_i64
+ tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
+#else
+ tcg_gen_shli_i64(ret, arg, 32);
+ tcg_gen_sari_i64(ret, ret, 32);
+#endif
+}
+
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext8u_i64
+ tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg);
+#else
+ tcg_gen_andi_i64(ret, arg, 0xffu);
+#endif
+}
+
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext16u_i64
+ tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg);
+#else
+ tcg_gen_andi_i64(ret, arg, 0xffffu);
+#endif
+}
+
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_ext32u_i64
+ tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg);
+#else
+ tcg_gen_andi_i64(ret, arg, 0xffffffffu);
+#endif
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+ registers. This will probably break MIPS64 targets. */
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
+{
+ tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+ registers */
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+ tcg_gen_ext32u_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)));
+}
+
+/* Note: we assume the target supports move between 32 and 64 bit
+ registers */
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
+{
+ tcg_gen_ext32s_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)));
+}
+
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap16_i64
+ tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
+#else
+ TCGv_i64 t0 = tcg_temp_new_i64();
+
+ tcg_gen_ext8u_i64(t0, arg);
+ tcg_gen_shli_i64(t0, t0, 8);
+ tcg_gen_shri_i64(ret, arg, 8);
+ tcg_gen_or_i64(ret, ret, t0);
+ tcg_temp_free_i64(t0);
+#endif
+}
+
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap32_i64
+ tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
+#else
+ TCGv_i64 t0, t1;
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+
+ tcg_gen_shli_i64(t0, arg, 24);
+ tcg_gen_ext32u_i64(t0, t0);
+
+ tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+ tcg_gen_shli_i64(t1, t1, 8);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 8);
+ tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 24);
+ tcg_gen_or_i64(ret, t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap64_i64
+ tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
+#else
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+
+ tcg_gen_shli_i64(t0, arg, 56);
+
+ tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+ tcg_gen_shli_i64(t1, t1, 40);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_andi_i64(t1, arg, 0x00ff0000);
+ tcg_gen_shli_i64(t1, t1, 24);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_andi_i64(t1, arg, 0xff000000);
+ tcg_gen_shli_i64(t1, t1, 8);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 8);
+ tcg_gen_andi_i64(t1, t1, 0xff000000);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 24);
+ tcg_gen_andi_i64(t1, t1, 0x00ff0000);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 40);
+ tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ tcg_gen_shri_i64(t1, arg, 56);
+ tcg_gen_or_i64(ret, t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+#endif
+}
+
+#endif
+
+static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_neg_i32
+ tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg);
+#else
+ TCGv_i32 t0 = tcg_const_i32(0);
+ tcg_gen_sub_i32(ret, t0, arg);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_neg_i64
+ tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg);
+#else
+ TCGv_i64 t0 = tcg_const_i64(0);
+ tcg_gen_sub_i64(ret, t0, arg);
+ tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg)
+{
+#ifdef TCG_TARGET_HAS_not_i32
+ tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg);
+#else
+ tcg_gen_xori_i32(ret, arg, -1);
+#endif
+}
+
+static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_not_i64
+ tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
+#elif defined(TCG_TARGET_HAS_not_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+ tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+#else
+ tcg_gen_xori_i64(ret, arg, -1);
+#endif
+}
+
+static inline void tcg_gen_discard_i32(TCGv_i32 arg)
+{
+ tcg_gen_op1_i32(INDEX_op_discard, arg);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
+{
+ tcg_gen_discard_i32(TCGV_LOW(arg));
+ tcg_gen_discard_i32(TCGV_HIGH(arg));
+}
+#else
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
+{
+ tcg_gen_op1_i64(INDEX_op_discard, arg);
+}
+#endif
+
+static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+ tcg_gen_mov_i32(TCGV_LOW(dest), low);
+ tcg_gen_mov_i32(TCGV_HIGH(dest), high);
+#else
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ /* This extension is only needed for type correctness.
+ We may be able to do better given target specific information. */
+ tcg_gen_extu_i32_i64(tmp, high);
+ tcg_gen_shli_i64(tmp, tmp, 32);
+ tcg_gen_extu_i32_i64(dest, low);
+ tcg_gen_or_i64(dest, dest, tmp);
+ tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+ tcg_gen_concat_i32_i64(dest, TCGV_LOW(low), TCGV_LOW(high));
+#else
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_ext32u_i64(dest, low);
+ tcg_gen_shli_i64(tmp, high, 32);
+ tcg_gen_or_i64(dest, dest, tmp);
+ tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_andc_i32
+ tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
+#else
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_not_i32(t0, arg2);
+ tcg_gen_and_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_andc_i64
+ tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_andc_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, arg2);
+ tcg_gen_and_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_eqv_i32
+ tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2);
+#else
+ tcg_gen_xor_i32(ret, arg1, arg2);
+ tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_eqv_i64
+ tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_eqv_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+ tcg_gen_xor_i64(ret, arg1, arg2);
+ tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_nand_i32
+ tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2);
+#else
+ tcg_gen_and_i32(ret, arg1, arg2);
+ tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_nand_i64
+ tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_nand_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+ tcg_gen_and_i64(ret, arg1, arg2);
+ tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_nor_i32
+ tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2);
+#else
+ tcg_gen_or_i32(ret, arg1, arg2);
+ tcg_gen_not_i32(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_nor_i64
+ tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_nor_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+ tcg_gen_or_i64(ret, arg1, arg2);
+ tcg_gen_not_i64(ret, ret);
+#endif
+}
+
+static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_orc_i32
+ tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
+#else
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_not_i32(t0, arg2);
+ tcg_gen_or_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_orc_i64
+ tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_orc_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, arg2);
+ tcg_gen_or_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+#endif
+}
+
+static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+ tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
+#else
+ TCGv_i32 t0, t1;
+
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_shl_i32(t0, arg1, arg2);
+ tcg_gen_subfi_i32(t1, 32, arg2);
+ tcg_gen_shr_i32(t1, arg1, t1);
+ tcg_gen_or_i32(ret, t0, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+ tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
+#else
+ TCGv_i64 t0, t1;
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ tcg_gen_shl_i64(t0, arg1, arg2);
+ tcg_gen_subfi_i64(t1, 64, arg2);
+ tcg_gen_shr_i64(t1, arg1, t1);
+ tcg_gen_or_i64(ret, t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+#ifdef TCG_TARGET_HAS_rot_i32
+ TCGv_i32 t0 = tcg_const_i32(arg2);
+ tcg_gen_rotl_i32(ret, arg1, t0);
+ tcg_temp_free_i32(t0);
+#else
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_shli_i32(t0, arg1, arg2);
+ tcg_gen_shri_i32(t1, arg1, 32 - arg2);
+ tcg_gen_or_i32(ret, t0, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+#endif
+ }
+}
+
+static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+#ifdef TCG_TARGET_HAS_rot_i64
+ TCGv_i64 t0 = tcg_const_i64(arg2);
+ tcg_gen_rotl_i64(ret, arg1, t0);
+ tcg_temp_free_i64(t0);
+#else
+ TCGv_i64 t0, t1;
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ tcg_gen_shli_i64(t0, arg1, arg2);
+ tcg_gen_shri_i64(t1, arg1, 64 - arg2);
+ tcg_gen_or_i64(ret, t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+#endif
+ }
+}
+
+static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+ tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
+#else
+ TCGv_i32 t0, t1;
+
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_shr_i32(t0, arg1, arg2);
+ tcg_gen_subfi_i32(t1, 32, arg2);
+ tcg_gen_shl_i32(t1, arg1, t1);
+ tcg_gen_or_i32(ret, t0, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+ tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
+#else
+ TCGv_i64 t0, t1;
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ tcg_gen_shr_i64(t0, arg1, arg2);
+ tcg_gen_subfi_i64(t1, 64, arg2);
+ tcg_gen_shl_i64(t1, arg1, t1);
+ tcg_gen_or_i64(ret, t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i32(ret, arg1);
+ } else {
+ tcg_gen_rotli_i32(ret, arg1, 32 - arg2);
+ }
+}
+
+static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+ /* some cases can be optimized here */
+ if (arg2 == 0) {
+ tcg_gen_mov_i64(ret, arg1);
+ } else {
+ tcg_gen_rotli_i64(ret, arg1, 64 - arg2);
+ }
+}
+
+static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
+ TCGv_i32 arg2, unsigned int ofs,
+ unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i32
+ tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
+#else
+ uint32_t mask = (1u << len) - 1;
+ TCGv_i32 t1 = tcg_temp_new_i32 ();
+
+ tcg_gen_andi_i32(t1, arg2, mask);
+ tcg_gen_shli_i32(t1, t1, ofs);
+ tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
+ tcg_gen_or_i32(ret, ret, t1);
+
+ tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
+ TCGv_i64 arg2, unsigned int ofs,
+ unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i64
+ tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
+#else
+ uint64_t mask = (1ull << len) - 1;
+ TCGv_i64 t1 = tcg_temp_new_i64 ();
+
+ tcg_gen_andi_i64(t1, arg2, mask);
+ tcg_gen_shli_i64(t1, t1, ofs);
+ tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
+ tcg_gen_or_i64(ret, ret, t1);
+
+ tcg_temp_free_i64(t1);
+#endif
+}
+
+/***************************************/
+/* QEMU specific operations. Their type depend on the QEMU CPU
+ type. */
+#ifndef TARGET_LONG_BITS
+#error must include QEMU headers
+#endif
+
+#if TARGET_LONG_BITS == 32
+#define TCGv TCGv_i32
+#define tcg_temp_new() tcg_temp_new_i32()
+#define tcg_global_reg_new tcg_global_reg_new_i32
+#define tcg_global_mem_new tcg_global_mem_new_i32
+#define tcg_temp_local_new() tcg_temp_local_new_i32()
+#define tcg_temp_free tcg_temp_free_i32
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32
+#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b)
+#else
+#define TCGv TCGv_i64
+#define tcg_temp_new() tcg_temp_new_i64()
+#define tcg_global_reg_new tcg_global_reg_new_i64
+#define tcg_global_mem_new tcg_global_mem_new_i64
+#define tcg_temp_local_new() tcg_temp_local_new_i64()
+#define tcg_temp_free tcg_temp_free_i64
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64
+#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b)
+#endif
+
+/* debug info: write the PC of the corresponding QEMU CPU instruction */
+static inline void tcg_gen_debug_insn_start(uint64_t pc)
+{
+ /* XXX: must really use a 32 bit size for TCGArg in all cases */
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+ tcg_gen_op2ii(INDEX_op_debug_insn_start,
+ (uint32_t)(pc), (uint32_t)(pc >> 32));
+#else
+ tcg_gen_op1i(INDEX_op_debug_insn_start, pc);
+#endif
+}
+
+static inline void tcg_gen_exit_tb(tcg_target_long val)
+{
+ tcg_gen_op1i(INDEX_op_exit_tb, val);
+}
+
+static inline void tcg_gen_goto_tb(int idx)
+{
+ tcg_gen_op1i(INDEX_op_goto_tb, idx);
+}
+
+#if TCG_TARGET_REG_BITS == 32
+static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld8u, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld8s, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld16u, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld16s, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld32, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld32, TCGV_LOW(ret), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op4i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), addr, mem_index);
+#else
+ tcg_gen_op5i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret),
+ TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_st8, arg, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_st8, TCGV_LOW(arg), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_st16, arg, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_st16, TCGV_LOW(arg), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op3i_i32(INDEX_op_qemu_st32, arg, addr, mem_index);
+#else
+ tcg_gen_op4i_i32(INDEX_op_qemu_st32, TCGV_LOW(arg), TCGV_LOW(addr),
+ TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_op4i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), addr,
+ mem_index);
+#else
+ tcg_gen_op5i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg),
+ TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
+#endif
+}
+
+#define tcg_gen_ld_ptr tcg_gen_ld_i32
+#define tcg_gen_discard_ptr tcg_gen_discard_i32
+
+#else /* TCG_TARGET_REG_BITS == 32 */
+
+static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32u, ret, addr, mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
+{
+#if TARGET_LONG_BITS == 32
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32, ret, addr, mem_index);
+#else
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32s, ret, addr, mem_index);
+#endif
+}
+
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_ld64, ret, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_st8, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_st16, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op(INDEX_op_qemu_st32, arg, addr, mem_index);
+}
+
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
+{
+ tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index);
+}
+
+#define tcg_gen_ld_ptr tcg_gen_ld_i64
+#define tcg_gen_discard_ptr tcg_gen_discard_i64
+
+#endif /* TCG_TARGET_REG_BITS != 32 */
+
+#if TARGET_LONG_BITS == 64
+#define tcg_gen_movi_tl tcg_gen_movi_i64
+#define tcg_gen_mov_tl tcg_gen_mov_i64
+#define tcg_gen_ld8u_tl tcg_gen_ld8u_i64
+#define tcg_gen_ld8s_tl tcg_gen_ld8s_i64
+#define tcg_gen_ld16u_tl tcg_gen_ld16u_i64
+#define tcg_gen_ld16s_tl tcg_gen_ld16s_i64
+#define tcg_gen_ld32u_tl tcg_gen_ld32u_i64
+#define tcg_gen_ld32s_tl tcg_gen_ld32s_i64
+#define tcg_gen_ld_tl tcg_gen_ld_i64
+#define tcg_gen_st8_tl tcg_gen_st8_i64
+#define tcg_gen_st16_tl tcg_gen_st16_i64
+#define tcg_gen_st32_tl tcg_gen_st32_i64
+#define tcg_gen_st_tl tcg_gen_st_i64
+#define tcg_gen_add_tl tcg_gen_add_i64
+#define tcg_gen_addi_tl tcg_gen_addi_i64
+#define tcg_gen_sub_tl tcg_gen_sub_i64
+#define tcg_gen_neg_tl tcg_gen_neg_i64
+#define tcg_gen_subfi_tl tcg_gen_subfi_i64
+#define tcg_gen_subi_tl tcg_gen_subi_i64
+#define tcg_gen_and_tl tcg_gen_and_i64
+#define tcg_gen_andi_tl tcg_gen_andi_i64
+#define tcg_gen_or_tl tcg_gen_or_i64
+#define tcg_gen_ori_tl tcg_gen_ori_i64
+#define tcg_gen_xor_tl tcg_gen_xor_i64
+#define tcg_gen_xori_tl tcg_gen_xori_i64
+#define tcg_gen_not_tl tcg_gen_not_i64
+#define tcg_gen_shl_tl tcg_gen_shl_i64
+#define tcg_gen_shli_tl tcg_gen_shli_i64
+#define tcg_gen_shr_tl tcg_gen_shr_i64
+#define tcg_gen_shri_tl tcg_gen_shri_i64
+#define tcg_gen_sar_tl tcg_gen_sar_i64
+#define tcg_gen_sari_tl tcg_gen_sari_i64
+#define tcg_gen_brcond_tl tcg_gen_brcond_i64
+#define tcg_gen_brcondi_tl tcg_gen_brcondi_i64
+#define tcg_gen_setcond_tl tcg_gen_setcond_i64
+#define tcg_gen_setcondi_tl tcg_gen_setcondi_i64
+#define tcg_gen_mul_tl tcg_gen_mul_i64
+#define tcg_gen_muli_tl tcg_gen_muli_i64
+#define tcg_gen_div_tl tcg_gen_div_i64
+#define tcg_gen_rem_tl tcg_gen_rem_i64
+#define tcg_gen_divu_tl tcg_gen_divu_i64
+#define tcg_gen_remu_tl tcg_gen_remu_i64
+#define tcg_gen_discard_tl tcg_gen_discard_i64
+#define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32
+#define tcg_gen_trunc_i64_tl tcg_gen_mov_i64
+#define tcg_gen_extu_i32_tl tcg_gen_extu_i32_i64
+#define tcg_gen_ext_i32_tl tcg_gen_ext_i32_i64
+#define tcg_gen_extu_tl_i64 tcg_gen_mov_i64
+#define tcg_gen_ext_tl_i64 tcg_gen_mov_i64
+#define tcg_gen_ext8u_tl tcg_gen_ext8u_i64
+#define tcg_gen_ext8s_tl tcg_gen_ext8s_i64
+#define tcg_gen_ext16u_tl tcg_gen_ext16u_i64
+#define tcg_gen_ext16s_tl tcg_gen_ext16s_i64
+#define tcg_gen_ext32u_tl tcg_gen_ext32u_i64
+#define tcg_gen_ext32s_tl tcg_gen_ext32s_i64
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i64
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64
+#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64
+#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i64
+#define tcg_gen_eqv_tl tcg_gen_eqv_i64
+#define tcg_gen_nand_tl tcg_gen_nand_i64
+#define tcg_gen_nor_tl tcg_gen_nor_i64
+#define tcg_gen_orc_tl tcg_gen_orc_i64
+#define tcg_gen_rotl_tl tcg_gen_rotl_i64
+#define tcg_gen_rotli_tl tcg_gen_rotli_i64
+#define tcg_gen_rotr_tl tcg_gen_rotr_i64
+#define tcg_gen_rotri_tl tcg_gen_rotri_i64
+#define tcg_gen_deposit_tl tcg_gen_deposit_i64
+#define tcg_const_tl tcg_const_i64
+#define tcg_const_local_tl tcg_const_local_i64
+#else
+#define tcg_gen_movi_tl tcg_gen_movi_i32
+#define tcg_gen_mov_tl tcg_gen_mov_i32
+#define tcg_gen_ld8u_tl tcg_gen_ld8u_i32
+#define tcg_gen_ld8s_tl tcg_gen_ld8s_i32
+#define tcg_gen_ld16u_tl tcg_gen_ld16u_i32
+#define tcg_gen_ld16s_tl tcg_gen_ld16s_i32
+#define tcg_gen_ld32u_tl tcg_gen_ld_i32
+#define tcg_gen_ld32s_tl tcg_gen_ld_i32
+#define tcg_gen_ld_tl tcg_gen_ld_i32
+#define tcg_gen_st8_tl tcg_gen_st8_i32
+#define tcg_gen_st16_tl tcg_gen_st16_i32
+#define tcg_gen_st32_tl tcg_gen_st_i32
+#define tcg_gen_st_tl tcg_gen_st_i32
+#define tcg_gen_add_tl tcg_gen_add_i32
+#define tcg_gen_addi_tl tcg_gen_addi_i32
+#define tcg_gen_sub_tl tcg_gen_sub_i32
+#define tcg_gen_neg_tl tcg_gen_neg_i32
+#define tcg_gen_subfi_tl tcg_gen_subfi_i32
+#define tcg_gen_subi_tl tcg_gen_subi_i32
+#define tcg_gen_and_tl tcg_gen_and_i32
+#define tcg_gen_andi_tl tcg_gen_andi_i32
+#define tcg_gen_or_tl tcg_gen_or_i32
+#define tcg_gen_ori_tl tcg_gen_ori_i32
+#define tcg_gen_xor_tl tcg_gen_xor_i32
+#define tcg_gen_xori_tl tcg_gen_xori_i32
+#define tcg_gen_not_tl tcg_gen_not_i32
+#define tcg_gen_shl_tl tcg_gen_shl_i32
+#define tcg_gen_shli_tl tcg_gen_shli_i32
+#define tcg_gen_shr_tl tcg_gen_shr_i32
+#define tcg_gen_shri_tl tcg_gen_shri_i32
+#define tcg_gen_sar_tl tcg_gen_sar_i32
+#define tcg_gen_sari_tl tcg_gen_sari_i32
+#define tcg_gen_brcond_tl tcg_gen_brcond_i32
+#define tcg_gen_brcondi_tl tcg_gen_brcondi_i32
+#define tcg_gen_setcond_tl tcg_gen_setcond_i32
+#define tcg_gen_setcondi_tl tcg_gen_setcondi_i32
+#define tcg_gen_mul_tl tcg_gen_mul_i32
+#define tcg_gen_muli_tl tcg_gen_muli_i32
+#define tcg_gen_div_tl tcg_gen_div_i32
+#define tcg_gen_rem_tl tcg_gen_rem_i32
+#define tcg_gen_divu_tl tcg_gen_divu_i32
+#define tcg_gen_remu_tl tcg_gen_remu_i32
+#define tcg_gen_discard_tl tcg_gen_discard_i32
+#define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32
+#define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32
+#define tcg_gen_extu_i32_tl tcg_gen_mov_i32
+#define tcg_gen_ext_i32_tl tcg_gen_mov_i32
+#define tcg_gen_extu_tl_i64 tcg_gen_extu_i32_i64
+#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64
+#define tcg_gen_ext8u_tl tcg_gen_ext8u_i32
+#define tcg_gen_ext8s_tl tcg_gen_ext8s_i32
+#define tcg_gen_ext16u_tl tcg_gen_ext16u_i32
+#define tcg_gen_ext16s_tl tcg_gen_ext16s_i32
+#define tcg_gen_ext32u_tl tcg_gen_mov_i32
+#define tcg_gen_ext32s_tl tcg_gen_mov_i32
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32
+#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i32
+#define tcg_gen_eqv_tl tcg_gen_eqv_i32
+#define tcg_gen_nand_tl tcg_gen_nand_i32
+#define tcg_gen_nor_tl tcg_gen_nor_i32
+#define tcg_gen_orc_tl tcg_gen_orc_i32
+#define tcg_gen_rotl_tl tcg_gen_rotl_i32
+#define tcg_gen_rotli_tl tcg_gen_rotli_i32
+#define tcg_gen_rotr_tl tcg_gen_rotr_i32
+#define tcg_gen_rotri_tl tcg_gen_rotri_i32
+#define tcg_gen_deposit_tl tcg_gen_deposit_i32
+#define tcg_const_tl tcg_const_i32
+#define tcg_const_local_tl tcg_const_local_i32
+#endif
+
+#if TCG_TARGET_REG_BITS == 32
+#define tcg_gen_add_ptr tcg_gen_add_i32
+#define tcg_gen_addi_ptr tcg_gen_addi_i32
+#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32
+#else /* TCG_TARGET_REG_BITS == 32 */
+#define tcg_gen_add_ptr tcg_gen_add_i64
+#define tcg_gen_addi_ptr tcg_gen_addi_i64
+#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64
+#endif /* TCG_TARGET_REG_BITS != 32 */
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
new file mode 100644
index 0000000..2c7ca1a
--- /dev/null
+++ b/tcg/tcg-opc.h
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+/*
+ * DEF(name, oargs, iargs, cargs, flags)
+ */
+
+/* predefined ops */
+DEF(end, 0, 0, 0, 0) /* must be kept first */
+DEF(nop, 0, 0, 0, 0)
+DEF(nop1, 0, 0, 1, 0)
+DEF(nop2, 0, 0, 2, 0)
+DEF(nop3, 0, 0, 3, 0)
+DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */
+
+DEF(discard, 1, 0, 0, 0)
+
+DEF(set_label, 0, 0, 1, 0)
+DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
+DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+
+DEF(mov_i32, 1, 1, 0, 0)
+DEF(movi_i32, 1, 0, 1, 0)
+DEF(setcond_i32, 1, 2, 1, 0)
+/* load/store */
+DEF(ld8u_i32, 1, 1, 1, 0)
+DEF(ld8s_i32, 1, 1, 1, 0)
+DEF(ld16u_i32, 1, 1, 1, 0)
+DEF(ld16s_i32, 1, 1, 1, 0)
+DEF(ld_i32, 1, 1, 1, 0)
+DEF(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+/* arith */
+DEF(add_i32, 1, 2, 0, 0)
+DEF(sub_i32, 1, 2, 0, 0)
+DEF(mul_i32, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_div_i32
+DEF(div_i32, 1, 2, 0, 0)
+DEF(divu_i32, 1, 2, 0, 0)
+DEF(rem_i32, 1, 2, 0, 0)
+DEF(remu_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_div2_i32
+DEF(div2_i32, 2, 3, 0, 0)
+DEF(divu2_i32, 2, 3, 0, 0)
+#endif
+DEF(and_i32, 1, 2, 0, 0)
+DEF(or_i32, 1, 2, 0, 0)
+DEF(xor_i32, 1, 2, 0, 0)
+/* shifts/rotates */
+DEF(shl_i32, 1, 2, 0, 0)
+DEF(shr_i32, 1, 2, 0, 0)
+DEF(sar_i32, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i32
+DEF(rotl_i32, 1, 2, 0, 0)
+DEF(rotr_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_deposit_i32
+DEF(deposit_i32, 1, 2, 2, 0)
+#endif
+
+DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+#if TCG_TARGET_REG_BITS == 32
+DEF(add2_i32, 2, 4, 0, 0)
+DEF(sub2_i32, 2, 4, 0, 0)
+DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(mulu2_i32, 2, 2, 0, 0)
+DEF(setcond2_i32, 1, 4, 1, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8s_i32
+DEF(ext8s_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16s_i32
+DEF(ext16s_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8u_i32
+DEF(ext8u_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16u_i32
+DEF(ext16u_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap16_i32
+DEF(bswap16_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap32_i32
+DEF(bswap32_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i32
+DEF(not_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_neg_i32
+DEF(neg_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_andc_i32
+DEF(andc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i32
+DEF(orc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_eqv_i32
+DEF(eqv_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nand_i32
+DEF(nand_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nor_i32
+DEF(nor_i32, 1, 2, 0, 0)
+#endif
+
+#if TCG_TARGET_REG_BITS == 64
+DEF(mov_i64, 1, 1, 0, 0)
+DEF(movi_i64, 1, 0, 1, 0)
+DEF(setcond_i64, 1, 2, 1, 0)
+/* load/store */
+DEF(ld8u_i64, 1, 1, 1, 0)
+DEF(ld8s_i64, 1, 1, 1, 0)
+DEF(ld16u_i64, 1, 1, 1, 0)
+DEF(ld16s_i64, 1, 1, 1, 0)
+DEF(ld32u_i64, 1, 1, 1, 0)
+DEF(ld32s_i64, 1, 1, 1, 0)
+DEF(ld_i64, 1, 1, 1, 0)
+DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+/* arith */
+DEF(add_i64, 1, 2, 0, 0)
+DEF(sub_i64, 1, 2, 0, 0)
+DEF(mul_i64, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_div_i64
+DEF(div_i64, 1, 2, 0, 0)
+DEF(divu_i64, 1, 2, 0, 0)
+DEF(rem_i64, 1, 2, 0, 0)
+DEF(remu_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_div2_i64
+DEF(div2_i64, 2, 3, 0, 0)
+DEF(divu2_i64, 2, 3, 0, 0)
+#endif
+DEF(and_i64, 1, 2, 0, 0)
+DEF(or_i64, 1, 2, 0, 0)
+DEF(xor_i64, 1, 2, 0, 0)
+/* shifts/rotates */
+DEF(shl_i64, 1, 2, 0, 0)
+DEF(shr_i64, 1, 2, 0, 0)
+DEF(sar_i64, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i64
+DEF(rotl_i64, 1, 2, 0, 0)
+DEF(rotr_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_deposit_i64
+DEF(deposit_i64, 1, 2, 2, 0)
+#endif
+
+DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+#ifdef TCG_TARGET_HAS_ext8s_i64
+DEF(ext8s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16s_i64
+DEF(ext16s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext32s_i64
+DEF(ext32s_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext8u_i64
+DEF(ext8u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext16u_i64
+DEF(ext16u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_ext32u_i64
+DEF(ext32u_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap16_i64
+DEF(bswap16_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap32_i64
+DEF(bswap32_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap64_i64
+DEF(bswap64_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i64
+DEF(not_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_neg_i64
+DEF(neg_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_andc_i64
+DEF(andc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i64
+DEF(orc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_eqv_i64
+DEF(eqv_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nand_i64
+DEF(nand_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_nor_i64
+DEF(nor_i64, 1, 2, 0, 0)
+#endif
+#endif
+
+/* QEMU specific */
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+DEF(debug_insn_start, 0, 0, 2, 0)
+#else
+DEF(debug_insn_start, 0, 0, 1, 0)
+#endif
+DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+/* 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
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld32, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+#if TARGET_LONG_BITS == 32
+DEF(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#else
+DEF(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+#endif
+
+#else /* TCG_TARGET_REG_BITS == 32 */
+
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+
+#endif /* TCG_TARGET_REG_BITS != 32 */
+
+#undef DEF
diff --git a/tcg/tcg-runtime.h b/tcg/tcg-runtime.h
new file mode 100644
index 0000000..5615b13
--- /dev/null
+++ b/tcg/tcg-runtime.h
@@ -0,0 +1,18 @@
+#ifndef TCG_RUNTIME_H
+#define TCG_RUNTIME_H
+
+/* tcg-runtime.c */
+int32_t tcg_helper_div_i32(int32_t arg1, int32_t arg2);
+int32_t tcg_helper_rem_i32(int32_t arg1, int32_t arg2);
+uint32_t tcg_helper_divu_i32(uint32_t arg1, uint32_t arg2);
+uint32_t tcg_helper_remu_i32(uint32_t arg1, uint32_t arg2);
+
+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);
+
+#endif
diff --git a/tcg/tcg.c b/tcg/tcg.c
new file mode 100644
index 0000000..5dd6a2c
--- /dev/null
+++ b/tcg/tcg.c
@@ -0,0 +1,2175 @@
+/*
+ * 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 it to use liveness analysis (better code) */
+#define USE_LIVENESS_ANALYSIS
+
+#include "config.h"
+
+#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
+/* define it to suppress various consistency checks (faster) */
+#define NDEBUG
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#ifdef _WIN32
+#include <malloc.h>
+#endif
+#ifdef _AIX
+#include <alloca.h>
+#endif
+
+#include "qemu-common.h"
+#include "cache-utils.h"
+#include "host-utils.h"
+#include "qemu-timer.h"
+
+/* Note: the long term plan is to reduce the dependancies on the QEMU
+ CPU definitions. Currently they are used for qemu_ld/st
+ instructions */
+#define NO_CPU_IO_DEFS
+#include "cpu.h"
+#include "exec-all.h"
+
+#include "tcg-op.h"
+#include "elf.h"
+
+#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
+#error GUEST_BASE not supported on this host.
+#endif
+
+static void tcg_target_init(TCGContext *s);
+static void tcg_target_qemu_prologue(TCGContext *s);
+static void patch_reloc(uint8_t *code_ptr, int type,
+ tcg_target_long value, tcg_target_long addend);
+
+static TCGOpDef tcg_op_defs[] = {
+#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
+#include "tcg-opc.h"
+#undef DEF
+};
+
+static TCGRegSet tcg_target_available_regs[2];
+static TCGRegSet tcg_target_call_clobber_regs;
+
+/* XXX: move that inside the context */
+uint16_t *gen_opc_ptr;
+TCGArg *gen_opparam_ptr;
+
+static inline void tcg_out8(TCGContext *s, uint8_t v)
+{
+ *s->code_ptr++ = v;
+}
+
+static inline void tcg_out16(TCGContext *s, uint16_t v)
+{
+ *(uint16_t *)s->code_ptr = v;
+ s->code_ptr += 2;
+}
+
+static inline void tcg_out32(TCGContext *s, uint32_t v)
+{
+ *(uint32_t *)s->code_ptr = v;
+ s->code_ptr += 4;
+}
+
+/* label relocation processing */
+
+static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
+ int label_index, long addend)
+{
+ TCGLabel *l;
+ TCGRelocation *r;
+
+ l = &s->labels[label_index];
+ if (l->has_value) {
+ /* FIXME: This may break relocations on RISC targets that
+ modify instruction fields in place. The caller may not have
+ written the initial value. */
+ patch_reloc(code_ptr, type, l->u.value, addend);
+ } else {
+ /* add a new relocation entry */
+ r = tcg_malloc(sizeof(TCGRelocation));
+ r->type = type;
+ r->ptr = code_ptr;
+ r->addend = addend;
+ r->next = l->u.first_reloc;
+ l->u.first_reloc = r;
+ }
+}
+
+static void tcg_out_label(TCGContext *s, int label_index,
+ tcg_target_long value)
+{
+ TCGLabel *l;
+ TCGRelocation *r;
+
+ l = &s->labels[label_index];
+ if (l->has_value)
+ tcg_abort();
+ r = l->u.first_reloc;
+ while (r != NULL) {
+ patch_reloc(r->ptr, r->type, value, r->addend);
+ r = r->next;
+ }
+ l->has_value = 1;
+ l->u.value = value;
+}
+
+int gen_new_label(void)
+{
+ TCGContext *s = &tcg_ctx;
+ int idx;
+ TCGLabel *l;
+
+ if (s->nb_labels >= TCG_MAX_LABELS)
+ tcg_abort();
+ idx = s->nb_labels++;
+ l = &s->labels[idx];
+ l->has_value = 0;
+ l->u.first_reloc = NULL;
+ return idx;
+}
+
+#include "tcg-target.c"
+
+/* pool based memory allocation */
+void *tcg_malloc_internal(TCGContext *s, int size)
+{
+ TCGPool *p;
+ int pool_size;
+
+ if (size > TCG_POOL_CHUNK_SIZE) {
+ /* big malloc: insert a new pool (XXX: could optimize) */
+ p = qemu_malloc(sizeof(TCGPool) + size);
+ p->size = size;
+ if (s->pool_current)
+ s->pool_current->next = p;
+ else
+ s->pool_first = p;
+ p->next = s->pool_current;
+ } else {
+ p = s->pool_current;
+ if (!p) {
+ p = s->pool_first;
+ if (!p)
+ goto new_pool;
+ } else {
+ if (!p->next) {
+ new_pool:
+ pool_size = TCG_POOL_CHUNK_SIZE;
+ p = qemu_malloc(sizeof(TCGPool) + pool_size);
+ p->size = pool_size;
+ p->next = NULL;
+ if (s->pool_current)
+ s->pool_current->next = p;
+ else
+ s->pool_first = p;
+ } else {
+ p = p->next;
+ }
+ }
+ }
+ s->pool_current = p;
+ s->pool_cur = p->data + size;
+ s->pool_end = p->data + p->size;
+ return p->data;
+}
+
+void tcg_pool_reset(TCGContext *s)
+{
+ s->pool_cur = s->pool_end = NULL;
+ s->pool_current = NULL;
+}
+
+void tcg_context_init(TCGContext *s)
+{
+ int op, total_args, n;
+ TCGOpDef *def;
+ TCGArgConstraint *args_ct;
+ int *sorted_args;
+
+ memset(s, 0, sizeof(*s));
+ s->temps = s->static_temps;
+ s->nb_globals = 0;
+
+ /* Count total number of arguments and allocate the corresponding
+ space */
+ total_args = 0;
+ for(op = 0; op < NB_OPS; op++) {
+ def = &tcg_op_defs[op];
+ n = def->nb_iargs + def->nb_oargs;
+ total_args += n;
+ }
+
+ args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
+ sorted_args = qemu_malloc(sizeof(int) * total_args);
+
+ for(op = 0; op < NB_OPS; op++) {
+ def = &tcg_op_defs[op];
+ def->args_ct = args_ct;
+ def->sorted_args = sorted_args;
+ n = def->nb_iargs + def->nb_oargs;
+ sorted_args += n;
+ args_ct += n;
+ }
+
+ tcg_target_init(s);
+}
+
+void tcg_prologue_init(TCGContext *s)
+{
+ /* init global prologue and epilogue */
+ s->code_buf = code_gen_prologue;
+ s->code_ptr = s->code_buf;
+ tcg_target_qemu_prologue(s);
+ flush_icache_range((unsigned long)s->code_buf,
+ (unsigned long)s->code_ptr);
+}
+
+void tcg_set_frame(TCGContext *s, int reg,
+ tcg_target_long start, tcg_target_long size)
+{
+ s->frame_start = start;
+ s->frame_end = start + size;
+ s->frame_reg = reg;
+}
+
+void tcg_func_start(TCGContext *s)
+{
+ int i;
+ tcg_pool_reset(s);
+ s->nb_temps = s->nb_globals;
+ for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
+ s->first_free_temp[i] = -1;
+ s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
+ s->nb_labels = 0;
+ s->current_frame_offset = s->frame_start;
+
+ gen_opc_ptr = gen_opc_buf;
+ gen_opparam_ptr = gen_opparam_buf;
+}
+
+static inline void tcg_temp_alloc(TCGContext *s, int n)
+{
+ if (n > TCG_MAX_TEMPS)
+ tcg_abort();
+}
+
+static inline int tcg_global_reg_new_internal(TCGType type, int reg,
+ const char *name)
+{
+ TCGContext *s = &tcg_ctx;
+ TCGTemp *ts;
+ int idx;
+
+#if TCG_TARGET_REG_BITS == 32
+ if (type != TCG_TYPE_I32)
+ tcg_abort();
+#endif
+ if (tcg_regset_test_reg(s->reserved_regs, reg))
+ tcg_abort();
+ idx = s->nb_globals;
+ tcg_temp_alloc(s, s->nb_globals + 1);
+ ts = &s->temps[s->nb_globals];
+ ts->base_type = type;
+ ts->type = type;
+ ts->fixed_reg = 1;
+ ts->reg = reg;
+ ts->name = name;
+ s->nb_globals++;
+ tcg_regset_set_reg(s->reserved_regs, reg);
+ return idx;
+}
+
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
+{
+ int idx;
+
+ idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
+ return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
+{
+ int idx;
+
+ idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
+ return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_global_mem_new_internal(TCGType type, int reg,
+ tcg_target_long offset,
+ const char *name)
+{
+ TCGContext *s = &tcg_ctx;
+ TCGTemp *ts;
+ int idx;
+
+ idx = s->nb_globals;
+#if TCG_TARGET_REG_BITS == 32
+ if (type == TCG_TYPE_I64) {
+ char buf[64];
+ tcg_temp_alloc(s, s->nb_globals + 2);
+ ts = &s->temps[s->nb_globals];
+ ts->base_type = type;
+ ts->type = TCG_TYPE_I32;
+ ts->fixed_reg = 0;
+ ts->mem_allocated = 1;
+ ts->mem_reg = reg;
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ ts->mem_offset = offset + 4;
+#else
+ ts->mem_offset = offset;
+#endif
+ pstrcpy(buf, sizeof(buf), name);
+ pstrcat(buf, sizeof(buf), "_0");
+ ts->name = strdup(buf);
+ ts++;
+
+ ts->base_type = type;
+ ts->type = TCG_TYPE_I32;
+ ts->fixed_reg = 0;
+ ts->mem_allocated = 1;
+ ts->mem_reg = reg;
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ ts->mem_offset = offset;
+#else
+ ts->mem_offset = offset + 4;
+#endif
+ pstrcpy(buf, sizeof(buf), name);
+ pstrcat(buf, sizeof(buf), "_1");
+ ts->name = strdup(buf);
+
+ s->nb_globals += 2;
+ } else
+#endif
+ {
+ tcg_temp_alloc(s, s->nb_globals + 1);
+ ts = &s->temps[s->nb_globals];
+ ts->base_type = type;
+ ts->type = type;
+ ts->fixed_reg = 0;
+ ts->mem_allocated = 1;
+ ts->mem_reg = reg;
+ ts->mem_offset = offset;
+ ts->name = name;
+ s->nb_globals++;
+ }
+ return idx;
+}
+
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+ const char *name)
+{
+ int idx;
+
+ idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
+ return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+ const char *name)
+{
+ int idx;
+
+ idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
+ return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_temp_new_internal(TCGType type, int temp_local)
+{
+ TCGContext *s = &tcg_ctx;
+ TCGTemp *ts;
+ int idx, k;
+
+ k = type;
+ if (temp_local)
+ k += TCG_TYPE_COUNT;
+ idx = s->first_free_temp[k];
+ if (idx != -1) {
+ /* There is already an available temp with the
+ right type */
+ ts = &s->temps[idx];
+ s->first_free_temp[k] = ts->next_free_temp;
+ ts->temp_allocated = 1;
+ assert(ts->temp_local == temp_local);
+ } else {
+ idx = s->nb_temps;
+#if TCG_TARGET_REG_BITS == 32
+ if (type == TCG_TYPE_I64) {
+ tcg_temp_alloc(s, s->nb_temps + 2);
+ ts = &s->temps[s->nb_temps];
+ ts->base_type = type;
+ ts->type = TCG_TYPE_I32;
+ ts->temp_allocated = 1;
+ ts->temp_local = temp_local;
+ ts->name = NULL;
+ ts++;
+ ts->base_type = TCG_TYPE_I32;
+ ts->type = TCG_TYPE_I32;
+ ts->temp_allocated = 1;
+ ts->temp_local = temp_local;
+ ts->name = NULL;
+ s->nb_temps += 2;
+ } else
+#endif
+ {
+ tcg_temp_alloc(s, s->nb_temps + 1);
+ ts = &s->temps[s->nb_temps];
+ ts->base_type = type;
+ ts->type = type;
+ ts->temp_allocated = 1;
+ ts->temp_local = temp_local;
+ ts->name = NULL;
+ s->nb_temps++;
+ }
+ }
+ return idx;
+}
+
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
+{
+ int idx;
+
+ idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
+ return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
+{
+ int idx;
+
+ idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
+ return MAKE_TCGV_I64(idx);
+}
+
+static inline void tcg_temp_free_internal(int idx)
+{
+ TCGContext *s = &tcg_ctx;
+ TCGTemp *ts;
+ int k;
+
+ assert(idx >= s->nb_globals && idx < s->nb_temps);
+ ts = &s->temps[idx];
+ assert(ts->temp_allocated != 0);
+ ts->temp_allocated = 0;
+ k = ts->base_type;
+ if (ts->temp_local)
+ k += TCG_TYPE_COUNT;
+ ts->next_free_temp = s->first_free_temp[k];
+ s->first_free_temp[k] = idx;
+}
+
+void tcg_temp_free_i32(TCGv_i32 arg)
+{
+ tcg_temp_free_internal(GET_TCGV_I32(arg));
+}
+
+void tcg_temp_free_i64(TCGv_i64 arg)
+{
+ tcg_temp_free_internal(GET_TCGV_I64(arg));
+}
+
+TCGv_i32 tcg_const_i32(int32_t val)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_new_i32();
+ tcg_gen_movi_i32(t0, val);
+ return t0;
+}
+
+TCGv_i64 tcg_const_i64(int64_t val)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_new_i64();
+ tcg_gen_movi_i64(t0, val);
+ return t0;
+}
+
+TCGv_i32 tcg_const_local_i32(int32_t val)
+{
+ TCGv_i32 t0;
+ t0 = tcg_temp_local_new_i32();
+ tcg_gen_movi_i32(t0, val);
+ return t0;
+}
+
+TCGv_i64 tcg_const_local_i64(int64_t val)
+{
+ TCGv_i64 t0;
+ t0 = tcg_temp_local_new_i64();
+ tcg_gen_movi_i64(t0, val);
+ return t0;
+}
+
+void tcg_register_helper(void *func, const char *name)
+{
+ TCGContext *s = &tcg_ctx;
+ int n;
+ if ((s->nb_helpers + 1) > s->allocated_helpers) {
+ n = s->allocated_helpers;
+ if (n == 0) {
+ n = 4;
+ } else {
+ n *= 2;
+ }
+ s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
+ s->allocated_helpers = n;
+ }
+ s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
+ s->helpers[s->nb_helpers].name = name;
+ s->nb_helpers++;
+}
+
+/* Note: we convert the 64 bit args to 32 bit and do some alignment
+ and endian swap. Maybe it would be better to do the alignment
+ and endian swap in tcg_reg_alloc_call(). */
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+ int sizemask, TCGArg ret, int nargs, TCGArg *args)
+{
+#ifdef TCG_TARGET_I386
+ int call_type;
+#endif
+ int i;
+ int real_args;
+ int nb_rets;
+ TCGArg *nparam;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+ for (i = 0; i < nargs; ++i) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ int is_signed = sizemask & (2 << (i+1)*2);
+ if (!is_64bit) {
+ TCGv_i64 temp = tcg_temp_new_i64();
+ TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
+ if (is_signed) {
+ tcg_gen_ext32s_i64(temp, orig);
+ } else {
+ tcg_gen_ext32u_i64(temp, orig);
+ }
+ args[i] = GET_TCGV_I64(temp);
+ }
+ }
+#endif /* TCG_TARGET_EXTEND_ARGS */
+
+ *gen_opc_ptr++ = INDEX_op_call;
+ nparam = gen_opparam_ptr++;
+#ifdef TCG_TARGET_I386
+ call_type = (flags & TCG_CALL_TYPE_MASK);
+#endif
+ if (ret != TCG_CALL_DUMMY_ARG) {
+#if TCG_TARGET_REG_BITS < 64
+ if (sizemask & 1) {
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+ *gen_opparam_ptr++ = ret + 1;
+ *gen_opparam_ptr++ = ret;
+#else
+ *gen_opparam_ptr++ = ret;
+ *gen_opparam_ptr++ = ret + 1;
+#endif
+ nb_rets = 2;
+ } else
+#endif
+ {
+ *gen_opparam_ptr++ = ret;
+ nb_rets = 1;
+ }
+ } else {
+ nb_rets = 0;
+ }
+ real_args = 0;
+ for (i = 0; i < nargs; i++) {
+#if TCG_TARGET_REG_BITS < 64
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ if (is_64bit) {
+#ifdef TCG_TARGET_I386
+ /* REGPARM case: if the third parameter is 64 bit, it is
+ allocated on the stack */
+ if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
+ call_type = TCG_CALL_TYPE_REGPARM_2;
+ flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
+ }
+#endif
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+ /* some targets want aligned 64 bit args */
+ if (real_args & 1) {
+ *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
+ real_args++;
+ }
+#endif
+ /* If stack grows up, then we will be placing successive
+ arguments at lower addresses, which means we need to
+ reverse the order compared to how we would normally
+ treat either big or little-endian. For those arguments
+ that will wind up in registers, this still works for
+ HPPA (the only current STACK_GROWSUP target) since the
+ argument registers are *also* allocated in decreasing
+ order. If another such target is added, this logic may
+ have to get more complicated to differentiate between
+ stack arguments and register arguments. */
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
+ *gen_opparam_ptr++ = args[i] + 1;
+ *gen_opparam_ptr++ = args[i];
+#else
+ *gen_opparam_ptr++ = args[i];
+ *gen_opparam_ptr++ = args[i] + 1;
+#endif
+ real_args += 2;
+ continue;
+ }
+#endif /* TCG_TARGET_REG_BITS < 64 */
+
+ *gen_opparam_ptr++ = args[i];
+ real_args++;
+ }
+ *gen_opparam_ptr++ = GET_TCGV_PTR(func);
+
+ *gen_opparam_ptr++ = flags;
+
+ *nparam = (nb_rets << 16) | (real_args + 1);
+
+ /* total parameters, needed to go backward in the instruction stream */
+ *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
+
+#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
+ for (i = 0; i < nargs; ++i) {
+ int is_64bit = sizemask & (1 << (i+1)*2);
+ if (!is_64bit) {
+ TCGv_i64 temp = MAKE_TCGV_I64(args[i]);
+ tcg_temp_free_i64(temp);
+ }
+ }
+#endif /* TCG_TARGET_EXTEND_ARGS */
+}
+
+#if TCG_TARGET_REG_BITS == 32
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
+ int c, int right, int arith)
+{
+ if (c == 0) {
+ tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
+ tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
+ } else if (c >= 32) {
+ c -= 32;
+ if (right) {
+ if (arith) {
+ tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
+ tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
+ } else {
+ tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
+ tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
+ }
+ } else {
+ tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
+ tcg_gen_movi_i32(TCGV_LOW(ret), 0);
+ }
+ } else {
+ TCGv_i32 t0, t1;
+
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ if (right) {
+ tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
+ if (arith)
+ tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
+ else
+ tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
+ tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
+ tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
+ tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
+ } else {
+ tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
+ /* Note: ret can be the same as arg1, so we use t1 */
+ tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
+ tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
+ tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
+ tcg_gen_mov_i32(TCGV_LOW(ret), t1);
+ }
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ }
+}
+#endif
+
+
+static void tcg_reg_alloc_start(TCGContext *s)
+{
+ int i;
+ TCGTemp *ts;
+ for(i = 0; i < s->nb_globals; i++) {
+ ts = &s->temps[i];
+ if (ts->fixed_reg) {
+ ts->val_type = TEMP_VAL_REG;
+ } else {
+ ts->val_type = TEMP_VAL_MEM;
+ }
+ }
+ for(i = s->nb_globals; i < s->nb_temps; i++) {
+ ts = &s->temps[i];
+ ts->val_type = TEMP_VAL_DEAD;
+ ts->mem_allocated = 0;
+ ts->fixed_reg = 0;
+ }
+ for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+ s->reg_to_temp[i] = -1;
+ }
+}
+
+static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
+ int idx)
+{
+ TCGTemp *ts;
+
+ ts = &s->temps[idx];
+ if (idx < s->nb_globals) {
+ pstrcpy(buf, buf_size, ts->name);
+ } else {
+ if (ts->temp_local)
+ snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
+ else
+ snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
+ }
+ return buf;
+}
+
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
+{
+ return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
+}
+
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
+{
+ return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
+}
+
+static int helper_cmp(const void *p1, const void *p2)
+{
+ const TCGHelperInfo *th1 = p1;
+ const TCGHelperInfo *th2 = p2;
+ if (th1->func < th2->func)
+ return -1;
+ else if (th1->func == th2->func)
+ return 0;
+ else
+ return 1;
+}
+
+/* find helper definition (Note: A hash table would be better) */
+static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
+{
+ int m, m_min, m_max;
+ TCGHelperInfo *th;
+ tcg_target_ulong v;
+
+ if (unlikely(!s->helpers_sorted)) {
+ qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
+ helper_cmp);
+ s->helpers_sorted = 1;
+ }
+
+ /* binary search */
+ m_min = 0;
+ m_max = s->nb_helpers - 1;
+ while (m_min <= m_max) {
+ m = (m_min + m_max) >> 1;
+ th = &s->helpers[m];
+ v = th->func;
+ if (v == val)
+ return th;
+ else if (val < v) {
+ m_max = m - 1;
+ } else {
+ m_min = m + 1;
+ }
+ }
+ return NULL;
+}
+
+static const char * const cond_name[] =
+{
+ [TCG_COND_EQ] = "eq",
+ [TCG_COND_NE] = "ne",
+ [TCG_COND_LT] = "lt",
+ [TCG_COND_GE] = "ge",
+ [TCG_COND_LE] = "le",
+ [TCG_COND_GT] = "gt",
+ [TCG_COND_LTU] = "ltu",
+ [TCG_COND_GEU] = "geu",
+ [TCG_COND_LEU] = "leu",
+ [TCG_COND_GTU] = "gtu"
+};
+
+void tcg_dump_ops(TCGContext *s, FILE *outfile)
+{
+ const uint16_t *opc_ptr;
+ const TCGArg *args;
+ TCGArg arg;
+ TCGOpcode c;
+ int i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
+ const TCGOpDef *def;
+ char buf[128];
+
+ first_insn = 1;
+ opc_ptr = gen_opc_buf;
+ args = gen_opparam_buf;
+ while (opc_ptr < gen_opc_ptr) {
+ c = *opc_ptr++;
+ def = &tcg_op_defs[c];
+ if (c == INDEX_op_debug_insn_start) {
+ uint64_t pc;
+#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
+ pc = ((uint64_t)args[1] << 32) | args[0];
+#else
+ pc = args[0];
+#endif
+ if (!first_insn)
+ fprintf(outfile, "\n");
+ fprintf(outfile, " ---- 0x%" PRIx64, pc);
+ first_insn = 0;
+ nb_oargs = def->nb_oargs;
+ nb_iargs = def->nb_iargs;
+ nb_cargs = def->nb_cargs;
+ } else if (c == INDEX_op_call) {
+ TCGArg arg;
+
+ /* variable number of arguments */
+ arg = *args++;
+ nb_oargs = arg >> 16;
+ nb_iargs = arg & 0xffff;
+ nb_cargs = def->nb_cargs;
+
+ fprintf(outfile, " %s ", def->name);
+
+ /* function name */
+ fprintf(outfile, "%s",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
+ /* flags */
+ fprintf(outfile, ",$0x%" TCG_PRIlx,
+ args[nb_oargs + nb_iargs]);
+ /* nb out args */
+ fprintf(outfile, ",$%d", nb_oargs);
+ for(i = 0; i < nb_oargs; i++) {
+ fprintf(outfile, ",");
+ fprintf(outfile, "%s",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
+ }
+ for(i = 0; i < (nb_iargs - 1); i++) {
+ fprintf(outfile, ",");
+ if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
+ fprintf(outfile, "<dummy>");
+ } else {
+ fprintf(outfile, "%s",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
+ }
+ }
+ } else if (c == INDEX_op_movi_i32
+#if TCG_TARGET_REG_BITS == 64
+ || c == INDEX_op_movi_i64
+#endif
+ ) {
+ tcg_target_ulong val;
+ TCGHelperInfo *th;
+
+ nb_oargs = def->nb_oargs;
+ nb_iargs = def->nb_iargs;
+ nb_cargs = def->nb_cargs;
+ fprintf(outfile, " %s %s,$", def->name,
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
+ val = args[1];
+ th = tcg_find_helper(s, val);
+ if (th) {
+ fprintf(outfile, "%s", th->name);
+ } else {
+ if (c == INDEX_op_movi_i32)
+ fprintf(outfile, "0x%x", (uint32_t)val);
+ else
+ fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
+ }
+ } else {
+ fprintf(outfile, " %s ", def->name);
+ if (c == INDEX_op_nopn) {
+ /* variable number of arguments */
+ nb_cargs = *args;
+ nb_oargs = 0;
+ nb_iargs = 0;
+ } else {
+ nb_oargs = def->nb_oargs;
+ nb_iargs = def->nb_iargs;
+ nb_cargs = def->nb_cargs;
+ }
+
+ k = 0;
+ for(i = 0; i < nb_oargs; i++) {
+ if (k != 0)
+ fprintf(outfile, ",");
+ fprintf(outfile, "%s",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+ }
+ for(i = 0; i < nb_iargs; i++) {
+ if (k != 0)
+ fprintf(outfile, ",");
+ fprintf(outfile, "%s",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+ }
+ switch (c) {
+ case INDEX_op_brcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+ case INDEX_op_brcond_i64:
+#endif
+ case INDEX_op_setcond_i32:
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_setcond2_i32:
+#elif TCG_TARGET_REG_BITS == 64
+ case INDEX_op_setcond_i64:
+#endif
+ if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
+ fprintf(outfile, ",%s", cond_name[args[k++]]);
+ else
+ fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
+ i = 1;
+ break;
+ default:
+ i = 0;
+ break;
+ }
+ for(; i < nb_cargs; i++) {
+ if (k != 0)
+ fprintf(outfile, ",");
+ arg = args[k++];
+ fprintf(outfile, "$0x%" TCG_PRIlx, arg);
+ }
+ }
+ fprintf(outfile, "\n");
+ args += nb_iargs + nb_oargs + nb_cargs;
+ }
+}
+
+/* we give more priority to constraints with less registers */
+static int get_constraint_priority(const TCGOpDef *def, int k)
+{
+ const TCGArgConstraint *arg_ct;
+
+ int i, n;
+ arg_ct = &def->args_ct[k];
+ if (arg_ct->ct & TCG_CT_ALIAS) {
+ /* an alias is equivalent to a single register */
+ n = 1;
+ } else {
+ if (!(arg_ct->ct & TCG_CT_REG))
+ return 0;
+ n = 0;
+ for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+ if (tcg_regset_test_reg(arg_ct->u.regs, i))
+ n++;
+ }
+ }
+ return TCG_TARGET_NB_REGS - n + 1;
+}
+
+/* sort from highest priority to lowest */
+static void sort_constraints(TCGOpDef *def, int start, int n)
+{
+ int i, j, p1, p2, tmp;
+
+ for(i = 0; i < n; i++)
+ def->sorted_args[start + i] = start + i;
+ if (n <= 1)
+ return;
+ for(i = 0; i < n - 1; i++) {
+ for(j = i + 1; j < n; j++) {
+ p1 = get_constraint_priority(def, def->sorted_args[start + i]);
+ p2 = get_constraint_priority(def, def->sorted_args[start + j]);
+ if (p1 < p2) {
+ tmp = def->sorted_args[start + i];
+ def->sorted_args[start + i] = def->sorted_args[start + j];
+ def->sorted_args[start + j] = tmp;
+ }
+ }
+ }
+}
+
+void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
+{
+ TCGOpcode op;
+ TCGOpDef *def;
+ const char *ct_str;
+ int i, nb_args;
+
+ for(;;) {
+ if (tdefs->op == (TCGOpcode)-1)
+ break;
+ op = tdefs->op;
+ assert((unsigned)op < NB_OPS);
+ def = &tcg_op_defs[op];
+#if defined(CONFIG_DEBUG_TCG)
+ /* Duplicate entry in op definitions? */
+ assert(!def->used);
+ def->used = 1;
+#endif
+ nb_args = def->nb_iargs + def->nb_oargs;
+ for(i = 0; i < nb_args; i++) {
+ ct_str = tdefs->args_ct_str[i];
+ /* Incomplete TCGTargetOpDef entry? */
+ assert(ct_str != NULL);
+ tcg_regset_clear(def->args_ct[i].u.regs);
+ def->args_ct[i].ct = 0;
+ if (ct_str[0] >= '0' && ct_str[0] <= '9') {
+ int oarg;
+ oarg = ct_str[0] - '0';
+ assert(oarg < def->nb_oargs);
+ assert(def->args_ct[oarg].ct & TCG_CT_REG);
+ /* TCG_CT_ALIAS is for the output arguments. The input
+ argument is tagged with TCG_CT_IALIAS. */
+ def->args_ct[i] = def->args_ct[oarg];
+ def->args_ct[oarg].ct = TCG_CT_ALIAS;
+ def->args_ct[oarg].alias_index = i;
+ def->args_ct[i].ct |= TCG_CT_IALIAS;
+ def->args_ct[i].alias_index = oarg;
+ } else {
+ for(;;) {
+ if (*ct_str == '\0')
+ break;
+ switch(*ct_str) {
+ case 'i':
+ def->args_ct[i].ct |= TCG_CT_CONST;
+ ct_str++;
+ break;
+ default:
+ if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
+ fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
+ ct_str, i, def->name);
+ exit(1);
+ }
+ }
+ }
+ }
+ }
+
+ /* TCGTargetOpDef entry with too much information? */
+ assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+
+ /* sort the constraints (XXX: this is just an heuristic) */
+ sort_constraints(def, 0, def->nb_oargs);
+ sort_constraints(def, def->nb_oargs, def->nb_iargs);
+
+#if 0
+ {
+ int i;
+
+ printf("%s: sorted=", def->name);
+ for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
+ printf(" %d", def->sorted_args[i]);
+ printf("\n");
+ }
+#endif
+ tdefs++;
+ }
+
+#if defined(CONFIG_DEBUG_TCG)
+ i = 0;
+ for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
+ if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+ /* Wrong entry in op definitions? */
+ if (tcg_op_defs[op].used) {
+ fprintf(stderr, "Invalid op definition for %s\n",
+ tcg_op_defs[op].name);
+ i = 1;
+ }
+ } else {
+ /* Missing entry in op definitions? */
+ if (!tcg_op_defs[op].used) {
+ fprintf(stderr, "Missing op definition for %s\n",
+ tcg_op_defs[op].name);
+ i = 1;
+ }
+ }
+ }
+ if (i == 1) {
+ tcg_abort();
+ }
+#endif
+}
+
+#ifdef USE_LIVENESS_ANALYSIS
+
+/* set a nop for an operation using 'nb_args' */
+static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr,
+ TCGArg *args, int nb_args)
+{
+ if (nb_args == 0) {
+ *opc_ptr = INDEX_op_nop;
+ } else {
+ *opc_ptr = INDEX_op_nopn;
+ args[0] = nb_args;
+ args[nb_args - 1] = nb_args;
+ }
+}
+
+/* liveness analysis: end of function: globals are live, temps are
+ dead. */
+/* XXX: at this stage, not used as there would be little gains because
+ most TBs end with a conditional jump. */
+static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
+{
+ memset(dead_temps, 0, s->nb_globals);
+ memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
+}
+
+/* liveness analysis: end of basic block: globals are live, temps are
+ dead, local temps are live. */
+static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
+{
+ int i;
+ TCGTemp *ts;
+
+ memset(dead_temps, 0, s->nb_globals);
+ ts = &s->temps[s->nb_globals];
+ for(i = s->nb_globals; i < s->nb_temps; i++) {
+ if (ts->temp_local)
+ dead_temps[i] = 0;
+ else
+ dead_temps[i] = 1;
+ ts++;
+ }
+}
+
+/* Liveness analysis : update the opc_dead_iargs array to tell if a
+ given input arguments is dead. Instructions updating dead
+ temporaries are removed. */
+static void tcg_liveness_analysis(TCGContext *s)
+{
+ int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
+ TCGOpcode op;
+ TCGArg *args;
+ const TCGOpDef *def;
+ uint8_t *dead_temps;
+ unsigned int dead_iargs;
+
+ gen_opc_ptr++; /* skip end */
+
+ nb_ops = gen_opc_ptr - gen_opc_buf;
+
+ s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
+
+ dead_temps = tcg_malloc(s->nb_temps);
+ memset(dead_temps, 1, s->nb_temps);
+
+ args = gen_opparam_ptr;
+ op_index = nb_ops - 1;
+ while (op_index >= 0) {
+ op = gen_opc_buf[op_index];
+ def = &tcg_op_defs[op];
+ switch(op) {
+ case INDEX_op_call:
+ {
+ int call_flags;
+
+ nb_args = args[-1];
+ args -= nb_args;
+ nb_iargs = args[0] & 0xffff;
+ nb_oargs = args[0] >> 16;
+ args++;
+ call_flags = args[nb_oargs + nb_iargs];
+
+ /* pure functions can be removed if their result is not
+ used */
+ if (call_flags & TCG_CALL_PURE) {
+ for(i = 0; i < nb_oargs; i++) {
+ arg = args[i];
+ if (!dead_temps[arg])
+ goto do_not_remove_call;
+ }
+ tcg_set_nop(s, gen_opc_buf + op_index,
+ args - 1, nb_args);
+ } else {
+ do_not_remove_call:
+
+ /* output args are dead */
+ for(i = 0; i < nb_oargs; i++) {
+ arg = args[i];
+ dead_temps[arg] = 1;
+ }
+
+ if (!(call_flags & TCG_CALL_CONST)) {
+ /* globals are live (they may be used by the call) */
+ memset(dead_temps, 0, s->nb_globals);
+ }
+
+ /* input args are live */
+ dead_iargs = 0;
+ for(i = 0; i < nb_iargs; i++) {
+ arg = args[i + nb_oargs];
+ if (arg != TCG_CALL_DUMMY_ARG) {
+ if (dead_temps[arg]) {
+ dead_iargs |= (1 << i);
+ }
+ dead_temps[arg] = 0;
+ }
+ }
+ s->op_dead_iargs[op_index] = dead_iargs;
+ }
+ args--;
+ }
+ break;
+ case INDEX_op_set_label:
+ args--;
+ /* mark end of basic block */
+ tcg_la_bb_end(s, dead_temps);
+ break;
+ case INDEX_op_debug_insn_start:
+ args -= def->nb_args;
+ break;
+ case INDEX_op_nopn:
+ nb_args = args[-1];
+ args -= nb_args;
+ break;
+ case INDEX_op_discard:
+ args--;
+ /* mark the temporary as dead */
+ dead_temps[args[0]] = 1;
+ break;
+ case INDEX_op_end:
+ break;
+ /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
+ default:
+ args -= def->nb_args;
+ nb_iargs = def->nb_iargs;
+ nb_oargs = def->nb_oargs;
+
+ /* Test if the operation can be removed because all
+ its outputs are dead. We assume that nb_oargs == 0
+ implies side effects */
+ if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
+ for(i = 0; i < nb_oargs; i++) {
+ arg = args[i];
+ if (!dead_temps[arg])
+ goto do_not_remove;
+ }
+ tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
+#ifdef CONFIG_PROFILER
+ s->del_op_count++;
+#endif
+ } else {
+ do_not_remove:
+
+ /* output args are dead */
+ for(i = 0; i < nb_oargs; i++) {
+ arg = args[i];
+ dead_temps[arg] = 1;
+ }
+
+ /* if end of basic block, update */
+ if (def->flags & TCG_OPF_BB_END) {
+ tcg_la_bb_end(s, dead_temps);
+ } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
+ /* globals are live */
+ memset(dead_temps, 0, s->nb_globals);
+ }
+
+ /* input args are live */
+ dead_iargs = 0;
+ for(i = 0; i < nb_iargs; i++) {
+ arg = args[i + nb_oargs];
+ if (dead_temps[arg]) {
+ dead_iargs |= (1 << i);
+ }
+ dead_temps[arg] = 0;
+ }
+ s->op_dead_iargs[op_index] = dead_iargs;
+ }
+ break;
+ }
+ op_index--;
+ }
+
+ if (args != gen_opparam_buf)
+ tcg_abort();
+}
+#else
+/* dummy liveness analysis */
+static void tcg_liveness_analysis(TCGContext *s)
+{
+ int nb_ops;
+ nb_ops = gen_opc_ptr - gen_opc_buf;
+
+ s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
+ memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
+}
+#endif
+
+#ifndef NDEBUG
+static void dump_regs(TCGContext *s)
+{
+ TCGTemp *ts;
+ int i;
+ char buf[64];
+
+ for(i = 0; i < s->nb_temps; i++) {
+ ts = &s->temps[i];
+ printf(" %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
+ switch(ts->val_type) {
+ case TEMP_VAL_REG:
+ printf("%s", tcg_target_reg_names[ts->reg]);
+ break;
+ case TEMP_VAL_MEM:
+ printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
+ break;
+ case TEMP_VAL_CONST:
+ printf("$0x%" TCG_PRIlx, ts->val);
+ break;
+ case TEMP_VAL_DEAD:
+ printf("D");
+ break;
+ default:
+ printf("???");
+ break;
+ }
+ printf("\n");
+ }
+
+ for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
+ if (s->reg_to_temp[i] >= 0) {
+ printf("%s: %s\n",
+ tcg_target_reg_names[i],
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
+ }
+ }
+}
+
+static void check_regs(TCGContext *s)
+{
+ int reg, k;
+ TCGTemp *ts;
+ char buf[64];
+
+ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+ k = s->reg_to_temp[reg];
+ if (k >= 0) {
+ ts = &s->temps[k];
+ if (ts->val_type != TEMP_VAL_REG ||
+ ts->reg != reg) {
+ printf("Inconsistency for register %s:\n",
+ tcg_target_reg_names[reg]);
+ goto fail;
+ }
+ }
+ }
+ for(k = 0; k < s->nb_temps; k++) {
+ ts = &s->temps[k];
+ if (ts->val_type == TEMP_VAL_REG &&
+ !ts->fixed_reg &&
+ s->reg_to_temp[ts->reg] != k) {
+ printf("Inconsistency for temp %s:\n",
+ tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
+ fail:
+ printf("reg state:\n");
+ dump_regs(s);
+ tcg_abort();
+ }
+ }
+}
+#endif
+
+static void temp_allocate_frame(TCGContext *s, int temp)
+{
+ TCGTemp *ts;
+ ts = &s->temps[temp];
+ s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
+ if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
+ tcg_abort();
+ ts->mem_offset = s->current_frame_offset;
+ ts->mem_reg = s->frame_reg;
+ ts->mem_allocated = 1;
+ s->current_frame_offset += sizeof(tcg_target_long);
+}
+
+/* free register 'reg' by spilling the corresponding temporary if necessary */
+static void tcg_reg_free(TCGContext *s, int reg)
+{
+ TCGTemp *ts;
+ int temp;
+
+ temp = s->reg_to_temp[reg];
+ if (temp != -1) {
+ ts = &s->temps[temp];
+ assert(ts->val_type == TEMP_VAL_REG);
+ if (!ts->mem_coherent) {
+ if (!ts->mem_allocated)
+ temp_allocate_frame(s, temp);
+ tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ }
+ ts->val_type = TEMP_VAL_MEM;
+ s->reg_to_temp[reg] = -1;
+ }
+}
+
+/* Allocate a register belonging to reg1 & ~reg2 */
+static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
+{
+ int i, reg;
+ TCGRegSet reg_ct;
+
+ tcg_regset_andnot(reg_ct, reg1, reg2);
+
+ /* first try free registers */
+ for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
+ reg = tcg_target_reg_alloc_order[i];
+ if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
+ return reg;
+ }
+
+ /* XXX: do better spill choice */
+ for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
+ reg = tcg_target_reg_alloc_order[i];
+ if (tcg_regset_test_reg(reg_ct, reg)) {
+ tcg_reg_free(s, reg);
+ return reg;
+ }
+ }
+
+ tcg_abort();
+}
+
+/* save a temporary to memory. 'allocated_regs' is used in case a
+ temporary registers needs to be allocated to store a constant. */
+static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
+{
+ TCGTemp *ts;
+ int reg;
+
+ ts = &s->temps[temp];
+ if (!ts->fixed_reg) {
+ switch(ts->val_type) {
+ case TEMP_VAL_REG:
+ tcg_reg_free(s, ts->reg);
+ break;
+ case TEMP_VAL_DEAD:
+ ts->val_type = TEMP_VAL_MEM;
+ break;
+ case TEMP_VAL_CONST:
+ reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
+ allocated_regs);
+ if (!ts->mem_allocated)
+ temp_allocate_frame(s, temp);
+ tcg_out_movi(s, ts->type, reg, ts->val);
+ tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ ts->val_type = TEMP_VAL_MEM;
+ break;
+ case TEMP_VAL_MEM:
+ break;
+ default:
+ tcg_abort();
+ }
+ }
+}
+
+/* save globals to their cannonical location and assume they can be
+ modified be the following code. 'allocated_regs' is used in case a
+ temporary registers needs to be allocated to store a constant. */
+static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
+{
+ int i;
+
+ for(i = 0; i < s->nb_globals; i++) {
+ temp_save(s, i, allocated_regs);
+ }
+}
+
+/* at the end of a basic block, we assume all temporaries are dead and
+ all globals are stored at their canonical location. */
+static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
+{
+ TCGTemp *ts;
+ int i;
+
+ for(i = s->nb_globals; i < s->nb_temps; i++) {
+ ts = &s->temps[i];
+ if (ts->temp_local) {
+ temp_save(s, i, allocated_regs);
+ } else {
+ if (ts->val_type == TEMP_VAL_REG) {
+ s->reg_to_temp[ts->reg] = -1;
+ }
+ ts->val_type = TEMP_VAL_DEAD;
+ }
+ }
+
+ save_globals(s, allocated_regs);
+}
+
+#define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
+
+static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
+{
+ TCGTemp *ots;
+ tcg_target_ulong val;
+
+ ots = &s->temps[args[0]];
+ val = args[1];
+
+ if (ots->fixed_reg) {
+ /* for fixed registers, we do not do any constant
+ propagation */
+ tcg_out_movi(s, ots->type, ots->reg, val);
+ } else {
+ /* The movi is not explicitly generated here */
+ if (ots->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ots->reg] = -1;
+ ots->val_type = TEMP_VAL_CONST;
+ ots->val = val;
+ }
+}
+
+static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
+ const TCGArg *args,
+ unsigned int dead_iargs)
+{
+ TCGTemp *ts, *ots;
+ int reg;
+ const TCGArgConstraint *arg_ct;
+
+ ots = &s->temps[args[0]];
+ ts = &s->temps[args[1]];
+ arg_ct = &def->args_ct[0];
+
+ /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
+ if (ts->val_type == TEMP_VAL_REG) {
+ if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
+ /* the mov can be suppressed */
+ if (ots->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ots->reg] = -1;
+ reg = ts->reg;
+ s->reg_to_temp[reg] = -1;
+ ts->val_type = TEMP_VAL_DEAD;
+ } else {
+ if (ots->val_type == TEMP_VAL_REG) {
+ reg = ots->reg;
+ } else {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
+ }
+ if (ts->reg != reg) {
+ tcg_out_mov(s, ots->type, reg, ts->reg);
+ }
+ }
+ } else if (ts->val_type == TEMP_VAL_MEM) {
+ if (ots->val_type == TEMP_VAL_REG) {
+ reg = ots->reg;
+ } else {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
+ }
+ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ } else if (ts->val_type == TEMP_VAL_CONST) {
+ if (ots->fixed_reg) {
+ reg = ots->reg;
+ tcg_out_movi(s, ots->type, reg, ts->val);
+ } else {
+ /* propagate constant */
+ if (ots->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ots->reg] = -1;
+ ots->val_type = TEMP_VAL_CONST;
+ ots->val = ts->val;
+ return;
+ }
+ } else {
+ tcg_abort();
+ }
+ s->reg_to_temp[reg] = args[0];
+ ots->reg = reg;
+ ots->val_type = TEMP_VAL_REG;
+ ots->mem_coherent = 0;
+}
+
+static void tcg_reg_alloc_op(TCGContext *s,
+ const TCGOpDef *def, TCGOpcode opc,
+ const TCGArg *args,
+ unsigned int dead_iargs)
+{
+ TCGRegSet allocated_regs;
+ int i, k, nb_iargs, nb_oargs, reg;
+ TCGArg arg;
+ const TCGArgConstraint *arg_ct;
+ TCGTemp *ts;
+ TCGArg new_args[TCG_MAX_OP_ARGS];
+ int const_args[TCG_MAX_OP_ARGS];
+
+ nb_oargs = def->nb_oargs;
+ nb_iargs = def->nb_iargs;
+
+ /* copy constants */
+ memcpy(new_args + nb_oargs + nb_iargs,
+ args + nb_oargs + nb_iargs,
+ sizeof(TCGArg) * def->nb_cargs);
+
+ /* satisfy input constraints */
+ tcg_regset_set(allocated_regs, s->reserved_regs);
+ for(k = 0; k < nb_iargs; k++) {
+ i = def->sorted_args[nb_oargs + k];
+ arg = args[i];
+ arg_ct = &def->args_ct[i];
+ ts = &s->temps[arg];
+ if (ts->val_type == TEMP_VAL_MEM) {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ ts->mem_coherent = 1;
+ s->reg_to_temp[reg] = arg;
+ } else if (ts->val_type == TEMP_VAL_CONST) {
+ if (tcg_target_const_match(ts->val, arg_ct)) {
+ /* constant is OK for instruction */
+ const_args[i] = 1;
+ new_args[i] = ts->val;
+ goto iarg_end;
+ } else {
+ /* need to move to a register */
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_movi(s, ts->type, reg, ts->val);
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ ts->mem_coherent = 0;
+ s->reg_to_temp[reg] = arg;
+ }
+ }
+ assert(ts->val_type == TEMP_VAL_REG);
+ if (arg_ct->ct & TCG_CT_IALIAS) {
+ if (ts->fixed_reg) {
+ /* if fixed register, we must allocate a new register
+ if the alias is not the same register */
+ if (arg != args[arg_ct->alias_index])
+ goto allocate_in_reg;
+ } else {
+ /* if the input is aliased to an output and if it is
+ not dead after the instruction, we must allocate
+ a new register and move it */
+ if (!IS_DEAD_IARG(i - nb_oargs))
+ goto allocate_in_reg;
+ }
+ }
+ reg = ts->reg;
+ if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+ /* nothing to do : the constraint is satisfied */
+ } else {
+ allocate_in_reg:
+ /* allocate a new register matching the constraint
+ and move the temporary register into it */
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
+ }
+ new_args[i] = reg;
+ const_args[i] = 0;
+ tcg_regset_set_reg(allocated_regs, reg);
+ iarg_end: ;
+ }
+
+ if (def->flags & TCG_OPF_BB_END) {
+ tcg_reg_alloc_bb_end(s, allocated_regs);
+ } else {
+ /* mark dead temporaries and free the associated registers */
+ for(i = 0; i < nb_iargs; i++) {
+ arg = args[nb_oargs + i];
+ if (IS_DEAD_IARG(i)) {
+ ts = &s->temps[arg];
+ if (!ts->fixed_reg) {
+ if (ts->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ts->reg] = -1;
+ ts->val_type = TEMP_VAL_DEAD;
+ }
+ }
+ }
+
+ if (def->flags & TCG_OPF_CALL_CLOBBER) {
+ /* XXX: permit generic clobber register list ? */
+ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+ if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
+ tcg_reg_free(s, reg);
+ }
+ }
+ /* XXX: for load/store we could do that only for the slow path
+ (i.e. when a memory callback is called) */
+
+ /* store globals and free associated registers (we assume the insn
+ can modify any global. */
+ save_globals(s, allocated_regs);
+ }
+
+ /* satisfy the output constraints */
+ tcg_regset_set(allocated_regs, s->reserved_regs);
+ for(k = 0; k < nb_oargs; k++) {
+ i = def->sorted_args[k];
+ arg = args[i];
+ arg_ct = &def->args_ct[i];
+ ts = &s->temps[arg];
+ if (arg_ct->ct & TCG_CT_ALIAS) {
+ reg = new_args[arg_ct->alias_index];
+ } else {
+ /* if fixed register, we try to use it */
+ reg = ts->reg;
+ if (ts->fixed_reg &&
+ tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+ goto oarg_end;
+ }
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ }
+ tcg_regset_set_reg(allocated_regs, reg);
+ /* if a fixed register is used, then a move will be done afterwards */
+ if (!ts->fixed_reg) {
+ if (ts->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ts->reg] = -1;
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ /* temp value is modified, so the value kept in memory is
+ potentially not the same */
+ ts->mem_coherent = 0;
+ s->reg_to_temp[reg] = arg;
+ }
+ oarg_end:
+ new_args[i] = reg;
+ }
+ }
+
+ /* emit instruction */
+ tcg_out_op(s, opc, new_args, const_args);
+
+ /* move the outputs in the correct register if needed */
+ for(i = 0; i < nb_oargs; i++) {
+ ts = &s->temps[args[i]];
+ reg = new_args[i];
+ if (ts->fixed_reg && ts->reg != reg) {
+ tcg_out_mov(s, ts->type, ts->reg, reg);
+ }
+ }
+}
+
+#ifdef TCG_TARGET_STACK_GROWSUP
+#define STACK_DIR(x) (-(x))
+#else
+#define STACK_DIR(x) (x)
+#endif
+
+static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
+ TCGOpcode opc, const TCGArg *args,
+ unsigned int dead_iargs)
+{
+ int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
+ TCGArg arg, func_arg;
+ TCGTemp *ts;
+ tcg_target_long stack_offset, call_stack_size, func_addr;
+ int const_func_arg, allocate_args;
+ TCGRegSet allocated_regs;
+ const TCGArgConstraint *arg_ct;
+
+ arg = *args++;
+
+ nb_oargs = arg >> 16;
+ nb_iargs = arg & 0xffff;
+ nb_params = nb_iargs - 1;
+
+ flags = args[nb_oargs + nb_iargs];
+
+ nb_regs = tcg_target_get_call_iarg_regs_count(flags);
+ if (nb_regs > nb_params)
+ nb_regs = nb_params;
+
+ /* assign stack slots first */
+ /* XXX: preallocate call stack */
+ call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
+ call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
+ ~(TCG_TARGET_STACK_ALIGN - 1);
+ allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
+ if (allocate_args) {
+ tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
+ }
+
+ stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
+ for(i = nb_regs; i < nb_params; i++) {
+ arg = args[nb_oargs + i];
+#ifdef TCG_TARGET_STACK_GROWSUP
+ stack_offset -= sizeof(tcg_target_long);
+#endif
+ if (arg != TCG_CALL_DUMMY_ARG) {
+ ts = &s->temps[arg];
+ if (ts->val_type == TEMP_VAL_REG) {
+ tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
+ } else if (ts->val_type == TEMP_VAL_MEM) {
+ reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
+ s->reserved_regs);
+ /* XXX: not correct if reading values from the stack */
+ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
+ } else if (ts->val_type == TEMP_VAL_CONST) {
+ reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type],
+ s->reserved_regs);
+ /* XXX: sign extend may be needed on some targets */
+ tcg_out_movi(s, ts->type, reg, ts->val);
+ tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
+ } else {
+ tcg_abort();
+ }
+ }
+#ifndef TCG_TARGET_STACK_GROWSUP
+ stack_offset += sizeof(tcg_target_long);
+#endif
+ }
+
+ /* assign input registers */
+ tcg_regset_set(allocated_regs, s->reserved_regs);
+ for(i = 0; i < nb_regs; i++) {
+ arg = args[nb_oargs + i];
+ if (arg != TCG_CALL_DUMMY_ARG) {
+ ts = &s->temps[arg];
+ reg = tcg_target_call_iarg_regs[i];
+ tcg_reg_free(s, reg);
+ if (ts->val_type == TEMP_VAL_REG) {
+ if (ts->reg != reg) {
+ tcg_out_mov(s, ts->type, reg, ts->reg);
+ }
+ } else if (ts->val_type == TEMP_VAL_MEM) {
+ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ } else if (ts->val_type == TEMP_VAL_CONST) {
+ /* XXX: sign extend ? */
+ tcg_out_movi(s, ts->type, reg, ts->val);
+ } else {
+ tcg_abort();
+ }
+ tcg_regset_set_reg(allocated_regs, reg);
+ }
+ }
+
+ /* assign function address */
+ func_arg = args[nb_oargs + nb_iargs - 1];
+ arg_ct = &def->args_ct[0];
+ ts = &s->temps[func_arg];
+ func_addr = ts->val;
+ const_func_arg = 0;
+ if (ts->val_type == TEMP_VAL_MEM) {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
+ func_arg = reg;
+ tcg_regset_set_reg(allocated_regs, reg);
+ } else if (ts->val_type == TEMP_VAL_REG) {
+ reg = ts->reg;
+ if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
+ }
+ func_arg = reg;
+ tcg_regset_set_reg(allocated_regs, reg);
+ } else if (ts->val_type == TEMP_VAL_CONST) {
+ if (tcg_target_const_match(func_addr, arg_ct)) {
+ const_func_arg = 1;
+ func_arg = func_addr;
+ } else {
+ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
+ tcg_out_movi(s, ts->type, reg, func_addr);
+ func_arg = reg;
+ tcg_regset_set_reg(allocated_regs, reg);
+ }
+ } else {
+ tcg_abort();
+ }
+
+
+ /* mark dead temporaries and free the associated registers */
+ for(i = 0; i < nb_iargs; i++) {
+ arg = args[nb_oargs + i];
+ if (IS_DEAD_IARG(i)) {
+ ts = &s->temps[arg];
+ if (!ts->fixed_reg) {
+ if (ts->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ts->reg] = -1;
+ ts->val_type = TEMP_VAL_DEAD;
+ }
+ }
+ }
+
+ /* clobber call registers */
+ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
+ if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
+ tcg_reg_free(s, reg);
+ }
+ }
+
+ /* store globals and free associated registers (we assume the call
+ can modify any global. */
+ if (!(flags & TCG_CALL_CONST)) {
+ save_globals(s, allocated_regs);
+ }
+
+ tcg_out_op(s, opc, &func_arg, &const_func_arg);
+
+ if (allocate_args) {
+ tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
+ }
+
+ /* assign output registers and emit moves if needed */
+ for(i = 0; i < nb_oargs; i++) {
+ arg = args[i];
+ ts = &s->temps[arg];
+ reg = tcg_target_call_oarg_regs[i];
+ assert(s->reg_to_temp[reg] == -1);
+ if (ts->fixed_reg) {
+ if (ts->reg != reg) {
+ tcg_out_mov(s, ts->type, ts->reg, reg);
+ }
+ } else {
+ if (ts->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ts->reg] = -1;
+ ts->val_type = TEMP_VAL_REG;
+ ts->reg = reg;
+ ts->mem_coherent = 0;
+ s->reg_to_temp[reg] = arg;
+ }
+ }
+
+ return nb_iargs + nb_oargs + def->nb_cargs + 1;
+}
+
+#ifdef CONFIG_PROFILER
+
+static int64_t tcg_table_op_count[NB_OPS];
+
+static void dump_op_count(void)
+{
+ int i;
+ FILE *f;
+ f = fopen("/tmp/op.log", "w");
+ for(i = INDEX_op_end; i < NB_OPS; i++) {
+ fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
+ }
+ fclose(f);
+}
+#endif
+
+
+static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
+ long search_pc)
+{
+ TCGOpcode opc;
+ int op_index;
+ const TCGOpDef *def;
+ unsigned int dead_iargs;
+ const TCGArg *args;
+
+#ifdef DEBUG_DISAS
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+ qemu_log("OP:\n");
+ tcg_dump_ops(s, logfile);
+ qemu_log("\n");
+ }
+#endif
+
+#ifdef CONFIG_PROFILER
+ s->la_time -= profile_getclock();
+#endif
+ tcg_liveness_analysis(s);
+#ifdef CONFIG_PROFILER
+ s->la_time += profile_getclock();
+#endif
+
+#ifdef DEBUG_DISAS
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
+ qemu_log("OP after liveness analysis:\n");
+ tcg_dump_ops(s, logfile);
+ qemu_log("\n");
+ }
+#endif
+
+ tcg_reg_alloc_start(s);
+
+ s->code_buf = gen_code_buf;
+ s->code_ptr = gen_code_buf;
+
+ args = gen_opparam_buf;
+ op_index = 0;
+
+ for(;;) {
+ opc = gen_opc_buf[op_index];
+#ifdef CONFIG_PROFILER
+ tcg_table_op_count[opc]++;
+#endif
+ def = &tcg_op_defs[opc];
+#if 0
+ printf("%s: %d %d %d\n", def->name,
+ def->nb_oargs, def->nb_iargs, def->nb_cargs);
+ // dump_regs(s);
+#endif
+ switch(opc) {
+ case INDEX_op_mov_i32:
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_mov_i64:
+#endif
+ dead_iargs = s->op_dead_iargs[op_index];
+ tcg_reg_alloc_mov(s, def, args, dead_iargs);
+ break;
+ case INDEX_op_movi_i32:
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_movi_i64:
+#endif
+ tcg_reg_alloc_movi(s, args);
+ break;
+ case INDEX_op_debug_insn_start:
+ /* debug instruction */
+ break;
+ case INDEX_op_nop:
+ case INDEX_op_nop1:
+ case INDEX_op_nop2:
+ case INDEX_op_nop3:
+ break;
+ case INDEX_op_nopn:
+ args += args[0];
+ goto next;
+ case INDEX_op_discard:
+ {
+ TCGTemp *ts;
+ ts = &s->temps[args[0]];
+ /* mark the temporary as dead */
+ if (!ts->fixed_reg) {
+ if (ts->val_type == TEMP_VAL_REG)
+ s->reg_to_temp[ts->reg] = -1;
+ ts->val_type = TEMP_VAL_DEAD;
+ }
+ }
+ break;
+ case INDEX_op_set_label:
+ tcg_reg_alloc_bb_end(s, s->reserved_regs);
+ tcg_out_label(s, args[0], (long)s->code_ptr);
+ break;
+ case INDEX_op_call:
+ dead_iargs = s->op_dead_iargs[op_index];
+ args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
+ goto next;
+ case INDEX_op_end:
+ goto the_end;
+ default:
+ /* Note: in order to speed up the code, it would be much
+ faster to have specialized register allocator functions for
+ some common argument patterns */
+ dead_iargs = s->op_dead_iargs[op_index];
+ tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
+ break;
+ }
+ args += def->nb_args;
+ next:
+ if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
+ return op_index;
+ }
+ op_index++;
+#ifndef NDEBUG
+ check_regs(s);
+#endif
+ }
+ the_end:
+ return -1;
+}
+
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
+{
+#ifdef CONFIG_PROFILER
+ {
+ int n;
+ n = (gen_opc_ptr - gen_opc_buf);
+ s->op_count += n;
+ if (n > s->op_count_max)
+ s->op_count_max = n;
+
+ s->temp_count += s->nb_temps;
+ if (s->nb_temps > s->temp_count_max)
+ s->temp_count_max = s->nb_temps;
+ }
+#endif
+
+ tcg_gen_code_common(s, gen_code_buf, -1);
+
+ /* flush instruction cache */
+ flush_icache_range((unsigned long)gen_code_buf,
+ (unsigned long)s->code_ptr);
+ return s->code_ptr - gen_code_buf;
+}
+
+/* Return the index of the micro operation such as the pc after is <
+ offset bytes from the start of the TB. The contents of gen_code_buf must
+ not be changed, though writing the same values is ok.
+ Return -1 if not found. */
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
+{
+ return tcg_gen_code_common(s, gen_code_buf, offset);
+}
+
+#ifdef CONFIG_PROFILER
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
+{
+ TCGContext *s = &tcg_ctx;
+ int64_t tot;
+
+ tot = s->interm_time + s->code_time;
+ cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
+ tot, tot / 2.4e9);
+ cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
+ s->tb_count,
+ s->tb_count1 - s->tb_count,
+ s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
+ cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
+ s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
+ cpu_fprintf(f, "deleted ops/TB %0.2f\n",
+ s->tb_count ?
+ (double)s->del_op_count / s->tb_count : 0);
+ cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n",
+ s->tb_count ?
+ (double)s->temp_count / s->tb_count : 0,
+ s->temp_count_max);
+
+ cpu_fprintf(f, "cycles/op %0.1f\n",
+ s->op_count ? (double)tot / s->op_count : 0);
+ cpu_fprintf(f, "cycles/in byte %0.1f\n",
+ s->code_in_len ? (double)tot / s->code_in_len : 0);
+ cpu_fprintf(f, "cycles/out byte %0.1f\n",
+ s->code_out_len ? (double)tot / s->code_out_len : 0);
+ if (tot == 0)
+ tot = 1;
+ cpu_fprintf(f, " gen_interm time %0.1f%%\n",
+ (double)s->interm_time / tot * 100.0);
+ cpu_fprintf(f, " gen_code time %0.1f%%\n",
+ (double)s->code_time / tot * 100.0);
+ cpu_fprintf(f, "liveness/code time %0.1f%%\n",
+ (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
+ cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
+ s->restore_count);
+ cpu_fprintf(f, " avg cycles %0.1f\n",
+ s->restore_count ? (double)s->restore_time / s->restore_count : 0);
+
+ dump_op_count();
+}
+#else
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
+{
+ cpu_fprintf(f, "[TCG profiler not compiled]\n");
+}
+#endif
diff --git a/tcg/tcg.h b/tcg/tcg.h
new file mode 100644
index 0000000..e1afde2
--- /dev/null
+++ b/tcg/tcg.h
@@ -0,0 +1,489 @@
+/*
+ * 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 "qemu-common.h"
+#include "tcg-target.h"
+#include "tcg-runtime.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
+
+typedef enum TCGOpcode {
+#define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
+#include "tcg-opc.h"
+#undef DEF
+ NB_OPS,
+} TCGOpcode;
+
+#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) |= 1L << (r)
+#define tcg_regset_reset_reg(d, r) (d) &= ~(1L << (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] __attribute__ ((aligned));
+} TCGPool;
+
+#define TCG_POOL_CHUNK_SIZE 32768
+
+#define TCG_MAX_LABELS 512
+
+#define TCG_MAX_TEMPS 512
+
+/* when the size of the arguments of a called function is smaller than
+ this value, they are statically allocated in the TB stack frame */
+#define TCG_STATIC_CALL_ARGS_SIZE 128
+
+typedef enum TCGType {
+ TCG_TYPE_I32,
+ TCG_TYPE_I64,
+ TCG_TYPE_COUNT, /* number of different types */
+
+ /* An alias for the size of the host register. */
+#if TCG_TARGET_REG_BITS == 32
+ TCG_TYPE_REG = TCG_TYPE_I32,
+#else
+ TCG_TYPE_REG = TCG_TYPE_I64,
+#endif
+
+ /* An alias for the size of the native pointer. We don't currently
+ support any hosts with 64-bit registers and 32-bit pointers. */
+ TCG_TYPE_PTR = TCG_TYPE_REG,
+
+ /* An alias for the size of the target "long", aka register. */
+#if TARGET_LONG_BITS == 64
+ TCG_TYPE_TL = TCG_TYPE_I64,
+#else
+ TCG_TYPE_TL = TCG_TYPE_I32,
+#endif
+} TCGType;
+
+typedef tcg_target_ulong TCGArg;
+
+/* Define a type and accessor macros for varables. Using a struct is
+ nice because it gives some level of type safely. Ideally the compiler
+ be able to see through all this. However in practice this is not true,
+ expecially on targets with braindamaged ABIs (e.g. i386).
+ We use plain int by default to avoid this runtime overhead.
+ Users of tcg_gen_* don't need to know about any of this, and should
+ treat TCGv as an opaque type.
+ In additon we do typechecking for different types of variables. TCGv_i32
+ and TCGv_i64 are 32/64-bit variables respectively. TCGv and TCGv_ptr
+ are aliases for target_ulong and host pointer sized values respectively.
+ */
+
+#ifdef CONFIG_DEBUG_TCG
+#define DEBUG_TCGV 1
+#endif
+
+#ifdef DEBUG_TCGV
+
+typedef struct
+{
+ int i32;
+} TCGv_i32;
+
+typedef struct
+{
+ int i64;
+} TCGv_i64;
+
+#define MAKE_TCGV_I32(i) __extension__ \
+ ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_I64(i) __extension__ \
+ ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define GET_TCGV_I32(t) ((t).i32)
+#define GET_TCGV_I64(t) ((t).i64)
+#if TCG_TARGET_REG_BITS == 32
+#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
+#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
+#endif
+
+#else /* !DEBUG_TCGV */
+
+typedef int TCGv_i32;
+typedef int TCGv_i64;
+#define MAKE_TCGV_I32(x) (x)
+#define MAKE_TCGV_I64(x) (x)
+#define GET_TCGV_I32(t) (t)
+#define GET_TCGV_I64(t) (t)
+
+#if TCG_TARGET_REG_BITS == 32
+#define TCGV_LOW(t) (t)
+#define TCGV_HIGH(t) ((t) + 1)
+#endif
+
+#endif /* DEBUG_TCGV */
+
+#define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b))
+#define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b))
+
+/* Dummy definition to avoid compiler warnings. */
+#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1)
+#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
+
+/* 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) */
+/* A pure function only reads its arguments and TCG global variables
+ and cannot raise exceptions. Hence a call to a pure function can be
+ safely suppressed if the return value is not used. */
+#define TCG_CALL_PURE 0x0010
+/* A const function only reads its arguments and does not use TCG
+ global variables. Hence a call to such a function does not
+ save TCG global variables back to their canonical location. */
+#define TCG_CALL_CONST 0x0020
+
+/* used to align parameters */
+#define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1)
+#define TCG_CALL_DUMMY_ARG ((TCGArg)(-1))
+
+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;
+
+/* Invert the sense of the comparison. */
+static inline TCGCond tcg_invert_cond(TCGCond c)
+{
+ return (TCGCond)(c ^ 1);
+}
+
+/* Swap the operands in a comparison. */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+ int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
+ return (TCGCond)(c ^ mask);
+}
+
+static inline TCGCond tcg_unsigned_cond(TCGCond c)
+{
+ return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
+}
+
+#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;
+ unsigned int temp_local:1; /* If true, the temp is saved accross
+ basic blocks. Otherwise, it is not
+ preserved accross basic blocks. */
+ unsigned int temp_allocated:1; /* never used for code gen */
+ /* index of next free temp of same base type, -1 if end */
+ int next_free_temp;
+ const char *name;
+} TCGTemp;
+
+typedef struct TCGHelperInfo {
+ tcg_target_ulong func;
+ const char *name;
+} TCGHelperInfo;
+
+typedef struct TCGContext TCGContext;
+
+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;
+ /* index of free temps, -1 if none */
+ int first_free_temp[TCG_TYPE_COUNT * 2];
+
+ /* 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 */
+
+ /* liveness analysis */
+ 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];
+
+ TCGHelperInfo *helpers;
+ int nb_helpers;
+ int allocated_helpers;
+ int helpers_sorted;
+
+#ifdef CONFIG_PROFILER
+ /* profiling info */
+ int64_t tb_count1;
+ int64_t tb_count;
+ int64_t op_count; /* total insn count */
+ int op_count_max; /* max insn per TB */
+ int64_t temp_count;
+ int temp_count_max;
+ int64_t del_op_count;
+ int64_t code_in_len;
+ int64_t code_out_len;
+ int64_t interm_time;
+ int64_t code_time;
+ int64_t la_time;
+ int64_t restore_count;
+ int64_t restore_time;
+#endif
+};
+
+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_prologue_init(TCGContext *s);
+void tcg_func_start(TCGContext *s);
+
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
+
+void tcg_set_frame(TCGContext *s, int reg,
+ tcg_target_long start, tcg_target_long size);
+
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+ const char *name);
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
+static inline TCGv_i32 tcg_temp_new_i32(void)
+{
+ return tcg_temp_new_internal_i32(0);
+}
+static inline TCGv_i32 tcg_temp_local_new_i32(void)
+{
+ return tcg_temp_new_internal_i32(1);
+}
+void tcg_temp_free_i32(TCGv_i32 arg);
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
+
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+ const char *name);
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
+static inline TCGv_i64 tcg_temp_new_i64(void)
+{
+ return tcg_temp_new_internal_i64(0);
+}
+static inline TCGv_i64 tcg_temp_local_new_i64(void)
+{
+ return tcg_temp_new_internal_i64(1);
+}
+void tcg_temp_free_i64(TCGv_i64 arg);
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
+
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
+
+#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 {
+ uint16_t ct;
+ uint8_t alias_index;
+ 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
+ and potentially update globals. */
+#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
+ cannot be removed if its output
+ are not used */
+
+typedef struct TCGOpDef {
+ const char *name;
+ uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
+ uint8_t flags;
+ TCGArgConstraint *args_ct;
+ int *sorted_args;
+#if defined(CONFIG_DEBUG_TCG)
+ int used;
+#endif
+} TCGOpDef;
+
+typedef struct TCGTargetOpDef {
+ TCGOpcode op;
+ const char *args_ct_str[TCG_MAX_OP_ARGS];
+} TCGTargetOpDef;
+
+#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);
+
+#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
+#define TCGv_ptr TCGv_i32
+#define GET_TCGV_PTR GET_TCGV_I32
+#define tcg_global_reg_new_ptr tcg_global_reg_new_i32
+#define tcg_global_mem_new_ptr tcg_global_mem_new_i32
+#define tcg_temp_new_ptr tcg_temp_new_i32
+#define tcg_temp_free_ptr tcg_temp_free_i32
+#else
+#define tcg_const_ptr tcg_const_i64
+#define tcg_add_ptr tcg_add_i64
+#define tcg_sub_ptr tcg_sub_i64
+#define TCGv_ptr TCGv_i64
+#define GET_TCGV_PTR GET_TCGV_I64
+#define tcg_global_reg_new_ptr tcg_global_reg_new_i64
+#define tcg_global_mem_new_ptr tcg_global_mem_new_i64
+#define tcg_temp_new_ptr tcg_temp_new_i64
+#define tcg_temp_free_ptr tcg_temp_free_i64
+#endif
+
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+ int sizemask, TCGArg ret, int nargs, TCGArg *args);
+
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
+ int c, int right, int arith);
+
+/* only used for debugging purposes */
+void tcg_register_helper(void *func, const char *name);
+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);
+TCGv_i32 tcg_const_i32(int32_t val);
+TCGv_i64 tcg_const_i64(int64_t val);
+TCGv_i32 tcg_const_local_i32(int32_t val);
+TCGv_i64 tcg_const_local_i64(int64_t val);
+
+extern uint8_t code_gen_prologue[];
+#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
+#define tcg_qemu_tb_exec(tb_ptr) \
+ ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr)
+#else
+#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)
+#endif