This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

v850


Could someone please apply this to lib1funcs.asm?

__mulsi3:
	mov	r6,r10
	mov	r7,r12
	mulh	r12,r10
	mov	r6,r13
	shr	16,r12
	bnc	mul32_0
	mov	r6,r1
	shl	16,r1
	add	r1,r10
mul32_0:
	shr	16,r13
	bnc	mul32_1
	mov	r7,r1
	shl	16,r1
	add	r1,r10
mul32_1:
	mulh	r6,r12
	mulh	r7,r13
	shl	16,r12
	shl	16,r13
	add	r12,r10
	add	r13,r10
	jmp [r31]


/* emulate v85x mulh behavior */
unsigned long
mulh (signed short x, signed short y)
{
  int ix = (int) x;
  int iy = (int) y;
  return (unsigned long) (ix * iy);
}


/* current lib1funcs.asm:__mulsi3 */
#define SHIFT 12
#define MASK ((1 << SHIFT) - 1)
 
#define STEP(i, j)                             \
({                                             \
    short a_part = (a >> (i)) & MASK;          \
    short b_part = (b >> (j)) & MASK;          \
    int res = (int) mulh (a_part, b_part);     \
    res;                                       \
})

int
old__mulsi3 (unsigned a, unsigned b)
{
   return STEP (0, 0) +
       ((STEP (SHIFT, 0) + STEP (0, SHIFT)) << SHIFT) +
       ((STEP (0, 2 * SHIFT) + STEP (SHIFT, SHIFT) + STEP (2 * SHIFT, 0))
        << (2 * SHIFT));
}


/* unsigned 16x16 = 32 bit multiplication using mulh */
#define FIRST_STEP() ({ \
  short sx = (short) x; \
  short sy = (short) y; \
  unsigned z = mulh (sx, sy); \
  if (sx & 0x8000) \
    z += ((unsigned) sy) << 16; \
  if (sy & 0x8000) \
    z += ((unsigned) sx) << 16; \
  z; \
})
/*
 * 
 * mulh produces a sign-extend multiplication result. Assume
 * that sx < 0, 0 <= sy.
 * 
 * ((sign-extend) sx) * sy
 *   := (0xffff0000 + sx) * sy
 *   := sx * sy + 0xffff0000 * sy
 *   := sx * sy - 0x00010000 * sy
 *   := sx * sy - (sy << 16)
 *
 * so if you want unsigned multiplication result, just add (sy << 16)
 * when sx < 0 (and add (sx << 16) when sy < 0).
 *
 */

#define SECOND_STEP(i,j) ({ \
  short sx = i ? (x >> 16) : x; \
  short sy = j ? (y >> 16) : y; \
  unsigned z = mulh (sx, sy); \
  z; \
})

int
new__mulsi3 (unsigned x, unsigned y)
{
  return FIRST_STEP ()
    + ((SECOND_STEP (0, 1)
	+ SECOND_STEP (1, 0)) << 16);
}

#define elements_of(x) ((unsigned) (sizeof (x) / sizeof ((x)[0])))

void
test (unsigned xh, unsigned yh)
{
  struct {
    signed short x, y;
  } testsuit[] = {
    { 0x0000, 0x0000 },
    { 0x0000, 0x7fff },
    { 0x7fff, 0x7fff },
    { 0x7fff, 0x8000 },
    { 0x8000, 0x8000 },
    { 0x8000, 0xffff },
    { 0xffff, 0xffff },
    { 0x1234, 0x5678 },
  };
  unsigned i;
  for (i = 0; i < elements_of (testsuit); i++)
    {
      int x = testsuit[i].x | xh;
      int y = testsuit[i].y | yh;
      int z1 = old__mulsi3 (x, y);
      int z2 = new__mulsi3 (x, y);
      if (z1 != z2)
	{
	  printf ("%08x %08x %08x %08x\n"
		  , x, y, z1, z2);
	  exit (1);
	}
    }
}

int
main ()
{
  test (0x00000000, 0x00000000);
  test (0x00000000, 0xffff0000);
  test (0xffff0000, 0xffff0000);
  printf ("done\n");
  return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]