1  /* { dg-do compile { target x86_64-pc-linux-gnu } } */
       2  /* { dg-require-effective-target lp64 } */
       3  /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
       4  /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
       5  
       6  /* Adapted/reduced from linux kernel (GPL-2.0).  */
       7  
       8  typedef __SIZE_TYPE__ size_t;
       9  
      10  #define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)
      11  
      12  #define __stringify_1(x...)	#x
      13  #define __stringify(x...)	__stringify_1(x)
      14  #define __ASM_FORM(x, ...)		" " __stringify(x,##__VA_ARGS__) " "
      15  #define __ASM_FORM_RAW(x, ...)		    __stringify(x,##__VA_ARGS__)
      16  #define __ASM_SEL(a,b)		__ASM_FORM(b)
      17  #define __ASM_SEL_RAW(a,b)	__ASM_FORM_RAW(b)
      18  #define __ASM_REG(reg)         __ASM_SEL_RAW(e##reg, r##reg)
      19  #define _ASM_PTR	__ASM_SEL(.long, .quad)
      20  #define _ASM_ALIGN   __ASM_SEL(.balign 4, .balign 8)
      21  #define _ASM_SP		__ASM_REG(sp)
      22  
      23  
      24  register unsigned long current_stack_pointer asm(_ASM_SP);
      25  #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
      26  
      27  #define ANNOTATE_RETPOLINE_SAFE					\
      28  	"999:\n\t"						\
      29  	".pushsection .discard.retpoline_safe\n\t"		\
      30  	_ASM_PTR " 999b\n\t"					\
      31  	".popsection\n\t"
      32  
      33  /* Adapted from Linux arch/x86/include/asm/paravirt.h  */
      34  
      35  struct pv_cpu_ops {
      36    /* snip */
      37    void (*cpuid)(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
      38  		unsigned int *edx);
      39    /* snip */
      40  };
      41  
      42  struct paravirt_patch_template {
      43    struct pv_cpu_ops cpu;
      44    /* snip */
      45  };
      46  extern struct paravirt_patch_template pv_ops;
      47  
      48  #define PARAVIRT_PATCH(x)					\
      49  	(offsetof(struct paravirt_patch_template, x) / sizeof(void *))
      50  
      51  #define paravirt_type(op)				\
      52  	[paravirt_typenum] "i" (PARAVIRT_PATCH(op)),	\
      53  	[paravirt_opptr] "i" (&(pv_ops.op))
      54  #define paravirt_clobber(clobber)		\
      55  	[paravirt_clobber] "i" (clobber)
      56  
      57  #define CLBR_ANY  ((1 << 9) - 1)
      58  
      59  #define _paravirt_alt(insn_string, type, clobber)	\
      60  	"771:\n\t" insn_string "\n" "772:\n"		\
      61  	".pushsection .parainstructions,\"a\"\n"	\
      62  	_ASM_ALIGN "\n"					\
      63  	_ASM_PTR " 771b\n"				\
      64  	"  .byte " type "\n"				\
      65  	"  .byte 772b-771b\n"				\
      66  	"  .short " clobber "\n"			\
      67  	".popsection\n"
      68  
      69  #define paravirt_alt(insn_string)					\
      70  	_paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
      71  
      72  #define PARAVIRT_CALL					\
      73  	ANNOTATE_RETPOLINE_SAFE				\
      74  	"call *%c[paravirt_opptr];"
      75  
      76  #define PVOP_CALL_ARGS						\
      77  	unsigned long __edi = __edi, __esi = __esi,		\
      78  		__edx = __edx, __ecx = __ecx, __eax = __eax;
      79  
      80  #define PVOP_CALL_ARG1(x)		"D" ((unsigned long)(x))
      81  #define PVOP_CALL_ARG2(x)		"S" ((unsigned long)(x))
      82  #define PVOP_CALL_ARG3(x)		"d" ((unsigned long)(x))
      83  #define PVOP_CALL_ARG4(x)		"c" ((unsigned long)(x))
      84  
      85  #define PVOP_VCALL_CLOBBERS	"=D" (__edi),				\
      86  				"=S" (__esi), "=d" (__edx),		\
      87  				"=c" (__ecx)
      88  /* void functions are still allowed [re]ax for scratch */
      89  #define PVOP_VCALLEE_CLOBBERS	"=a" (__eax)
      90  
      91  #define VEXTRA_CLOBBERS	 , "rax", "r8", "r9", "r10", "r11"
      92  
      93  #define PVOP_TEST_NULL(op)	((void)pv_ops.op)
      94  
      95  #define ____PVOP_CALL(ret, op, clbr, call_clbr, extra_clbr, ...)	\
      96  	({								\
      97  		PVOP_CALL_ARGS;						\
      98  		PVOP_TEST_NULL(op);					\
      99  		asm volatile(paravirt_alt(PARAVIRT_CALL)		\
     100  			     : call_clbr, ASM_CALL_CONSTRAINT		\
     101  			     : paravirt_type(op),			\
     102  			       paravirt_clobber(clbr),			\
     103  			       ##__VA_ARGS__				\
     104  			     : "memory", "cc" extra_clbr);		\
     105  		ret;							\
     106  	})
     107  
     108  #define __PVOP_VCALL(op, ...)						\
     109  	(void)____PVOP_CALL(, op, CLBR_ANY, PVOP_VCALL_CLOBBERS,	\
     110  		       VEXTRA_CLOBBERS, ##__VA_ARGS__)
     111  
     112  #define PVOP_VCALL4(op, arg1, arg2, arg3, arg4)				\
     113  	__PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2),	\
     114  		     PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
     115  
     116  static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
     117  		  unsigned int *edx)
     118  {
     119    PVOP_VCALL4(cpu.cpuid, eax, ebx, ecx, edx);
     120  }
     121  
     122  extern void check_init_int(int v);
     123  
     124  void test(unsigned int op) {
     125    unsigned int eax, ebx, ecx, edx;
     126  
     127    eax = op;
     128    ecx = 0;
     129    cpuid(&eax, &ebx, &ecx, &edx);
     130  
     131    check_init_int(eax);
     132    check_init_int(ebx); /* { dg-bogus "use of uninitialized value 'ebx'" } */
     133    check_init_int(ecx);
     134    check_init_int(edx); /* { dg-bogus "use of uninitialized value 'edx'" } */
     135  }