#include <stdio.h>

typedef struct PingPong {
	int restart;										// style 1
	int N, i;
	const char * name;
	struct PingPong * partner;
	void * next;										// style 2
} PingPong;
#define PPCtor( name, N ) { 0, N, 0, name, NULL, NULL }

void comain( PingPong * pp ) __attribute__(( noinline ));
void comain( PingPong * pp ) {
#if 0
	if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
	pp->next = &&cycle;
	for ( ; pp->i < pp->N; pp->i += 1 ) {
#ifdef PRINT
		printf( "%s %d\n", pp->name, pp->i );
#endif // PRINT
		asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
		asm( "mov  %rdi,%rax" );
#ifndef OPT
#ifdef PRINT
		asm( "add  $16, %rsp" );
#endif // PRINT
		asm( "popq %rbp" );
#endif // ! OPT

#ifdef OPT
#ifdef PRINT
		asm( "popq %rbx" );
#endif // PRINT
#endif // OPT
		asm( "jmp  comain" );
	  cycle: ;
	} // for
#endif // 0

#if 1
	static void * states[] = {&&s0, &&s1};
	goto *states[pp->restart];
  s0: pp->restart = 1;
	for ( ; pp->i < pp->N; pp->i += 1 ) {
#ifdef PRINT
		printf( "%s %d\n", pp->name, pp->i );
#endif // PRINT
		asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
		asm( "mov  %rdi,%rax" );
#ifndef OPT
#ifdef PRINT
		asm( "add  $16, %rsp" );
#endif // PRINT
		asm( "popq %rbp" );
#endif // ! OPT

#ifdef OPT
#ifdef PRINT
		asm( "popq %rbx" );
#endif // PRINT
#endif // OPT
		asm( "jmp  comain" );
	  s1: ;
	} // for
#endif // 0
}

int main() {
	enum { N =
#ifdef PRINT
		   5
#else
		   1000000000
#endif // PRINT
	};
	PingPong ping = PPCtor( "ping", N ), pong = PPCtor( "pong", N );
	ping.partner = &pong;  pong.partner = &ping;
	comain( &ping );
}

// Local Variables: //
// tab-width: 4 //
// compile-command: "gcc-9 -g -DPRINT PingPong.c" //
// End: //
