]> git.proxmox.com Git - qemu.git/blobdiff - tcg/ppc/tcg-target.c
tcg: Use TCGReg for standard tcg-target entry points.
[qemu.git] / tcg / ppc / tcg-target.c
index 13f0fe55de14148fd6916bdce45e99a9f718e457..f5d9bf3b00b5bbab8f815abee8172aed18abdc6a 100644 (file)
 
 static uint8_t *tb_ret_addr;
 
-#define TCG_CT_PC14 0x100
-#define TCG_CT_PC24 0x200
+#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",
@@ -68,11 +82,26 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "r30",
     "r31"
 };
+#endif
 
 static const int tcg_target_reg_alloc_order[] = {
-    TCG_REG_R0,
-    TCG_REG_R1,
+    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,
@@ -81,27 +110,17 @@ static const int tcg_target_reg_alloc_order[] = {
     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_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,
+#endif
     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_R27
 };
 
 static const int tcg_target_call_iarg_regs[] = {
@@ -121,7 +140,13 @@ static const int tcg_target_call_oarg_regs[2] = {
 };
 
 static const int tcg_target_callee_save_regs[] = {
-    TCG_REG_R13,                /* sould r13 be saved? */
+#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,
@@ -132,6 +157,10 @@ static const int tcg_target_callee_save_regs[] = {
     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,
@@ -140,7 +169,13 @@ static const int tcg_target_callee_save_regs[] = {
 
 static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
 {
-    return (target - (tcg_target_long) pc) & 0x3fffffc;
+    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)
@@ -151,7 +186,13 @@ static void reloc_pc24 (void *pc, tcg_target_long target)
 
 static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
 {
-    return (target - (tcg_target_long) pc) & 0xfffc;
+    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)
@@ -179,7 +220,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
 /* 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 */
@@ -189,10 +230,15 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_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);
@@ -218,12 +264,18 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7);
         break;
-    case 'J':                   /* 24 bit displacement */
-        ct->ct |= TCG_CT_PC24;
+#else
+    case 'L':
+    case 'K':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
         break;
-    case 'j':                   /* 16 bit displacement */
-        ct->ct |= TCG_CT_PC14;
+    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;
     }
@@ -241,13 +293,6 @@ static int tcg_target_const_match(tcg_target_long val,
     ct = arg_ct->ct;
     if (ct & TCG_CT_CONST)
         return 1;
-    else if (ct & TCG_CT_PC14) {
-        return val == (int16_t) val;
-    }
-    else if (ct & TCG_CT_PC24) {
-        if (val < 0) return val > -0x800000;
-        return val < 0x7fffff;
-    }
     return 0;
 }
 
@@ -265,6 +310,7 @@ static int tcg_target_const_match(tcg_target_long val,
 #define STH    OPCD(44)
 #define STW    OPCD(36)
 
+#define ADDIC  OPCD(12)
 #define ADDI   OPCD(14)
 #define ADDIS  OPCD(15)
 #define ORI    OPCD(24)
@@ -276,15 +322,22 @@ static int tcg_target_const_match(tcg_target_long val,
 #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 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)
@@ -311,9 +364,16 @@ static int tcg_target_const_match(tcg_target_long val,
 #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)
@@ -328,9 +388,6 @@ static int tcg_target_const_match(tcg_target_long val,
 #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))
 
@@ -379,20 +436,20 @@ static const uint32_t tcg_to_bc[10] = {
     [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));
     else {
         tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff));
         if (arg & 0xffff)
-            tcg_out32 (s, ORI | RT (ret) | RA (ret) | (arg & 0xffff));
+            tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff));
     }
 }
 
@@ -407,16 +464,49 @@ static void tcg_out_ldst (TCGContext *s, int ret, int addr,
     }
 }
 
+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)
-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,
@@ -435,13 +525,13 @@ static void *qemu_st_helpers[4] = {
 
 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++;
@@ -450,16 +540,17 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     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)
@@ -499,16 +590,15 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 
     /* 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_out32 (s, B | reloc_pc24_val (s->code_ptr,
-                                      (tcg_target_long) qemu_ld_helpers[s_bits]) | LK);
+    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));
@@ -520,23 +610,23 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     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;
     }
@@ -552,7 +642,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     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 */
@@ -561,6 +651,8 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 
 #else  /* !CONFIG_SOFTMMU */
     r0 = addr_reg;
+    r1 = 3;
+    rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
 #endif
 
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -568,54 +660,57 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 #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;
     }
@@ -627,13 +722,13 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 
 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++;
@@ -642,15 +737,16 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     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)
@@ -690,12 +786,16 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
 
     /* 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) {
@@ -716,19 +816,20 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int 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_out32 (s, B | reloc_pc24_val (s->code_ptr,
-                                      (tcg_target_long) qemu_st_helpers[opc]) | LK);
+    tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
     label2_ptr = s->code_ptr;
     tcg_out32 (s, B);
 
@@ -740,7 +841,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     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 */
@@ -748,8 +849,9 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     /* 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
@@ -759,25 +861,35 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
 #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;
     }
@@ -787,30 +899,52 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
 #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;
 
@@ -818,22 +952,22 @@ void tcg_target_qemu_prologue (TCGContext *s)
         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);
@@ -853,35 +987,65 @@ static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si)
     }
 }
 
-static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
+                         int const_arg2, int cr)
 {
-    ppc_addi (s, reg, reg, val);
-}
-
-static void tcg_out_brcond(TCGContext *s, int cond,
-                           TCGArg arg1, TCGArg arg2, int const_arg2,
-                           int label_index)
-{
-    TCGLabel *l = &s->labels[label_index];
     int imm;
     uint32_t op;
 
-    imm = const_arg2 ? ((int16_t) arg2 == arg2) : 0;
     switch (cond) {
-    case TCG_COND_EQ: op = imm ? CMPLI : CMPL; break;
-    case TCG_COND_NE: op = imm ? CMPLI : CMPL; break;
-    case TCG_COND_LT: op = imm ? CMPI : CMP; break;
-    case TCG_COND_GE: op = imm ? CMPI : CMP; break;
-    case TCG_COND_LE: op = imm ? CMPI : CMP; break;
-    case TCG_COND_GT: op = imm ? CMPI : CMP; break;
-    case TCG_COND_LTU: op = imm ? CMPLI : CMPL; break;
-    case TCG_COND_GEU: op = imm ? CMPLI : CMPL; break;
-    case TCG_COND_LEU: op = imm ? CMPLI : CMPL; break;
-    case TCG_COND_GTU: op = imm ? CMPLI : CMPL; break;
+    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 (7);
+    op |= BF (cr);
 
     if (imm)
         tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff));
@@ -894,93 +1058,255 @@ static void tcg_out_brcond(TCGContext *s, int cond,
             tcg_out32 (s, op | RA (arg1) | RB (arg2));
     }
 
-    if (l->has_value) {
-        tcg_out32 (s, tcg_to_bc[cond] | reloc_pc14_val (s->code_ptr,
-                                                        l->u.value));
-    }
+}
+
+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 {
-        tcg_out32 (s, tcg_to_bc[cond]);
+        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);
     }
 }
 
-/* brcond2 is taken verbatim from i386 tcg-target */
-/* 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 label_next;
-    label_next = gen_new_label();
-    switch(args[4]) {
+    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:
-        tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next);
-        tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]);
-        break;
     case TCG_COND_NE:
-        tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]);
+        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:
-        tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_LT, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_LE:
-        tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_LE, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_GT:
-        tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_GT, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_GE:
-        tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_GE, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_LTU:
-        tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_LEU:
-        tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_GTU:
-        tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]);
-        break;
     case TCG_COND_GEU:
-        tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]);
-        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);
-        tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]);
+        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();
     }
-    tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
 }
 
-static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
+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_out32 (s, B | reloc_pc24_val (s->code_ptr, (tcg_target_long) tb_ret_addr));
+        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;
-            tcg_out32 (s, B | 4);
-        } else {
+            s->code_ptr += 16;
+        }
+        else {
             tcg_abort ();
         }
         s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
@@ -990,26 +1316,23 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
             TCGLabel *l = &s->labels[args[0]];
 
             if (l->has_value) {
-                tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, l->u.value));
+                tcg_out_b (s, 0, l->u.value);
             }
             else {
-                tcg_out32 (s, B);
+                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:
-        if (const_args[0]) {
-            tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, args[0]) | LK);
-        }
-        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]) {
-            tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, args[0]));
+            tcg_out_b (s, 0, args[0]);
         }
         else {
             tcg_out32 (s, MTSPR | RS (args[0]) | CTR);
@@ -1060,20 +1383,58 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
 
     case INDEX_op_and_i32:
         if (const_args[2]) {
-            if (!args[2])
+            uint32_t c;
+
+            c = args[2];
+
+            if (!c) {
                 tcg_out_movi (s, TCG_TYPE_I32, args[0], 0);
-            else {
-                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 if (args[2] == 0xffffffff) {
-                    if (args[0] != args[1])
-                        tcg_out_mov (s, args[0], args[1]);
+                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 {
-                    tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]);
+                    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));
                 }
             }
@@ -1083,21 +1444,16 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         break;
     case INDEX_op_or_i32:
         if (const_args[2]) {
-            if (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])
+            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 {
-                if (args[0] != args[1])
-                    tcg_out_mov (s, args[0], args[1]);
+                tcg_out32 (s, ORIS | RS (args[1])  | RA (args[0])
+                           | ((args[2] >> 16) & 0xffff));
             }
         }
         else
@@ -1105,26 +1461,35 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         break;
     case INDEX_op_xor_i32:
         if (const_args[2]) {
-            if (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));
-                }
-            }
+            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 {
-                if (args[0] != args[1])
-                    tcg_out_mov (s, args[0], args[1]);
+                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]) {
@@ -1139,76 +1504,63 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         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, 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]));
             tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
         }
         break;
-    case INDEX_op_div2_i32:
-        if (args[0] == args[2] || args[0] == args[3]) {
-            tcg_out32 (s, DIVW | TAB (0, args[2], args[3]));
-            tcg_out32 (s, MULLW | TAB (0, 0, args[3]));
-            tcg_out32 (s, SUBF | TAB (0, 0, args[2]));
-            tcg_out32 (s, DIVW | TAB (args[0], args[2], args[3]));
-            tcg_out_mov (s, args[1], 0);
-        }
-        else {
-            tcg_out32 (s, DIVW | TAB (args[0], args[2], args[3]));
-            tcg_out32 (s, MULLW | TAB (0, args[0], args[3]));
-            tcg_out32 (s, SUBF | TAB (args[1], 0, args[2]));
-        }
-        break;
-    case INDEX_op_divu2_i32:
-        if (args[0] == args[2] || args[0] == args[3]) {
-            tcg_out32 (s, DIVWU | TAB (0, args[2], args[3]));
-            tcg_out32 (s, MULLW | TAB (0, 0, args[3]));
-            tcg_out32 (s, SUBF | TAB (0, 0, args[2]));
-            tcg_out32 (s, DIVWU | TAB (args[0], args[2], args[3]));
-            tcg_out_mov (s, args[1], 0);
-        }
-        else {
-            tcg_out32 (s, DIVWU | TAB (args[0], args[2], args[3]));
-            tcg_out32 (s, MULLW | TAB (0, args[0], args[3]));
-            tcg_out32 (s, SUBF | TAB (args[1], 0, args[2]));
-        }
-        break;
 
     case INDEX_op_shl_i32:
         if (const_args[2]) {
-            if (args[2])
-                tcg_out32 (s, (RLWINM
-                               | RA (args[0])
-                               | RS (args[1])
-                               | SH (args[2])
-                               | MB (0)
-                               | ME (31 - args[2])
-                               )
-                    );
-            else
-                tcg_out_mov (s, args[0], args[1]);
+            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]) {
-            if (args[2])
-                tcg_out32 (s, (RLWINM
-                               | RA (args[0])
-                               | RS (args[1])
-                               | SH (32 - args[2])
-                               | MB (args[2])
-                               | ME (31)
-                               )
-                    );
-            else
-                tcg_out_mov (s, args[0], args[1]);
+            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]));
@@ -1219,12 +1571,51 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         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]));
@@ -1235,7 +1626,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         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]));
@@ -1261,6 +1652,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         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;
@@ -1273,7 +1668,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
     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:
@@ -1292,6 +1687,119 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
         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;
+
+    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);
         tcg_abort ();
@@ -1301,8 +1809,8 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
 static const TCGTargetOpDef ppc_op_defs[] = {
     { INDEX_op_exit_tb, { } },
     { INDEX_op_goto_tb, { } },
-    { INDEX_op_call, { "rJ" } },
-    { INDEX_op_jmp, { "rJ" } },
+    { INDEX_op_call, { "ri" } },
+    { INDEX_op_jmp, { "ri" } },
     { INDEX_op_br, { } },
 
     { INDEX_op_mov_i32, { "r", "r" } },
@@ -1318,9 +1826,11 @@ static const TCGTargetOpDef ppc_op_defs[] = {
 
     { 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_div2_i32, { "r", "r", "r", "r", "r" } },
-    { INDEX_op_divu2_i32, { "r", "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" } },
@@ -1330,6 +1840,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { 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" } },
@@ -1337,14 +1850,26 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { 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" } },
@@ -1356,8 +1881,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { 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" } },
@@ -1366,14 +1890,24 @@ static const TCGTargetOpDef ppc_op_defs[] = {
     { 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" } },
+
+    { 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) |
@@ -1389,7 +1923,12 @@ void tcg_target_init(TCGContext *s)
     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);
 }