Commit 398ce98e4f4286370d97a7e51b01bf6334c3b65e
1 parent
0f459d16
Fix div[u]2.
Previous code assummed 32 by 32 bit divmod operation, and survived x86_64 test only by sheer luck. MIPS wasn't so forgiving. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4705 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
65 additions
and
26 deletions
tcg/ppc/tcg-target.c
| ... | ... | @@ -198,6 +198,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) |
| 198 | 198 | |
| 199 | 199 | ct_str = *pct_str; |
| 200 | 200 | switch (ct_str[0]) { |
| 201 | + case 'A': case 'B': case 'C': case 'D': | |
| 202 | + ct->ct |= TCG_CT_REG; | |
| 203 | + tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A'); | |
| 204 | + break; | |
| 201 | 205 | case 'r': |
| 202 | 206 | ct->ct |= TCG_CT_REG; |
| 203 | 207 | tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
| ... | ... | @@ -1014,6 +1018,63 @@ static void tcg_out_brcond2(TCGContext *s, |
| 1014 | 1018 | tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); |
| 1015 | 1019 | } |
| 1016 | 1020 | |
| 1021 | +static uint64_t __attribute ((used)) ppc_udiv_helper (uint64_t a, uint32_t b) | |
| 1022 | +{ | |
| 1023 | + uint64_t rem, quo; | |
| 1024 | + quo = a / b; | |
| 1025 | + rem = a % b; | |
| 1026 | + return (rem << 32) | (uint32_t) quo; | |
| 1027 | +} | |
| 1028 | + | |
| 1029 | +static uint64_t __attribute ((used)) ppc_div_helper (int64_t a, int32_t b) | |
| 1030 | +{ | |
| 1031 | + int64_t rem, quo; | |
| 1032 | + quo = a / b; | |
| 1033 | + rem = a % b; | |
| 1034 | + return (rem << 32) | (uint32_t) quo; | |
| 1035 | +} | |
| 1036 | + | |
| 1037 | +#define MAKE_TRAMPOLINE(name) \ | |
| 1038 | +extern void name##_trampoline (void); \ | |
| 1039 | +asm (#name "_trampoline:\n" \ | |
| 1040 | + " mflr 0\n" \ | |
| 1041 | + " addi 1,1,-112\n" \ | |
| 1042 | + " mr 4,6\n" \ | |
| 1043 | + " stmw 7,0(1)\n" \ | |
| 1044 | + " stw 0,108(0)\n" \ | |
| 1045 | + " bl ppc_" #name "_helper\n" \ | |
| 1046 | + " lmw 7,0(1)\n" \ | |
| 1047 | + " lwz 0,108(0)\n" \ | |
| 1048 | + " addi 1,1,112\n" \ | |
| 1049 | + " mtlr 0\n" \ | |
| 1050 | + " blr\n" \ | |
| 1051 | + ) | |
| 1052 | + | |
| 1053 | +MAKE_TRAMPOLINE (div); | |
| 1054 | +MAKE_TRAMPOLINE (udiv); | |
| 1055 | + | |
| 1056 | +static void tcg_out_div2 (TCGContext *s, int uns) | |
| 1057 | +{ | |
| 1058 | + void *label1_ptr, *label2_ptr; | |
| 1059 | + | |
| 1060 | + tcg_out32 (s, CMPLI | BF (7) | RA (3)); | |
| 1061 | + label1_ptr = s->code_ptr; | |
| 1062 | + tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); | |
| 1063 | + | |
| 1064 | + tcg_out_b (s, LK, (tcg_target_long) (uns ? udiv_trampoline : div_trampoline)); | |
| 1065 | + | |
| 1066 | + label2_ptr = s->code_ptr; | |
| 1067 | + tcg_out32 (s, B); | |
| 1068 | + | |
| 1069 | + reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); | |
| 1070 | + | |
| 1071 | + tcg_out32 (s, (uns ? DIVWU : DIVW) | TAB (6, 4, 5)); | |
| 1072 | + tcg_out32 (s, MULLW | TAB (0, 6, 5)); | |
| 1073 | + tcg_out32 (s, SUBF | TAB (3, 0, 4)); | |
| 1074 | + | |
| 1075 | + reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); | |
| 1076 | +} | |
| 1077 | + | |
| 1017 | 1078 | static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
| 1018 | 1079 | const int *const_args) |
| 1019 | 1080 | { |
| ... | ... | @@ -1204,32 +1265,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
| 1204 | 1265 | } |
| 1205 | 1266 | break; |
| 1206 | 1267 | case INDEX_op_div2_i32: |
| 1207 | - if (args[0] == args[2] || args[0] == args[3]) { | |
| 1208 | - tcg_out32 (s, DIVW | TAB (0, args[2], args[3])); | |
| 1209 | - tcg_out32 (s, MTSPR | RS (0) | CTR); | |
| 1210 | - tcg_out32 (s, MULLW | TAB (0, 0, args[3])); | |
| 1211 | - tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
| 1212 | - tcg_out32 (s, MFSPR | RT (args[0]) | CTR); | |
| 1213 | - } | |
| 1214 | - else { | |
| 1215 | - tcg_out32 (s, DIVW | TAB (args[0], args[2], args[3])); | |
| 1216 | - tcg_out32 (s, MULLW | TAB (0, args[0], args[3])); | |
| 1217 | - tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
| 1218 | - } | |
| 1268 | + tcg_out_div2 (s, 0); | |
| 1219 | 1269 | break; |
| 1220 | 1270 | case INDEX_op_divu2_i32: |
| 1221 | - if (args[0] == args[2] || args[0] == args[3]) { | |
| 1222 | - tcg_out32 (s, DIVWU | TAB (0, args[2], args[3])); | |
| 1223 | - tcg_out32 (s, MTSPR | RS (0) | CTR); | |
| 1224 | - tcg_out32 (s, MULLW | TAB (0, 0, args[3])); | |
| 1225 | - tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
| 1226 | - tcg_out32 (s, MFSPR | RT (args[0]) | CTR); | |
| 1227 | - } | |
| 1228 | - else { | |
| 1229 | - tcg_out32 (s, DIVWU | TAB (args[0], args[2], args[3])); | |
| 1230 | - tcg_out32 (s, MULLW | TAB (0, args[0], args[3])); | |
| 1231 | - tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
| 1232 | - } | |
| 1271 | + tcg_out_div2 (s, 1); | |
| 1233 | 1272 | break; |
| 1234 | 1273 | |
| 1235 | 1274 | case INDEX_op_shl_i32: |
| ... | ... | @@ -1372,8 +1411,8 @@ static const TCGTargetOpDef ppc_op_defs[] = { |
| 1372 | 1411 | { INDEX_op_add_i32, { "r", "r", "ri" } }, |
| 1373 | 1412 | { INDEX_op_mul_i32, { "r", "r", "ri" } }, |
| 1374 | 1413 | { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, |
| 1375 | - { INDEX_op_div2_i32, { "r", "r", "r", "r", "r" } }, | |
| 1376 | - { INDEX_op_divu2_i32, { "r", "r", "r", "r", "r" } }, | |
| 1414 | + { INDEX_op_div2_i32, { "D", "A", "B", "1", "C" } }, | |
| 1415 | + { INDEX_op_divu2_i32, { "D", "A", "B", "1", "C" } }, | |
| 1377 | 1416 | { INDEX_op_sub_i32, { "r", "r", "ri" } }, |
| 1378 | 1417 | { INDEX_op_and_i32, { "r", "r", "ri" } }, |
| 1379 | 1418 | { INDEX_op_or_i32, { "r", "r", "ri" } }, | ... | ... |