Commit 45bbbb466cf4a6280076ea5a51f67ef5bedee345
1 parent
d592d303
added overflow exceptions in divisions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
47 additions
and
18 deletions
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; | ... | ... |