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