[AD] sincos optimization

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


This patch adds the sincos optimization on i386 which was discussed several 
times on the list.  However, it only adds it for GCC-based platforms because 
GCC is the only compiler to feature a powerful enough inline assembly syntax 
so as to guarantee that it is really an optimization in all cases.

The GCC syntax is

__asm__ ("fsincos" : "=t" (cosinus), "=u" (sinus) : "0" (angle))

so the compiler knows that the cosinus is in st(0) and the sinus in st(1) 
after the calculation.


With Watcom C, the best solution is

double al_sincos(double x, double *c);

#pragma aux al_sincos =		\
   " fsincos "			\
   " fstp qword ptr [eax] "	\
				\
   parm [8087] [eax]		\
   value [8087];

so we need to unconditionally spill the cosinus to memory, which may loose in 
some cases.


With MSVC, I think the best solution is

double al_sincos(double x, double *c)
{
   _asm {
      fld x
      fsincos
      mov eax c
      fstp qword ptr [eax]
   }
}

so we need to unconditionally spill the cosinus too.


Applied to mainline.

-- 
Eric Botcazou
Index: todo.txt
===================================================================
RCS file: /cvsroot/alleg/allegro/todo.txt,v
retrieving revision 1.172
diff -u -p -r1.172 todo.txt
--- todo.txt	4 Dec 2003 06:36:54 -0000	1.172
+++ todo.txt	14 Dec 2003 18:18:39 -0000
@@ -13,7 +13,6 @@ General (Platform independent) todos:
 - make the library thread-safe
 - fix use of 32-bit 'long' on 64-bit platforms
 - add set_harware_volume()
-- add asm/C sincos() internal routine
 - don't use BITMAPs for zbuffers
 - make the 'save' method of plugins return FALSE on failure
 
Index: include/allegro/internal/alconfig.h
===================================================================
RCS file: /cvsroot/alleg/allegro/include/allegro/internal/alconfig.h,v
retrieving revision 1.14
diff -u -p -r1.14 alconfig.h
--- include/allegro/internal/alconfig.h	14 Jun 2003 09:48:06 -0000	1.14
+++ include/allegro/internal/alconfig.h	14 Dec 2003 18:18:41 -0000
@@ -105,6 +105,7 @@
 
    #ifdef __i386__
       #define ALLEGRO_I386
+      #define _AL_SINCOS(x, s, c)  __asm__ ("fsincos" : "=t" (c), "=u" (s) : "0" (x))
    #endif
 
    #ifndef AL_CONST
@@ -132,6 +133,10 @@
  * features and helper functions, which are conditionalised so they will
  * only be included if none of the above headers defined custom versions.
  */
+
+#ifndef _AL_SINCOS
+   #define _AL_SINCOS(x, s, c)  do { (c) = cos(x); (s) = sin(x); } while (0)
+#endif
 
 #ifndef INLINE
    #define INLINE
Index: src/math3d.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/math3d.c,v
retrieving revision 1.7
diff -u -p -r1.7 math3d.c
--- src/math3d.c	12 Sep 2002 16:23:57 -0000	1.7
+++ src/math3d.c	14 Dec 2003 18:18:44 -0000
@@ -22,9 +22,8 @@
 
 
 
-#define floatcos(x)     cos((x) * AL_PI / 128.0)
-#define floatsin(x)     sin((x) * AL_PI / 128.0)
-#define floattan(x)     tan((x) * AL_PI / 128.0)
+#define FLOATSINCOS(x, s, c)  _AL_SINCOS((x) * AL_PI / 128.0, s ,c)
+#define floattan(x)           tan((x) * AL_PI / 128.0)
 
 
 
@@ -147,10 +146,10 @@ void get_x_rotate_matrix(MATRIX *m, fixe
  */
 void get_x_rotate_matrix_f(MATRIX_f *m, float r)
 {
-   float c = floatcos(r);
-   float s = floatsin(r);
+   float c, s;
    ASSERT(m);
 
+   FLOATSINCOS(r, s, c);
    *m = identity_matrix_f;
 
    m->v[1][1] = c;
@@ -189,10 +188,10 @@ void get_y_rotate_matrix(MATRIX *m, fixe
  */
 void get_y_rotate_matrix_f(MATRIX_f *m, float r)
 {
-   float c = floatcos(r);
-   float s = floatsin(r);
+   float c, s;
    ASSERT(m);
 
+   FLOATSINCOS(r, s, c);
    *m = identity_matrix_f;
 
    m->v[0][0] = c;
@@ -231,10 +230,10 @@ void get_z_rotate_matrix(MATRIX *m, fixe
  */
 void get_z_rotate_matrix_f(MATRIX_f *m, float r)
 {
-   float c = floatcos(r);
-   float s = floatsin(r);
+   float c, s;
    ASSERT(m);
 
+   FLOATSINCOS(r, s, c);
    *m = identity_matrix_f;
 
    m->v[0][0] = c;
@@ -263,17 +262,17 @@ void get_z_rotate_matrix_f(MATRIX_f *m, 
 
 
 #define MAKE_ROTATION_f(x, y, z)                \
-   float sin_x = floatsin(x);                   \
-   float cos_x = floatcos(x);                   \
+   float sin_x, cos_x;				\
+   float sin_y, cos_y;				\
+   float sin_z, cos_z;				\
+   float sinx_siny, cosx_siny;			\
 						\
-   float sin_y = floatsin(y);                   \
-   float cos_y = floatcos(y);                   \
+   FLOATSINCOS(x, sin_x, cos_x);		\
+   FLOATSINCOS(y, sin_y, cos_y);		\
+   FLOATSINCOS(z, sin_z, cos_z);		\
 						\
-   float sin_z = floatsin(z);                   \
-   float cos_z = floatcos(z);                   \
-						\
-   float sinx_siny = sin_x * sin_y;             \
-   float cosx_siny = cos_x * sin_y;
+   sinx_siny = sin_x * sin_y;			\
+   cosx_siny = cos_x * sin_y;
 
 
 
@@ -446,11 +445,11 @@ void get_vector_rotation_matrix(MATRIX *
  */
 void get_vector_rotation_matrix_f(MATRIX_f *m, float x, float y, float z, float a)
 {
-   float c = floatcos(a);
-   float s = floatsin(a);
-   float cc = 1 - c;
+   float c, s, cc;
    ASSERT(m);
 
+   FLOATSINCOS(a, s, c);
+   cc = 1 - c;
    normalize_vector_f(&x, &y, &z);
 
    m->v[0][0] = (cc * x * x) + c;
Index: src/quat.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/quat.c,v
retrieving revision 1.7
diff -u -p -r1.7 quat.c
--- src/quat.c	18 Sep 2003 08:31:36 -0000	1.7
+++ src/quat.c	14 Dec 2003 18:18:44 -0000
@@ -22,8 +22,7 @@
 
 
 
-#define floatcos(x)   ((float)(cos((x) * AL_PI / 128.0)))
-#define floatsin(x)   ((float)(sin((x) * AL_PI / 128.0)))
+#define FLOATSINCOS(x, s, c)  _AL_SINCOS((x) * AL_PI / 128.0, s ,c)
 
 
 #define EPSILON (0.001)
@@ -95,8 +94,7 @@ void get_x_rotate_quat(QUAT *q, float r)
 {
    ASSERT(q);
 
-   q->w = floatcos(r / 2);
-   q->x = floatsin(r / 2);
+   FLOATSINCOS(r/2, q->x, q->w);
    q->y = 0;
    q->z = 0;
 }
@@ -112,9 +110,8 @@ void get_y_rotate_quat(QUAT *q, float r)
 {
    ASSERT(q);
 
-   q->w = floatcos(r / 2);
+   FLOATSINCOS(r/2, q->y, q->w);
    q->x = 0;
-   q->y = floatsin(r / 2);
    q->z = 0;
 }
 
@@ -129,10 +126,9 @@ void get_z_rotate_quat(QUAT *q, float r)
 {
    ASSERT(q);
 
-   q->w = floatcos(r / 2);
+   FLOATSINCOS(r/2, q->z, q->w);
    q->x = 0;
    q->y = 0;
-   q->z = floatsin(r / 2);
 }
 
 
@@ -154,12 +150,9 @@ void get_rotation_quat(QUAT *q, float x,
 
    ASSERT(q);
 
-   sx = floatsin(x / 2);
-   sy = floatsin(y / 2);
-   sz = floatsin(z / 2);
-   cx = floatcos(x / 2);
-   cy = floatcos(y / 2);
-   cz = floatcos(z / 2);
+   FLOATSINCOS(x/2, sx, cx);
+   FLOATSINCOS(y/2, sy, cy);
+   FLOATSINCOS(z/2, sz, cz);
 
    sysz = sy * sz;
    cycz = cy * cz;
@@ -196,8 +189,7 @@ void get_vector_rotation_quat(QUAT *q, f
    y /= l;
    z /= l;
 
-   q->w = floatcos(a / 2);
-   s    = floatsin(a / 2);
+   FLOATSINCOS(a/2, s, q->w);
    q->x = s * x;
    q->y = s * y;
    q->z = s * z;
Index: src/rotate.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/rotate.c,v
retrieving revision 1.17
diff -u -p -r1.17 rotate.c
--- src/rotate.c	14 Dec 2003 15:29:38 -0000	1.17
+++ src/rotate.c	14 Dec 2003 18:18:46 -0000
@@ -718,8 +718,7 @@ void _rotate_scale_flip_coordinates(fixe
    if (angle >= 0x800000)
       angle -= 0x1000000;
 
-   cos_angle = cos(angle * (AL_PI / (double)0x800000));
-   sin_angle = sin(angle * (AL_PI / (double)0x800000));
+   _AL_SINCOS(angle * (AL_PI / (double)0x800000), sin_angle, cos_angle);
 
    if (cos_angle >= 0)
       fix_cos = (int)(cos_angle * 0x10000 + 0.5);


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/