This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
v850
- From: dohzono at hf dot rim dot or dot jp
- To: bug-gcc at gnu dot org
- Date: Wed, 3 Apr 2002 18:17:12 +0900 (JST)
- Subject: 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;
}