diff options
Diffstat (limited to 'tcg/ppc64')
-rw-r--r-- | tcg/ppc64/tcg-target.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 803db481fd..fed179c616 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -305,6 +305,7 @@ static int tcg_target_const_match (tcg_target_long val, #define LWA XO58( 2) #define LWAX XO31(341) +#define ADDIC OPCD( 12) #define ADDI OPCD( 14) #define ADDIS OPCD( 15) #define ORI OPCD( 24) @@ -332,6 +333,7 @@ static int tcg_target_const_match (tcg_target_long val, #define CRANDC XO19(129) #define CRNAND XO19(225) #define CROR XO19(449) +#define CRNOR XO19( 33) #define EXTSB XO31(954) #define EXTSH XO31(922) @@ -359,6 +361,9 @@ 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 CNTLZD XO31( 58) #define MULLD XO31(233) #define MULHD XO31( 73) @@ -1044,6 +1049,122 @@ static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, } +static void tcg_out_setcond (TCGContext *s, TCGType type, int 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]; @@ -1433,6 +1554,15 @@ static void tcg_out_op (TCGContext *s, int opc, const TCGArg *args, 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 (); @@ -1530,6 +1660,9 @@ static const TCGTargetOpDef ppc_op_defs[] = { { 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 }, }; |