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,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; |