Commit 398ce98e4f4286370d97a7e51b01bf6334c3b65e

Authored by malc
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,6 +198,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
198 198
199 ct_str = *pct_str; 199 ct_str = *pct_str;
200 switch (ct_str[0]) { 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 case 'r': 205 case 'r':
202 ct->ct |= TCG_CT_REG; 206 ct->ct |= TCG_CT_REG;
203 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); 207 tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
@@ -1014,6 +1018,63 @@ static void tcg_out_brcond2(TCGContext *s, @@ -1014,6 +1018,63 @@ static void tcg_out_brcond2(TCGContext *s,
1014 tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr); 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 static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, 1078 static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
1018 const int *const_args) 1079 const int *const_args)
1019 { 1080 {
@@ -1204,32 +1265,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, @@ -1204,32 +1265,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
1204 } 1265 }
1205 break; 1266 break;
1206 case INDEX_op_div2_i32: 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 break; 1269 break;
1220 case INDEX_op_divu2_i32: 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 break; 1272 break;
1234 1273
1235 case INDEX_op_shl_i32: 1274 case INDEX_op_shl_i32:
@@ -1372,8 +1411,8 @@ static const TCGTargetOpDef ppc_op_defs[] = { @@ -1372,8 +1411,8 @@ static const TCGTargetOpDef ppc_op_defs[] = {
1372 { INDEX_op_add_i32, { "r", "r", "ri" } }, 1411 { INDEX_op_add_i32, { "r", "r", "ri" } },
1373 { INDEX_op_mul_i32, { "r", "r", "ri" } }, 1412 { INDEX_op_mul_i32, { "r", "r", "ri" } },
1374 { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, 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 { INDEX_op_sub_i32, { "r", "r", "ri" } }, 1416 { INDEX_op_sub_i32, { "r", "r", "ri" } },
1378 { INDEX_op_and_i32, { "r", "r", "ri" } }, 1417 { INDEX_op_and_i32, { "r", "r", "ri" } },
1379 { INDEX_op_or_i32, { "r", "r", "ri" } }, 1418 { INDEX_op_or_i32, { "r", "r", "ri" } },