Commit 45bbbb466cf4a6280076ea5a51f67ef5bedee345

Authored by bellard
1 parent d592d303

added overflow exceptions in divisions


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162
target-i386/helper.c
@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index) @@ -1209,13 +1209,13 @@ void raise_exception(int exception_index)
1209 #ifdef BUGGY_GCC_DIV64 1209 #ifdef BUGGY_GCC_DIV64
1210 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we 1210 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1211 call it from another function */ 1211 call it from another function */
1212 -uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den) 1212 +uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1213 { 1213 {
1214 *q_ptr = num / den; 1214 *q_ptr = num / den;
1215 return num % den; 1215 return num % den;
1216 } 1216 }
1217 1217
1218 -int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) 1218 +int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1219 { 1219 {
1220 *q_ptr = num / den; 1220 *q_ptr = num / den;
1221 return num % den; 1221 return num % den;
@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) @@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
1224 1224
1225 void helper_divl_EAX_T0(void) 1225 void helper_divl_EAX_T0(void)
1226 { 1226 {
1227 - unsigned int den, q, r;  
1228 - uint64_t num; 1227 + unsigned int den, r;
  1228 + uint64_t num, q;
1229 1229
1230 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); 1230 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1231 den = T0; 1231 den = T0;
@@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void) @@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
1238 q = (num / den); 1238 q = (num / den);
1239 r = (num % den); 1239 r = (num % den);
1240 #endif 1240 #endif
  1241 + if (q > 0xffffffff)
  1242 + raise_exception(EXCP00_DIVZ);
1241 EAX = (uint32_t)q; 1243 EAX = (uint32_t)q;
1242 EDX = (uint32_t)r; 1244 EDX = (uint32_t)r;
1243 } 1245 }
1244 1246
1245 void helper_idivl_EAX_T0(void) 1247 void helper_idivl_EAX_T0(void)
1246 { 1248 {
1247 - int den, q, r;  
1248 - int64_t num; 1249 + int den, r;
  1250 + int64_t num, q;
1249 1251
1250 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); 1252 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1251 den = T0; 1253 den = T0;
@@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void) @@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
1258 q = (num / den); 1260 q = (num / den);
1259 r = (num % den); 1261 r = (num % den);
1260 #endif 1262 #endif
  1263 + if (q != (int32_t)q)
  1264 + raise_exception(EXCP00_DIVZ);
1261 EAX = (uint32_t)q; 1265 EAX = (uint32_t)q;
1262 EDX = (uint32_t)r; 1266 EDX = (uint32_t)r;
1263 } 1267 }
@@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) @@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
3254 } 3258 }
3255 } 3259 }
3256 3260
3257 -/* XXX: overflow support */  
3258 -static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) 3261 +/* return TRUE if overflow */
  3262 +static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3259 { 3263 {
3260 uint64_t q, r, a1, a0; 3264 uint64_t q, r, a1, a0;
3261 int i, qb; 3265 int i, qb;
@@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) @@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3268 *plow = q; 3272 *plow = q;
3269 *phigh = r; 3273 *phigh = r;
3270 } else { 3274 } else {
  3275 + if (a1 >= b)
  3276 + return 1;
3271 /* XXX: use a better algorithm */ 3277 /* XXX: use a better algorithm */
3272 for(i = 0; i < 64; i++) { 3278 for(i = 0; i < 64; i++) {
3273 a1 = (a1 << 1) | (a0 >> 63); 3279 a1 = (a1 << 1) | (a0 >> 63);
@@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) @@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3286 *plow = a0; 3292 *plow = a0;
3287 *phigh = a1; 3293 *phigh = a1;
3288 } 3294 }
  3295 + return 0;
3289 } 3296 }
3290 3297
3291 -static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) 3298 +/* return TRUE if overflow */
  3299 +static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3292 { 3300 {
3293 int sa, sb; 3301 int sa, sb;
3294 sa = ((int64_t)*phigh < 0); 3302 sa = ((int64_t)*phigh < 0);
@@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) @@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3297 sb = (b < 0); 3305 sb = (b < 0);
3298 if (sb) 3306 if (sb)
3299 b = -b; 3307 b = -b;
3300 - div64(plow, phigh, b);  
3301 - if (sa ^ sb) 3308 + if (div64(plow, phigh, b) != 0)
  3309 + return 1;
  3310 + if (sa ^ sb) {
  3311 + if (*plow > (1ULL << 63))
  3312 + return 1;
3302 *plow = - *plow; 3313 *plow = - *plow;
  3314 + } else {
  3315 + if (*plow >= (1ULL << 63))
  3316 + return 1;
  3317 + }
3303 if (sa) 3318 if (sa)
3304 *phigh = - *phigh; 3319 *phigh = - *phigh;
  3320 + return 0;
3305 } 3321 }
3306 3322
3307 void helper_mulq_EAX_T0(void) 3323 void helper_mulq_EAX_T0(void)
@@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void) @@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void)
3344 } 3360 }
3345 r0 = EAX; 3361 r0 = EAX;
3346 r1 = EDX; 3362 r1 = EDX;
3347 - div64(&r0, &r1, T0); 3363 + if (div64(&r0, &r1, T0))
  3364 + raise_exception(EXCP00_DIVZ);
3348 EAX = r0; 3365 EAX = r0;
3349 EDX = r1; 3366 EDX = r1;
3350 } 3367 }
@@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void) @@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void)
3357 } 3374 }
3358 r0 = EAX; 3375 r0 = EAX;
3359 r1 = EDX; 3376 r1 = EDX;
3360 - idiv64(&r0, &r1, T0); 3377 + if (idiv64(&r0, &r1, T0))
  3378 + raise_exception(EXCP00_DIVZ);
3361 EAX = r0; 3379 EAX = r0;
3362 EDX = r1; 3380 EDX = r1;
3363 } 3381 }
target-i386/op.c
@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void) @@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
328 #endif 328 #endif
329 329
330 /* division, flags are undefined */ 330 /* division, flags are undefined */
331 -/* XXX: add exceptions for overflow */  
332 331
333 void OPPROTO op_divb_AL_T0(void) 332 void OPPROTO op_divb_AL_T0(void)
334 { 333 {
@@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void) @@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
339 if (den == 0) { 338 if (den == 0) {
340 raise_exception(EXCP00_DIVZ); 339 raise_exception(EXCP00_DIVZ);
341 } 340 }
342 - q = (num / den) & 0xff; 341 + q = (num / den);
  342 + if (q > 0xff)
  343 + raise_exception(EXCP00_DIVZ);
  344 + q &= 0xff;
343 r = (num % den) & 0xff; 345 r = (num % den) & 0xff;
344 EAX = (EAX & ~0xffff) | (r << 8) | q; 346 EAX = (EAX & ~0xffff) | (r << 8) | q;
345 } 347 }
@@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void) @@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
353 if (den == 0) { 355 if (den == 0) {
354 raise_exception(EXCP00_DIVZ); 356 raise_exception(EXCP00_DIVZ);
355 } 357 }
356 - q = (num / den) & 0xff; 358 + q = (num / den);
  359 + if (q != (int8_t)q)
  360 + raise_exception(EXCP00_DIVZ);
  361 + q &= 0xff;
357 r = (num % den) & 0xff; 362 r = (num % den) & 0xff;
358 EAX = (EAX & ~0xffff) | (r << 8) | q; 363 EAX = (EAX & ~0xffff) | (r << 8) | q;
359 } 364 }
@@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void) @@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
367 if (den == 0) { 372 if (den == 0) {
368 raise_exception(EXCP00_DIVZ); 373 raise_exception(EXCP00_DIVZ);
369 } 374 }
370 - q = (num / den) & 0xffff; 375 + q = (num / den);
  376 + if (q > 0xffff)
  377 + raise_exception(EXCP00_DIVZ);
  378 + q &= 0xffff;
371 r = (num % den) & 0xffff; 379 r = (num % den) & 0xffff;
372 EAX = (EAX & ~0xffff) | q; 380 EAX = (EAX & ~0xffff) | q;
373 EDX = (EDX & ~0xffff) | r; 381 EDX = (EDX & ~0xffff) | r;
@@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void) @@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
382 if (den == 0) { 390 if (den == 0) {
383 raise_exception(EXCP00_DIVZ); 391 raise_exception(EXCP00_DIVZ);
384 } 392 }
385 - q = (num / den) & 0xffff; 393 + q = (num / den);
  394 + if (q != (int16_t)q)
  395 + raise_exception(EXCP00_DIVZ);
  396 + q &= 0xffff;
386 r = (num % den) & 0xffff; 397 r = (num % den) & 0xffff;
387 EAX = (EAX & ~0xffff) | q; 398 EAX = (EAX & ~0xffff) | q;
388 EDX = (EDX & ~0xffff) | r; 399 EDX = (EDX & ~0xffff) | r;