blob: c125ac60c5ad4eedf4b591469ea2a870d96cf6d4 [file] [log] [blame]
/* { dg-do run } */
/* { dg-options "-std=c99" } */
extern int printf (const char *, ...);
extern void abort (void) __attribute__((noreturn));
typedef unsigned long uint32;
typedef unsigned long long uint64;
extern uint32 __mspabi_divul (uint32, uint32);
extern uint32 __mspabi_divlu (uint32, uint32);
extern uint64 __mspabi_divull (uint64, uint64);
extern uint64 __mspabi_divllu (uint64, uint64);
uint32 func1 (uint32, uint32) __attribute__ ((noinline));
uint32 func2 (uint32, uint32) __attribute__ ((noinline));
uint32 func3 (uint32, uint32) __attribute__ ((noinline));
uint64 func4 (uint64, uint64) __attribute__ ((noinline));
uint64 func5 (uint64, uint64) __attribute__ ((noinline));
uint64 func6 (uint64, uint64) __attribute__ ((noinline));
#define DEBUG 0
int
main (void)
{
int fail = 0;
if (func1 (7UL, 3UL) != 2UL)
{
#if DEBUG
printf ("FAIL: func1: 7 / 3 returns %lu\n", func1 (7UL, 3UL));
#endif
++ fail;
}
if (func2 (7UL, 3UL) != 2UL)
{
#if DEBUG
printf ("FAIL: func2: 7 / 3 returns %lu\n", func2 (7UL, 3UL));
#endif
++ fail;
}
if (func3 (7UL, 3UL) != 2UL)
{
#if DEBUG
printf ("FAIL: func4: 7 / 3 returns %lu\n", func3 (7UL, 3UL));
#endif
++ fail;
}
if (func4 (7ULL, 3ULL) != 2ULL)
{
#if DEBUG
printf ("FAIL: func4: 7 / 3 returns %llu\n", func4 (7ULL, 3ULL));
#endif
++ fail;
}
if (func5 (7ULL, 3ULL) != 2ULL)
{
#if DEBUG
printf ("FAIL: func5: 7 / 3 returns %llu\n", func5 (7ULL, 3ULL));
#endif
++ fail;
}
if (func6 (7ULL, 3ULL) != 2ULL)
{
#if DEBUG
printf ("FAIL: func6: 7 / 3 returns %llu\n", func6 (7ULL, 3ULL));
#endif
++ fail;
}
if (fail)
abort ();
return 0;
}
/* At high levels of optimization gcc will probably fold func1 and func4 into
main, but this does not really matter. Those two functions are just there
for a sanity check at low levels of optimization. */
uint32 func1 (uint32 a, uint32 b) { return a / b; }
uint32 func2 (uint32 a, uint32 b) { return __mspabi_divul (a, b); }
uint32 func3 (uint32 a, uint32 b) { return __mspabi_divlu (a, b); }
uint64 func4 (uint64 a, uint64 b) { return a / b; }
uint64 func5 (uint64 a, uint64 b) { return __mspabi_divull (a, b); }
uint64
func6 (uint64 a, uint64 b)
{
uint64 ret;
/* This test function is special. The correctly spelt ABI function
__mspabi_divull takes its first argument in registers R8::R11 and its
second argument in registers R12::R15, but GCC knows that __mspabi_divllu
is not the correct spelling and so it will use the normal function
calling convention - first argument in R12::R15, second argument on the
stack.
The stub function for __mspabi_divllu in libgcc just does a BRAnch to
the real __mspabi_divull function - it does *not* rearrange the arguments
or pull anything off the stack. This is correct, because in real code
that calls __mspabi_divllu, compiled by *old* versions of gcc, the
arguments will already be in the special ABI mandated locations.
As a result, in order to test __mspabi_divllu here, we have to put the
arguments into the correct registers ourselves and call __mspabi_divllu
manually. This does lead to some very inefficient code generation, but
that is not our concern here. */
#ifdef __MSP430X_LARGE__
__asm ("mov %A1, r8\n\
mov %B1, r9\n\
mov %C1, r10\n\
mov %D1, r11\n\
mov %A2, r12\n\
mov %B2, r13\n\
mov %C2, r14\n\
mov %D2, r15\n\
calla #__mspabi_divllu\n\
mov r12, %A0\n\
mov r13, %B0\n\
mov r14, %C0\n\
mov r15, %D0\n"
: "=r" (ret) : "r" (a), "m" (b));
#else
__asm ("mov %A1, r8\n\
mov %B1, r9\n\
mov %C1, r10\n\
mov %D1, r11\n\
mov %A2, r12\n\
mov %B2, r13\n\
mov %C2, r14\n\
mov %D2, r15\n\
call #__mspabi_divllu\n\
mov r12, %A0\n\
mov r13, %B0\n\
mov r14, %C0\n\
mov r15, %D0\n"
: "=r" (ret) : "r" (a), "m" (b));
#endif
return ret;
}