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