diff options
| -rw-r--r-- | arch/powerpc/math-emu/math_efp.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index 59835c625dc6..ecdf35d8cb00 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c | |||
| @@ -680,7 +680,8 @@ int speround_handler(struct pt_regs *regs) | |||
| 680 | { | 680 | { |
| 681 | union dw_union fgpr; | 681 | union dw_union fgpr; |
| 682 | int s_lo, s_hi; | 682 | int s_lo, s_hi; |
| 683 | unsigned long speinsn, type, fc; | 683 | int lo_inexact, hi_inexact; |
| 684 | unsigned long speinsn, type, fc, fptype; | ||
| 684 | 685 | ||
| 685 | if (get_user(speinsn, (unsigned int __user *) regs->nip)) | 686 | if (get_user(speinsn, (unsigned int __user *) regs->nip)) |
| 686 | return -EFAULT; | 687 | return -EFAULT; |
| @@ -693,8 +694,12 @@ int speround_handler(struct pt_regs *regs) | |||
| 693 | __FPU_FPSCR = mfspr(SPRN_SPEFSCR); | 694 | __FPU_FPSCR = mfspr(SPRN_SPEFSCR); |
| 694 | pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); | 695 | pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); |
| 695 | 696 | ||
| 697 | fptype = (speinsn >> 5) & 0x7; | ||
| 698 | |||
| 696 | /* No need to round if the result is exact */ | 699 | /* No need to round if the result is exact */ |
| 697 | if (!(__FPU_FPSCR & FP_EX_INEXACT)) | 700 | lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX); |
| 701 | hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH); | ||
| 702 | if (!(lo_inexact || (hi_inexact && fptype == VCT))) | ||
| 698 | return 0; | 703 | return 0; |
| 699 | 704 | ||
| 700 | fc = (speinsn >> 21) & 0x1f; | 705 | fc = (speinsn >> 21) & 0x1f; |
| @@ -705,7 +710,7 @@ int speround_handler(struct pt_regs *regs) | |||
| 705 | 710 | ||
| 706 | pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); | 711 | pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); |
| 707 | 712 | ||
| 708 | switch ((speinsn >> 5) & 0x7) { | 713 | switch (fptype) { |
| 709 | /* Since SPE instructions on E500 core can handle round to nearest | 714 | /* Since SPE instructions on E500 core can handle round to nearest |
| 710 | * and round toward zero with IEEE-754 complied, we just need | 715 | * and round toward zero with IEEE-754 complied, we just need |
| 711 | * to handle round toward +Inf and round toward -Inf by software. | 716 | * to handle round toward +Inf and round toward -Inf by software. |
| @@ -728,11 +733,15 @@ int speround_handler(struct pt_regs *regs) | |||
| 728 | 733 | ||
| 729 | case VCT: | 734 | case VCT: |
| 730 | if (FP_ROUNDMODE == FP_RND_PINF) { | 735 | if (FP_ROUNDMODE == FP_RND_PINF) { |
| 731 | if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ | 736 | if (lo_inexact && !s_lo) |
| 732 | if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ | 737 | fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ |
| 738 | if (hi_inexact && !s_hi) | ||
| 739 | fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ | ||
| 733 | } else { /* round to -Inf */ | 740 | } else { /* round to -Inf */ |
| 734 | if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ | 741 | if (lo_inexact && s_lo) |
| 735 | if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ | 742 | fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ |
| 743 | if (hi_inexact && s_hi) | ||
| 744 | fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ | ||
| 736 | } | 745 | } |
| 737 | break; | 746 | break; |
| 738 | 747 | ||
