#include <cstdio>

struct Obj {
	Obj() { printf( "Obj constructor\n" ); }
	~Obj() { printf( "Obj destructor\n" ); }
	int i = 4;
};

struct PingPong {
	const char * name;
	const int N;
	PingPong * partner = nullptr;
	int i = 0;
	void * next = nullptr;

	PingPong( const char * name, int N ) : name(name), N(N) {}

	void operator()() {
		if ( __builtin_expect(next != 0, 1) ) goto *next;
		next = &&cycle;
		for ( ; i < N; i += 1 ) {
			Obj obj;
			printf( "X %s %d\n", name, obj.i );
			obj.i = 7;
#ifdef PRINT
			printf( "%s %d\n", name, i );
#endif // PRINT
			asm( "mov  %0,%%rdi" : "=m" (partner) );
			asm( "mov  %rdi,%rax" );
#ifndef OPT
#ifdef PRINT
			asm( "add  $40, %rsp" );
#endif // PRINT
			asm( "popq %rbp" );
#endif // ! OPT

#ifdef OPT
#ifdef PRINT
			asm( "popq %rbx" );
#endif // PRINT
#endif // OPT
			asm( "jmp  _ZN8PingPongclEv" );
		  cycle: ;
			printf( "Y %s %d\n", name, obj.i );
		} // for
	}
};
int main() {
	enum { N =
#ifdef PRINT
		   5
#else
		   1000000000
#endif // PRINT
	};
	PingPong ping = { "ping", N }, pong = { "pong", N };
	ping.partner = &pong; pong.partner = &ping;
	ping();
}

// Local Variables: //
// tab-width: 4 //
// compile-command: "g++-8 -g -DPRINT PingPong.cc" //
// End: //
