Viewing file: msp_abi_div_funcs.c (4.06 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* { 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; }
|