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 1209 #ifdef BUGGY_GCC_DIV64
1210 1210 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1211 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 1214 *q_ptr = num / den;
1215 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 1220 *q_ptr = num / den;
1221 1221 return num % den;
... ... @@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
1224 1224  
1225 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 1230 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1231 1231 den = T0;
... ... @@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
1238 1238 q = (num / den);
1239 1239 r = (num % den);
1240 1240 #endif
  1241 + if (q > 0xffffffff)
  1242 + raise_exception(EXCP00_DIVZ);
1241 1243 EAX = (uint32_t)q;
1242 1244 EDX = (uint32_t)r;
1243 1245 }
1244 1246  
1245 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 1252 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1251 1253 den = T0;
... ... @@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
1258 1260 q = (num / den);
1259 1261 r = (num % den);
1260 1262 #endif
  1263 + if (q != (int32_t)q)
  1264 + raise_exception(EXCP00_DIVZ);
1261 1265 EAX = (uint32_t)q;
1262 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 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 3264 uint64_t q, r, a1, a0;
3261 3265 int i, qb;
... ... @@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3268 3272 *plow = q;
3269 3273 *phigh = r;
3270 3274 } else {
  3275 + if (a1 >= b)
  3276 + return 1;
3271 3277 /* XXX: use a better algorithm */
3272 3278 for(i = 0; i < 64; i++) {
3273 3279 a1 = (a1 << 1) | (a0 >> 63);
... ... @@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3286 3292 *plow = a0;
3287 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 3301 int sa, sb;
3294 3302 sa = ((int64_t)*phigh < 0);
... ... @@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3297 3305 sb = (b < 0);
3298 3306 if (sb)
3299 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 3313 *plow = - *plow;
  3314 + } else {
  3315 + if (*plow >= (1ULL << 63))
  3316 + return 1;
  3317 + }
3303 3318 if (sa)
3304 3319 *phigh = - *phigh;
  3320 + return 0;
3305 3321 }
3306 3322  
3307 3323 void helper_mulq_EAX_T0(void)
... ... @@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void)
3344 3360 }
3345 3361 r0 = EAX;
3346 3362 r1 = EDX;
3347   - div64(&r0, &r1, T0);
  3363 + if (div64(&r0, &r1, T0))
  3364 + raise_exception(EXCP00_DIVZ);
3348 3365 EAX = r0;
3349 3366 EDX = r1;
3350 3367 }
... ... @@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void)
3357 3374 }
3358 3375 r0 = EAX;
3359 3376 r1 = EDX;
3360   - idiv64(&r0, &r1, T0);
  3377 + if (idiv64(&r0, &r1, T0))
  3378 + raise_exception(EXCP00_DIVZ);
3361 3379 EAX = r0;
3362 3380 EDX = r1;
3363 3381 }
... ...
target-i386/op.c
... ... @@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
328 328 #endif
329 329  
330 330 /* division, flags are undefined */
331   -/* XXX: add exceptions for overflow */
332 331  
333 332 void OPPROTO op_divb_AL_T0(void)
334 333 {
... ... @@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
339 338 if (den == 0) {
340 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 345 r = (num % den) & 0xff;
344 346 EAX = (EAX & ~0xffff) | (r << 8) | q;
345 347 }
... ... @@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
353 355 if (den == 0) {
354 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 362 r = (num % den) & 0xff;
358 363 EAX = (EAX & ~0xffff) | (r << 8) | q;
359 364 }
... ... @@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
367 372 if (den == 0) {
368 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 379 r = (num % den) & 0xffff;
372 380 EAX = (EAX & ~0xffff) | q;
373 381 EDX = (EDX & ~0xffff) | r;
... ... @@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
382 390 if (den == 0) {
383 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 397 r = (num % den) & 0xffff;
387 398 EAX = (EAX & ~0xffff) | q;
388 399 EDX = (EDX & ~0xffff) | r;
... ...