revert rounding change to only alter arm platform
[vuplus_xbmc] / xbmc / utils / MathUtils.h
1 #pragma once
2 /*
3  *      Copyright (C) 2005-2008 Team XBMC
4  *      http://www.xbmc.org
5  *
6  *  This Program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This Program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with XBMC; see the file COPYING.  If not, write to
18  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  *  http://www.gnu.org/copyleft/gpl.html
20  *
21  */
22
23 #include <stdint.h>
24 #include <cassert>
25 #include <climits>
26 #include <cmath>
27
28 namespace MathUtils
29 {
30   // GCC does something stupid with optimization on release builds if we try
31   // to assert in these functions
32   inline int round_int (double x)
33   {
34     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
35     assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
36     const float round_to_nearest = 0.5f;
37     int i;
38     
39 #ifndef _LINUX
40     __asm
41     {
42       fld x
43       fadd st, st (0)
44       fadd round_to_nearest
45       fistp i
46       sar i, 1
47     }
48 #else
49 #if defined(__powerpc__) || defined(__ppc__)
50     i = floor(x + round_to_nearest);
51 #elif defined(__arm__)
52     //BIG FIXME here (still has issues with rounding -0.5 to zero and not -1)
53     //the asm codes below do the following - trunc(x+0.5)
54     //this isn't correct for negativ x - values - for example 
55     //-1 gets rounded to zero because trunc(-1+0.5) == 0
56     //this is a dirty hack until someone fixes this propably in asm
57     //i've created a trac ticket for this #11767
58     //this hacks decrements the x by 1 if it is negativ
59     // so for -1 it would be trunc(-2+0.5) - which would be correct -1 then ...
60     x = x < 0 ? x-1 : x;
61
62     __asm__ __volatile__ (
63                           "vmov.F64 d1,%[rnd_val]             \n\t" // Copy round_to_nearest into a working register
64                           "vadd.F64 %P[value],%P[value],d1    \n\t" // Add round_to_nearest to value
65                           "vcvt.S32.F64 %[result],%P[value]   \n\t" // Truncate(round towards zero) and store the result
66                           : [result] "=w"(i), [value] "+w"(x)  // Outputs
67                           : [rnd_val] "Dv" (round_to_nearest)  // Inputs
68                           : "d1");                             // Clobbers
69 #else
70     __asm__ __volatile__ (
71                           "fadd %%st\n\t"
72                           "fadd %%st(1)\n\t"
73                           "fistpl %0\n\t"
74                           "sarl $1, %0\n"
75                           : "=m"(i) : "u"(round_to_nearest), "t"(x) : "st"
76                           );
77 #endif
78 #endif
79     return (i);
80   }
81
82   inline int truncate_int(double x)
83   {
84     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
85     assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
86
87 #if !defined(__powerpc__) && !defined(__ppc__) && !defined(__arm__)
88     const float round_towards_m_i = -0.5f;
89 #endif
90     int i;
91
92 #ifndef _LINUX
93     __asm
94     {
95       fld x
96       fadd st, st (0)
97       fabs
98       fadd round_towards_m_i
99       fistp i
100       sar i, 1
101     }
102 #else
103 #if defined(__powerpc__) || defined(__ppc__) || defined(__arm__)
104     return (int)x;
105 #else
106     __asm__ __volatile__ (
107                           "fadd %%st\n\t"
108                           "fabs\n\t"
109                           "fadd %%st(1)\n\t"
110                           "fistpl %0\n\t"
111                           "sarl $1, %0\n"
112                           : "=m"(i) : "u"(round_towards_m_i), "t"(x) : "st"
113                           );
114 #endif
115 #endif
116     if (x < 0)
117       i = -i;
118     return (i);
119   }
120
121   inline int64_t abs(int64_t a)
122   {
123     return (a < 0) ? -a : a;
124   }
125
126   inline void hack()
127   {
128     // stupid hack to keep compiler from dropping these
129     // functions as unused
130     MathUtils::round_int(0.0);
131     MathUtils::truncate_int(0.0);
132     MathUtils::abs(0);
133   }
134 } // namespace MathUtils
135