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" } }, | ... | ... |