(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.target/
aarch64/
aapcs64/
abitest-2.h
       1  /* This header file should be included for the purpose of function return
       2     value testing.  */
       3  
       4  #include "abitest-common.h"
       5  #include "validate_memory.h"
       6  
       7  void (*testfunc_ptr)(char* stack);
       8  unsigned long long saved_return_address;
       9  
      10  /* Helper macros to generate function name.  Example of the function name:
      11     func_return_val_1.  */
      12  #define FUNC_BASE_NAME func_return_val_
      13  #define FUNC_NAME_COMBINE(base,suffix) base ## suffix
      14  #define FUNC_NAME_1(base,suffix) FUNC_NAME_COMBINE(base,suffix)
      15  #define FUNC_NAME(suffix) FUNC_NAME_1(FUNC_BASE_NAME,suffix)
      16  #define TEST_FUNC_BASE_NAME testfunc_
      17  #define TEST_FUNC_NAME(suffix) FUNC_NAME_1(TEST_FUNC_BASE_NAME,suffix)
      18  
      19  #undef DUMP_STATUS
      20  #ifdef DUMP_ENABLED
      21  #define DUMP_STATUS(type,val) printf ("### Checking "#type" "#val"\n");
      22  #else
      23  #define DUMP_STATUS(type,val)
      24  #endif
      25  
      26  /* Generate code to do memcmp to check if the returned value is in the
      27     correct location and has the expected value.
      28     Note that for value that is returned in the caller-allocated memory
      29     block, we get the address from the saved x8 register.  x8 is saved
      30     just after the callee is returned; we assume that x8 has not been
      31     clobbered at then, although there is no requirement for the callee
      32     preserve the value stored in x8.  Luckily, all test cases here are
      33     simple enough that x8 doesn't normally get clobbered (although not
      34     guaranteed).  */
      35  #undef FUNC_VAL_CHECK
      36  #define FUNC_VAL_CHECK(id, type, val, offset, layout)			\
      37  void TEST_FUNC_NAME(id)(char* stack)					\
      38  {									\
      39    type __x = val;							\
      40    char* addr;								\
      41    DUMP_STATUS(type,val)							\
      42    if (offset != X8)							\
      43      addr = stack + offset;						\
      44    else									\
      45      addr = *(char **)(stack + X8);					\
      46    if (validate_memory (&__x, addr, sizeof (type), layout) != 0)		\
      47      abort();								\
      48  }
      49  
      50  /* Composite larger than 16 bytes is replaced by a pointer to a copy prepared
      51     by the caller, so here we extrat the pointer, deref it and compare the
      52     content with that of the original one.  */
      53  #define PTR(type, val, offset, ...) {					\
      54    type * ptr;								\
      55    DUMP_ARG(type,val)							\
      56    ptr = *(type **)(stack + offset);					\
      57    if (memcmp (ptr, &val, sizeof (type)) != 0) abort ();			\
      58  }
      59  
      60  #include TESTFILE
      61  
      62  MYFUNCTYPE myfunc () PCSATTR;
      63  
      64  /* Define the function to return VAL of type TYPE.  I and D in the
      65     parameter list are two dummy parameters to help improve the detection
      66     of bugs like a short vector being returned in X0 after copied from V0.  */
      67  #undef FUNC_VAL_CHECK
      68  #define FUNC_VAL_CHECK(id, type, var, offset, layout)			  \
      69  __attribute__ ((noipa)) type FUNC_NAME (id) (int i, double d, type t)	  \
      70    {									  \
      71      asm (""::"r" (i),"r" (d)); /* asm prevents function from getting      \
      72  				  optimized away.  Using i and d prevents \
      73  				  warnings about unused parameters.	  \
      74  			       */					  \
      75      /* We save and set up the LR register in a way that essentially	  \
      76         inserts myfunc () between the return of this function and the	  \
      77         continuing execution of its caller.  By doing this, myfunc ()	  \
      78         can save and check the exact content of the registers that are	  \
      79         used for the function return value.				  \
      80         The previous approach of sequentially calling myfunc right after	  \
      81         this function does not guarantee myfunc see the exact register	  \
      82         content, as compiler may emit code in between the two calls,	  \
      83         especially during the -O0 codegen.  */				  \
      84      asm volatile ("mov %0, x30" : "=r" (saved_return_address));		  \
      85      asm volatile ("mov x30, %0" : : "r" ((unsigned long long) myfunc));   \
      86      return t;								  \
      87    }
      88  #include TESTFILE
      89  
      90  
      91  /* Call the function to return value and call the checking function
      92     to validate.  See the comment above for the reason of having 0 and 0.0
      93     in the function argument list.  */
      94  #undef FUNC_VAL_CHECK
      95  #define FUNC_VAL_CHECK(id, type, var, offset, layout)			\
      96    {									\
      97      testfunc_ptr = TEST_FUNC_NAME(id);					\
      98      FUNC_NAME(id) (0, 0.0, var);					\
      99      /* The above function implicitly calls myfunc () on its return,	\
     100         and the execution resumes from here after myfunc () finishes.  */\
     101    }
     102  
     103  int main()
     104  {
     105    which_kind_of_test = TK_RETURN;
     106  
     107  #ifdef HAS_DATA_INIT_FUNC
     108    init_data ();
     109  #endif
     110  
     111  #include TESTFILE
     112  
     113    return 0;
     114  }