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
-#if TARGET_PHYS_ADDR_BITS <= 32
-#define ADDEND_OFFSET 0
+
+#ifndef GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
+#ifdef CONFIG_USE_GUEST_BASE
+#define TCG_GUEST_BASE_REG 30
#else
-#define ADDEND_OFFSET 4
+#define TCG_GUEST_BASE_REG 0
#endif
+#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"r0",
"r1",
- "rp",
+ "r2",
"r3",
"r4",
"r5",
"r30",
"r31"
};
+#endif
static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R14,
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_R8,
TCG_REG_R9,
TCG_REG_R10,
+#ifndef _CALL_DARWIN
TCG_REG_R11,
+#endif
TCG_REG_R12,
+#ifndef _CALL_SYSV
TCG_REG_R13,
- TCG_REG_R0,
- TCG_REG_R1,
- TCG_REG_R2,
+#endif
TCG_REG_R24,
TCG_REG_R25,
TCG_REG_R26,
};
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_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 */
TCG_REG_R28,
TCG_REG_R29,
TCG_REG_R30,
/* maximum number of register used for input function arguments */
static int tcg_target_get_call_iarg_regs_count(int flags)
{
- return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]);
+ return ARRAY_SIZE (tcg_target_call_iarg_regs);
}
/* parse target specific constraints */
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_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;
}
#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 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 CRANDC XO19(129)
#define CRNAND XO19(225)
#define CROR XO19(449)
+#define CRNOR XO19( 33)
#define EXTSB XO31(954)
#define EXTSH XO31(922)
#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(276)
+#define LHZX XO31(279)
#define LHAX XO31(343)
#define LWZX XO31( 23)
#define STBX XO31(215)
#define SRW XO31(536)
#define SRAW XO31(792)
-#define LMW OPCD(46)
-#define STMW OPCD(47)
-
#define TW XO31(4)
#define TRAP (TW | TO (31))
[TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
};
-static void tcg_out_mov(TCGContext *s, int ret, int arg)
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
{
tcg_out32 (s, OR | SAB (arg, ret, arg));
}
static void tcg_out_movi(TCGContext *s, TCGType type,
- int ret, tcg_target_long arg)
+ TCGReg ret, tcg_target_long arg)
{
if (arg == (int16_t) arg)
tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff));
}
}
+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)
-extern void __ldb_mmu(void);
-extern void __ldw_mmu(void);
-extern void __ldl_mmu(void);
-extern void __ldq_mmu(void);
-extern void __stb_mmu(void);
-extern void __stw_mmu(void);
-extern void __stl_mmu(void);
-extern void __stq_mmu(void);
+#include "../../softmmu_defs.h"
static void *qemu_ld_helpers[4] = {
__ldb_mmu,
static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
{
- int addr_reg, data_reg, data_reg2, r0, mem_index, s_bits, bswap;
+ int addr_reg, data_reg, data_reg2, r0, r1, rbase, bswap;
#ifdef CONFIG_SOFTMMU
- int r1, r2;
+ int mem_index, s_bits, r2;
void *label1_ptr, *label2_ptr;
-#endif
#if TARGET_LONG_BITS == 64
int addr_reg2;
+#endif
#endif
data_reg = *args++;
else
data_reg2 = 0;
addr_reg = *args++;
+
+#ifdef CONFIG_SOFTMMU
#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)
/* slow path */
#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, 3, addr_reg);
+ 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, 3, addr_reg2);
- tcg_out_mov (s, 4, addr_reg);
+ 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_b (s, LK, (tcg_target_long) qemu_ld_helpers[s_bits]);
+ 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));
case 1:
case 2:
if (data_reg != 3)
- tcg_out_mov (s, 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, 0, 4);
- tcg_out_mov (s, 4, 3);
- tcg_out_mov (s, 3, 0);
+ 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, data_reg2, 3);
- tcg_out_mov (s, 3, 4);
+ 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, data_reg, 4);
- if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3);
+ 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;
}
tcg_out32 (s, (LWZ
| RT (r0)
| RA (r0)
- | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend)
+ | (offsetof (CPUTLBEntry, addend)
- offsetof (CPUTLBEntry, addr_read))
));
/* r0 = env->tlb_table[mem_index][index].addend */
#else /* !CONFIG_SOFTMMU */
r0 = addr_reg;
+ r1 = 3;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
#endif
#ifdef TARGET_WORDS_BIGENDIAN
#else
bswap = 1;
#endif
+
switch (opc) {
default:
case 0:
- tcg_out32 (s, LBZ | RT (data_reg) | RA (r0));
+ tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
break;
case 0|4:
- tcg_out32 (s, LBZ | RT (data_reg) | RA (r0));
+ 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 | RT (data_reg) | RB (r0));
- else tcg_out32 (s, LHZ | RT (data_reg) | RA (r0));
+ 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 | RT (data_reg) | RB (r0));
+ tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
}
- else tcg_out32 (s, LHA | RT (data_reg) | RA (r0));
+ else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
break;
case 2:
- if (bswap) tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
- else tcg_out32 (s, LWZ | RT (data_reg)| RA (r0));
+ 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) {
- if (r0 == data_reg) {
- tcg_out32 (s, LWBRX | RT (0) | RB (r0));
- tcg_out32 (s, ADDI | RT (r0) | RA (r0) | 4);
- tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r0));
- tcg_out_mov (s, data_reg, 0);
- }
- else {
- tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
- tcg_out32 (s, ADDI | RT (r0) | RA (r0) | 4);
- tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r0));
- }
+ 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, data_reg2, 0);
+ 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;
}
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;
+ int addr_reg, r0, r1, data_reg, data_reg2, bswap, rbase;
#ifdef CONFIG_SOFTMMU
- int r2, ir;
+ int mem_index, r2, ir;
void *label1_ptr, *label2_ptr;
-#endif
#if TARGET_LONG_BITS == 64
int addr_reg2;
+#endif
#endif
data_reg = *args++;
else
data_reg2 = 0;
addr_reg = *args++;
+
+#ifdef CONFIG_SOFTMMU
#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)
/* slow path */
#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, 3, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
ir = 4;
#else
- tcg_out_mov (s, 3, addr_reg2);
- tcg_out_mov (s, 4, addr_reg);
+ 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) {
| ME (31)));
break;
case 2:
- tcg_out_mov (s, ir, data_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
break;
case 3:
- tcg_out_mov (s, 5, data_reg2);
- tcg_out_mov (s, 6, data_reg);
- ir = 6;
+#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_b (s, LK, (tcg_target_long) qemu_st_helpers[opc]);
+ tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
label2_ptr = s->code_ptr;
tcg_out32 (s, B);
tcg_out32 (s, (LWZ
| RT (r0)
| RA (r0)
- | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend)
+ | (offsetof (CPUTLBEntry, addend)
- offsetof (CPUTLBEntry, addr_write))
));
/* r0 = env->tlb_table[mem_index][index].addend */
/* r0 = env->tlb_table[mem_index][index].addend + addr */
#else /* !CONFIG_SOFTMMU */
- r1 = 4;
r0 = addr_reg;
+ r1 = 3;
+ rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
#endif
#ifdef TARGET_WORDS_BIGENDIAN
#endif
switch (opc) {
case 0:
- tcg_out32 (s, STB | RS (data_reg) | RA (r0));
+ tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
break;
case 1:
- if (bswap) tcg_out32 (s, STHBRX | RS (data_reg) | RA (0) | RB (r0));
- else tcg_out32 (s, STH | RS (data_reg) | RA (r0));
+ 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 | RS (data_reg) | RA (0) | RB (r0));
- else tcg_out32 (s, STW | RS (data_reg) | RA (r0));
+ 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 | RS (data_reg) | RA (0) | RB (r0));
- tcg_out32 (s, STWBRX | RS (data_reg2) | RA (0) | RB (r1));
+ 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;
}
#endif
}
-void tcg_target_qemu_prologue (TCGContext *s)
+static void tcg_target_qemu_prologue (TCGContext *s)
{
int i, frame_size;
frame_size = 0
- + 4 /* back chain */
- + 4 /* LR */
+ + LINKAGE_AREA_SIZE
+ TCG_STATIC_CALL_ARGS_SIZE
+ ARRAY_SIZE (tcg_target_callee_save_regs) * 4
+ + CPU_TEMP_BUF_NLONGS * sizeof(long)
;
frame_size = (frame_size + 15) & ~15;
+ tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+ - CPU_TEMP_BUF_NLONGS * sizeof(long),
+ CPU_TEMP_BUF_NLONGS * sizeof(long));
+
+#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 + 8 + TCG_STATIC_CALL_ARGS_SIZE)
+ | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
)
);
- tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + 4));
+ 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_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+ tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
tcg_out32 (s, BCCTR | BO_ALWAYS);
tb_ret_addr = s->code_ptr;
tcg_out32 (s, (LWZ
| RT (tcg_target_callee_save_regs[i])
| RA (1)
- | (i * 4 + 8 + TCG_STATIC_CALL_ARGS_SIZE)
+ | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
)
);
- tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + 4));
+ 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,
+static void tcg_out_ld (TCGContext *s, TCGType type, TCGReg ret, TCGReg 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,
+static void tcg_out_st (TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
tcg_target_long arg2)
{
tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
}
}
-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)
{
}
}
-static void tcg_out_brcond (TCGContext *s, int 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)
+static void tcg_out_cr7eq_from_cond (TCGContext *s, const TCGArg *args,
+ const int *const_args)
{
- int cond = args[4], label_index = args[5], op;
+ 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 },
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_COND_EQ, args[1], args[3], const_args[3], 6);
- tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 7);
- tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, b->bit2));
+ 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)
+ )
+ );
+}
- tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), label_index);
+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);
}
-static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
+/* 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) {
}
break;
case INDEX_op_call:
- if (const_args[0]) {
- tcg_out_b (s, LK, args[0]);
- }
- else {
- tcg_out32 (s, MTSPR | RS (args[0]) | LR);
- tcg_out32 (s, BCLR | BO_ALWAYS | LK);
- }
+ tcg_out_call (s, args[0], const_args[0]);
break;
case INDEX_op_jmp:
if (const_args[0]) {
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, TCG_TYPE_I32, 0, args[2]);
- tcg_out32 (s, AND | SAB (args[1], args[0], 0));
+ 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
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[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, args[0], 0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
}
else {
tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3]));
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, args[0], 0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
}
else {
tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4]));
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, args[0], 0);
+ 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, 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_ld16s:
tcg_out_qemu_ld(s, args, 1 | 4);
break;
- case INDEX_op_qemu_ld32u:
+ case INDEX_op_qemu_ld32:
tcg_out_qemu_ld(s, args, 2);
break;
case INDEX_op_qemu_ld64:
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;
+
+ case INDEX_op_deposit_i32:
+ tcg_out32 (s, RLWIMI
+ | RA (args[0])
+ | RS (args[2])
+ | SH (args[3])
+ | MB (32 - args[3] - args[4])
+ | ME (31 - args[3])
+ );
+ break;
default:
tcg_dump_ops (s, stderr);
{ 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_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_ld32u, { "r", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
{ INDEX_op_qemu_ld64, { "r", "r", "L" } },
{ INDEX_op_qemu_st8, { "K", "K" } },
{ INDEX_op_qemu_ld8s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32s, { "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" } },
#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" } },
+
+ { INDEX_op_deposit_i32, { "r", "0", "r" } },
{ -1 },
};
-void tcg_target_init(TCGContext *s)
+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) |
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);
}