/ externals / xbyak / test / jmp.cpp
jmp.cpp
   1  #include <stdio.h>
   2  #include <string.h>
   3  #include <string>
   4  #define XBYAK_NO_OP_NAMES
   5  #include <xbyak/xbyak.h>
   6  #include <cybozu/inttype.hpp>
   7  #include <cybozu/test.hpp>
   8  
   9  using namespace Xbyak;
  10  
  11  void putNop(Xbyak::CodeGenerator *gen, int n)
  12  {
  13  	for (int i = 0; i < n; i++) {
  14  		gen->nop();
  15  	}
  16  }
  17  
  18  void diff(const std::string& a, const std::string& b)
  19  {
  20  	if (a == b) return;
  21  	if (a.size() != b.size()) printf("size diff %d %d\n", (int)a.size(), (int)b.size());
  22  	for (size_t i = 0; i < (std::min)(a.size(), b.size()); i++) {
  23  		if (a[i] != b[i]) {
  24  			printf("diff %d(%04x) %02x %02x\n", (int)i, (int)i, (unsigned char)a[i], (unsigned char)b[i]);
  25  		}
  26  	}
  27  }
  28  
  29  void dump(const std::string& m)
  30  {
  31  	printf("size=%d\n     ", (int)m.size());
  32  	for (int i = 0; i < 16; i++) {
  33  		printf("%02x ", i);
  34  	}
  35  	printf("\n     ");
  36  	for (int i = 0; i < 16; i++) {
  37  		printf("---");
  38  	}
  39  	printf("\n");
  40  	for (size_t i = 0; i < m.size(); i++) {
  41  		if ((i % 16) == 0) printf("%04x ", (int)(i / 16));
  42  		printf("%02x ", (unsigned char)m[i]);
  43  		if ((i % 16) == 15) putchar('\n');
  44  	}
  45  	putchar('\n');
  46  }
  47  
  48  CYBOZU_TEST_AUTO(test1)
  49  {
  50  	struct TestJmp : public Xbyak::CodeGenerator {
  51  	/*
  52  	     4                                  X0:
  53  	     5 00000004 EBFE                    jmp short X0
  54  	     6
  55  	     7                                  X1:
  56  	     8 00000006 <res 00000001>          dummyX1 resb 1
  57  	     9 00000007 EBFD                    jmp short X1
  58  	    10
  59  	    11                                  X126:
  60  	    12 00000009 <res 0000007E>          dummyX126 resb 126
  61  	    13 00000087 EB80                    jmp short X126
  62  	    14
  63  	    15                                  X127:
  64  	    16 00000089 <res 0000007F>          dummyX127 resb 127
  65  	    17 00000108 E97CFFFFFF              jmp near X127
  66  	    18
  67  	    19 0000010D EB00                    jmp short Y0
  68  	    20                                  Y0:
  69  	    21
  70  	    22 0000010F EB01                    jmp short Y1
  71  	    23 00000111 <res 00000001>          dummyY1 resb 1
  72  	    24                                  Y1:
  73  	    25
  74  	    26 00000112 EB7F                    jmp short Y127
  75  	    27 00000114 <res 0000007F>          dummyY127 resb 127
  76  	    28                                  Y127:
  77  	    29
  78  	    30 00000193 E980000000              jmp near Y128
  79  	    31 00000198 <res 00000080>          dummyY128 resb 128
  80  	    32                                  Y128:
  81  	*/
  82  		TestJmp(int offset, bool isBack, bool isShort, bool useNewLabel)
  83  		{
  84  			if (useNewLabel) {
  85  				Label label;
  86  				if (isBack) {
  87  					L(label);
  88  					putNop(this, offset);
  89  					jmp(label);
  90  				} else {
  91  					if (isShort) {
  92  						jmp(label);
  93  					} else {
  94  						jmp(label, T_NEAR);
  95  					}
  96  					putNop(this, offset);
  97  					L(label);
  98  				}
  99  			} else {
 100  				if (isBack) {
 101  					L("@@");
 102  					putNop(this, offset);
 103  					jmp("@b");
 104  				} else {
 105  					if (isShort) {
 106  						jmp("@f");
 107  					} else {
 108  						jmp("@f", T_NEAR);
 109  					}
 110  					putNop(this, offset);
 111  					L("@@");
 112  				}
 113  			}
 114  		}
 115  	};
 116  	static const struct Tbl {
 117  		int offset;
 118  		bool isBack;
 119  		bool isShort;
 120  		uint8_t result[6];
 121  		int size;
 122  	} tbl[] = {
 123  		{ 0, true, true, { 0xeb, 0xfe }, 2 },
 124  		{ 1, true, true, { 0xeb, 0xfd }, 2 },
 125  		{ 126, true, true, { 0xeb, 0x80 }, 2 },
 126  		{ 127, true, false, {0xe9, 0x7c, 0xff, 0xff, 0xff }, 5 },
 127  		{ 0, false, true, { 0xeb, 0x00 }, 2 },
 128  		{ 1, false, true, { 0xeb, 0x01 }, 2 },
 129  		{ 127, false, true, { 0xeb, 0x7f }, 2 },
 130  		{ 128, false, false, { 0xe9, 0x80, 0x00, 0x00, 0x00 }, 5 },
 131  	};
 132  	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
 133  		const Tbl *p = &tbl[i];
 134  		for (int k = 0; k < 2; k++) {
 135  			TestJmp jmp(p->offset, p->isBack, p->isShort, k == 0);
 136  			const uint8_t *q = (const uint8_t*)jmp.getCode();
 137  			if (p->isBack) q += p->offset; /* skip nop */
 138  			for (int j = 0; j < p->size; j++) {
 139  				CYBOZU_TEST_EQUAL(q[j], p->result[j]);
 140  			}
 141  		}
 142  	}
 143  }
 144  
 145  CYBOZU_TEST_AUTO(testJmpCx)
 146  {
 147  	struct TestJmpCx : public CodeGenerator {
 148  		explicit TestJmpCx(void *p, bool useNewLabel)
 149  			: Xbyak::CodeGenerator(16, p)
 150  		{
 151  			if (useNewLabel) {
 152  				Label lp;
 153  			L(lp);
 154  #ifdef XBYAK64
 155  				/*
 156  					67 E3 FD ; jecxz lp
 157  					E3 FB    ; jrcxz lp
 158  				*/
 159  				jecxz(lp);
 160  				jrcxz(lp);
 161  #else
 162  				/*
 163  					E3FE   ; jecxz lp
 164  					67E3FB ; jcxz lp
 165  				*/
 166  				jecxz(lp);
 167  				jcxz(lp);
 168  #endif
 169  			} else {
 170  				inLocalLabel();
 171  			L(".lp");
 172  #ifdef XBYAK64
 173  				/*
 174  					67 E3 FD ; jecxz lp
 175  					E3 FB    ; jrcxz lp
 176  				*/
 177  				jecxz(".lp");
 178  				jrcxz(".lp");
 179  #else
 180  				/*
 181  					E3FE   ; jecxz lp
 182  					67E3FB ; jcxz lp
 183  				*/
 184  				jecxz(".lp");
 185  				jcxz(".lp");
 186  #endif
 187  				outLocalLabel();
 188  			}
 189  		}
 190  	};
 191  	const struct {
 192  		const char *p;
 193  		size_t len;
 194  	} tbl = {
 195  #ifdef XBYAK64
 196  		"\x67\xe3\xfd\xe3\xfb", 5
 197  #else
 198  		"\xe3\xfe\x67\xe3\xfb", 5
 199  #endif
 200  	};
 201  	for (int j = 0; j < 2; j++) {
 202  		char buf[16] = {};
 203  		TestJmpCx code(buf, j == 0);
 204  		CYBOZU_TEST_EQUAL(memcmp(buf, tbl.p, tbl.len), 0);
 205  	}
 206  }
 207  
 208  CYBOZU_TEST_AUTO(loop)
 209  {
 210  	const uint8_t ok[] = {
 211  		// lp:
 212  		0x31, 0xC0, // xor eax, eax
 213  		0xE2, 0xFC, // loop lp
 214  		0xE0, 0xFA, // loopne lp
 215  		0xE1, 0xF8, // loope lp
 216  	};
 217  	struct Code : CodeGenerator {
 218  		Code(bool useLabel)
 219  		{
 220  			if (useLabel) {
 221  				Xbyak::Label lp = L();
 222  				xor_(eax, eax);
 223  				loop(lp);
 224  				loopne(lp);
 225  				loope(lp);
 226  			} else {
 227  				L("@@");
 228  				xor_(eax, eax);
 229  				loop("@b");
 230  				loopne("@b");
 231  				loope("@b");
 232  			}
 233  		}
 234  	};
 235  	Code code1(false);
 236  	CYBOZU_TEST_EQUAL(code1.getSize(), sizeof(ok));
 237  	CYBOZU_TEST_EQUAL_ARRAY(code1.getCode(), ok, sizeof(ok));
 238  	Code code2(true);
 239  	CYBOZU_TEST_EQUAL(code2.getSize(), sizeof(ok));
 240  	CYBOZU_TEST_EQUAL_ARRAY(code2.getCode(), ok, sizeof(ok));
 241  }
 242  
 243  #ifdef _MSC_VER
 244  	#pragma warning(disable : 4310)
 245  #endif
 246  CYBOZU_TEST_AUTO(test2)
 247  {
 248  	struct TestJmp2 : public CodeGenerator {
 249  	/*
 250  	  1 00000000 90                      nop
 251  	  2 00000001 90                      nop
 252  	  3                                  f1:
 253  	  4 00000002 <res 0000007E>          dummyX1 resb 126
 254  	  6 00000080 EB80                     jmp f1
 255  	  7
 256  	  8                                  f2:
 257  	  9 00000082 <res 0000007F>          dummyX2 resb 127
 258  	 11 00000101 E97CFFFFFF               jmp f2
 259  	 12
 260  	 13
 261  	 14 00000106 EB7F                    jmp f3
 262  	 15 00000108 <res 0000007F>          dummyX3 resb 127
 263  	 17                                  f3:
 264  	 18
 265  	 19 00000187 E980000000              jmp f4
 266  	 20 0000018C <res 00000080>          dummyX4 resb 128
 267  	 22                                  f4:
 268  	*/
 269  		TestJmp2(void *p, bool useNewLabel)
 270  			: Xbyak::CodeGenerator(8192, p)
 271  		{
 272  			if (useNewLabel) {
 273  				inLocalLabel();
 274  				nop();
 275  				nop();
 276  			L(".f1");
 277  				putNop(this, 126);
 278  				jmp(".f1");
 279  			L(".f2");
 280  				putNop(this, 127);
 281  				jmp(".f2", T_NEAR);
 282  
 283  				jmp(".f3");
 284  				putNop(this, 127);
 285  			L(".f3");
 286  				jmp(".f4", T_NEAR);
 287  				putNop(this, 128);
 288  			L(".f4");
 289  				outLocalLabel();
 290  			} else {
 291  				nop();
 292  				nop();
 293  				Label f1, f2, f3, f4;
 294  			L(f1);
 295  				putNop(this, 126);
 296  				jmp(f1);
 297  			L(f2);
 298  				putNop(this, 127);
 299  				jmp(f2, T_NEAR);
 300  
 301  				jmp(f3);
 302  				putNop(this, 127);
 303  			L(f3);
 304  				jmp(f4, T_NEAR);
 305  				putNop(this, 128);
 306  			L(f4);
 307  			}
 308  		}
 309  	};
 310  
 311  	std::string ok;
 312  	ok.resize(0x18C + 128, (char)0x90);
 313  	ok[0x080] = (char)0xeb;
 314  	ok[0x081] = (char)0x80;
 315  
 316  	ok[0x101] = (char)0xe9;
 317  	ok[0x102] = (char)0x7c;
 318  	ok[0x103] = (char)0xff;
 319  	ok[0x104] = (char)0xff;
 320  	ok[0x105] = (char)0xff;
 321  
 322  	ok[0x106] = (char)0xeb;
 323  	ok[0x107] = (char)0x7f;
 324  
 325  	ok[0x187] = (char)0xe9;
 326  	ok[0x188] = (char)0x80;
 327  	ok[0x189] = (char)0x00;
 328  	ok[0x18a] = (char)0x00;
 329  	ok[0x18b] = (char)0x00;
 330  	for (int i = 0; i < 2; i++) {
 331  		for (int j = 0; j < 2; j++) {
 332  			TestJmp2 c(i == 0 ? 0 : Xbyak::AutoGrow, j == 0);
 333  			c.ready();
 334  			std::string m((const char*)c.getCode(), c.getSize());
 335  			CYBOZU_TEST_EQUAL(m, ok);
 336  		}
 337  	}
 338  }
 339  
 340  #ifdef XBYAK32
 341  int add5(int x) { return x + 5; }
 342  int add2(int x) { return x + 2; }
 343  
 344  CYBOZU_TEST_AUTO(test3)
 345  {
 346  	struct Grow : Xbyak::CodeGenerator {
 347  		Grow(int dummySize)
 348  			: Xbyak::CodeGenerator(128, Xbyak::AutoGrow)
 349  		{
 350  			mov(eax, 100);
 351  			push(eax);
 352  			call((void*)add5);
 353  			add(esp, 4);
 354  			push(eax);
 355  			call((void*)add2);
 356  			add(esp, 4);
 357  			ret();
 358  			for (int i = 0; i < dummySize; i++) {
 359  				db(0);
 360  			}
 361  		}
 362  	};
 363  	for (int dummySize = 0; dummySize < 40000; dummySize += 10000) {
 364  		printf("dummySize=%d\n", dummySize);
 365  		Grow g(dummySize);
 366  		g.ready();
 367  		int (*f)() = (int (*)())g.getCode();
 368  		int x = f();
 369  		const int ok = 107;
 370  		CYBOZU_TEST_EQUAL(x, ok);
 371  	}
 372  }
 373  #endif
 374  
 375  uint8_t bufL[4096 * 32];
 376  uint8_t bufS[4096 * 2];
 377  
 378  struct MyAllocator : Xbyak::Allocator {
 379  	uint8_t *alloc(size_t size)
 380  	{
 381  		if (size < sizeof(bufS)) {
 382  			printf("test use bufS(%d)\n", (int)size);
 383  			return bufS;
 384  		}
 385  		if (size < sizeof(bufL)) {
 386  			printf("test use bufL(%d)\n", (int)size);
 387  			return bufL;
 388  		}
 389  		fprintf(stderr, "no memory %d\n", (int)size);
 390  		exit(1);
 391  	}
 392  	void free(uint8_t *)
 393  	{
 394  	}
 395  } myAlloc;
 396  
 397  CYBOZU_TEST_AUTO(test4)
 398  {
 399  	struct Test4 : Xbyak::CodeGenerator {
 400  		Test4(int size, void *mode, bool useNewLabel)
 401  			: CodeGenerator(size, mode)
 402  		{
 403  			if (useNewLabel) {
 404  				Label x;
 405  				jmp(x);
 406  				putNop(this, 10);
 407  			L(x);
 408  				ret();
 409  			} else {
 410  				inLocalLabel();
 411  				jmp(".x");
 412  				putNop(this, 10);
 413  			L(".x");
 414  				ret();
 415  				outLocalLabel();
 416  			}
 417  		}
 418  	};
 419  	for (int i = 0; i < 2; i++) {
 420  		const bool useNewLabel = i == 0;
 421  		std::string fm, gm;
 422  		Test4 fc(1024, 0, useNewLabel);
 423  		Test4 gc(5, Xbyak::AutoGrow, !useNewLabel);
 424  		gc.ready();
 425  		fm.assign((const char*)fc.getCode(), fc.getSize());
 426  		gm.assign((const char*)gc.getCode(), gc.getSize());
 427  		CYBOZU_TEST_EQUAL(fm, gm);
 428  	}
 429  }
 430  
 431  #ifndef __APPLE__
 432  CYBOZU_TEST_AUTO(test5)
 433  {
 434  	struct Test5 : Xbyak::CodeGenerator {
 435  		explicit Test5(int size, int count, void *mode)
 436  			: CodeGenerator(size, mode, &myAlloc)
 437  		{
 438  			using namespace Xbyak;
 439  			inLocalLabel();
 440  			mov(ecx, count);
 441  			xor_(eax, eax);
 442  		L(".lp");
 443  			for (int i = 0; i < count; i++) {
 444  				L(Label::toStr(i));
 445  				add(eax, 1);
 446  				int to = 0;
 447  				if (i < count / 2) {
 448  					to = count - 1 - i;
 449  				} else {
 450  					to = count  - i;
 451  				}
 452  				if (i == count / 2) {
 453  					jmp(".exit", T_NEAR);
 454  				} else {
 455  					jmp(Label::toStr(to), T_NEAR);
 456  				}
 457  			}
 458  		L(".exit");
 459  			sub(ecx, 1);
 460  			jnz(".lp", T_NEAR);
 461  			ret();
 462  			outLocalLabel();
 463  		}
 464  	};
 465  	std::string fm, gm;
 466  	const int count = 50;
 467  	int ret;
 468  	Test5 fc(1024 * 64, count, 0);
 469  	ret = ((int (*)())fc.getCode())();
 470  	CYBOZU_TEST_EQUAL(ret, count * count);
 471  	fm.assign((const char*)fc.getCode(), fc.getSize());
 472  	Test5 gc(10, count, Xbyak::AutoGrow);
 473  	gc.ready();
 474  	ret = ((int (*)())gc.getCode())();
 475  	CYBOZU_TEST_EQUAL(ret, count * count);
 476  	gm.assign((const char*)gc.getCode(), gc.getSize());
 477  	CYBOZU_TEST_EQUAL(fm, gm);
 478  }
 479  #endif
 480  
 481  size_t getValue(const uint8_t* p)
 482  {
 483  	size_t v = 0;
 484  	for (size_t i = 0; i < sizeof(size_t); i++) {
 485  		v |= size_t(p[i]) << (i * 8);
 486  	}
 487  	return v;
 488  }
 489  
 490  void checkAddr(const uint8_t *p, size_t offset, size_t expect)
 491  {
 492  	size_t v = getValue(p + offset);
 493  	CYBOZU_TEST_EQUAL(v, size_t(p) + expect);
 494  }
 495  
 496  CYBOZU_TEST_AUTO(MovLabel)
 497  {
 498  	struct MovLabelCode : Xbyak::CodeGenerator {
 499  		MovLabelCode(bool grow, bool useNewLabel)
 500  			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
 501  		{
 502  #ifdef XBYAK64
 503  			const Reg64& a = rax;
 504  #else
 505  			const Reg32& a = eax;
 506  #endif
 507  			if (useNewLabel) {
 508  				nop(); // 0x90
 509  				Label lp1, lp2;
 510  			L(lp1);
 511  				nop();
 512  				mov(a, lp1); // 0xb8 + <4byte> / 0x48bb + <8byte>
 513  				nop();
 514  				mov(a, lp2); // 0xb8
 515  				// force realloc if AutoGrow
 516  				putNop(this, 256);
 517  				nop();
 518  			L(lp2);
 519  			} else {
 520  				inLocalLabel();
 521  				nop(); // 0x90
 522  			L(".lp1");
 523  				nop();
 524  				mov(a, ".lp1"); // 0xb8 + <4byte> / 0x48bb + <8byte>
 525  				nop();
 526  				mov(a, ".lp2"); // 0xb8
 527  				// force realloc if AutoGrow
 528  				putNop(this, 256);
 529  				nop();
 530  			L(".lp2");
 531  				outLocalLabel();
 532  			}
 533  		}
 534  	};
 535  
 536  	const struct {
 537  		int pos;
 538  		uint8_t ok;
 539  	} tbl[] = {
 540  #ifdef XBYAK32
 541  		{ 0x00, 0x90 },
 542  		// lp1:0x001
 543  		{ 0x001, 0x90 },
 544  		{ 0x002, 0xb8 },
 545  		// 0x003
 546  		{ 0x007, 0x90 },
 547  		{ 0x008, 0xb8 },
 548  		// 0x009
 549  		{ 0x10d, 0x90 },
 550  		// lp2:0x10e
 551  #else
 552  		{ 0x000, 0x90 },
 553  		// lp1:0x001
 554  		{ 0x001, 0x90 },
 555  		{ 0x002, 0x48 },
 556  		{ 0x003, 0xb8 },
 557  		// 0x004
 558  		{ 0x00c, 0x90 },
 559  		{ 0x00d, 0x48 },
 560  		{ 0x00e, 0xb8 },
 561  		// 0x00f
 562  		{ 0x117, 0x90 },
 563  		// lp2:0x118
 564  #endif
 565  	};
 566  	for (int j = 0; j < 2; j++) {
 567  		const bool grow = j == 0;
 568  		for (int k = 0; k < 2; k++) {
 569  			const bool useNewLabel = k == 0;
 570  			MovLabelCode code(grow, useNewLabel);
 571  			if (grow) code.ready();
 572  			const uint8_t* const p = code.getCode();
 573  			for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
 574  				int pos = tbl[i].pos;
 575  				uint8_t x = p[pos];
 576  				uint8_t ok = tbl[i].ok;
 577  				CYBOZU_TEST_EQUAL(x, ok);
 578  			}
 579  #ifdef XBYAK32
 580  			checkAddr(p, 0x03, 0x001);
 581  			checkAddr(p, 0x09, 0x10e);
 582  #else
 583  			checkAddr(p, 0x04, 0x001);
 584  			checkAddr(p, 0x0f, 0x118);
 585  #endif
 586  		}
 587  	}
 588  }
 589  
 590  CYBOZU_TEST_AUTO(testMovLabel2)
 591  {
 592  	struct MovLabel2Code : Xbyak::CodeGenerator {
 593  		MovLabel2Code()
 594  		{
 595  #ifdef XBYAK64
 596  			const Reg64& a = rax;
 597  			const Reg64& c = rcx;
 598  #else
 599  			const Reg32& a = eax;
 600  			const Reg32& c = ecx;
 601  #endif
 602  			xor_(a, a);
 603  			xor_(c, c);
 604  			jmp("in");
 605  			ud2();
 606  		L("@@"); // L1
 607  			add(a, 2);
 608  			mov(c, "@f");
 609  			jmp(c); // goto L2
 610  			ud2();
 611  		L("in");
 612  			mov(c, "@b");
 613  			add(a, 1);
 614  			jmp(c); // goto L1
 615  			ud2();
 616  		L("@@"); // L2
 617  			add(a, 4);
 618  			ret();
 619  		}
 620  	};
 621  	MovLabel2Code code;
 622  	int ret = code.getCode<int (*)()>()();
 623  	CYBOZU_TEST_EQUAL(ret, 7);
 624  }
 625  
 626  CYBOZU_TEST_AUTO(testF_B)
 627  {
 628  	struct Code : Xbyak::CodeGenerator {
 629  		Code(int type)
 630  		{
 631  			inLocalLabel();
 632  			xor_(eax, eax);
 633  			switch (type) {
 634  			case 0:
 635  			L("@@");
 636  				inc(eax);
 637  				cmp(eax, 1);
 638  				je("@b");
 639  				break;
 640  			case 1:
 641  				test(eax, eax);
 642  				jz("@f");
 643  				ud2();
 644  			L("@@");
 645  				break;
 646  			case 2:
 647  			L("@@");
 648  				inc(eax);
 649  				cmp(eax, 1); // 1, 2
 650  				je("@b");
 651  				cmp(eax, 2); // 2, 3
 652  				je("@b");
 653  				break;
 654  			case 3:
 655  			L("@@");
 656  				inc(eax);
 657  				cmp(eax, 1); // 1, 2
 658  				je("@b");
 659  				cmp(eax, 2); // 2, 3
 660  				je("@b");
 661  				jmp("@f");
 662  				ud2();
 663  			L("@@");
 664  				break;
 665  			case 4:
 666  			L("@@");
 667  				inc(eax);
 668  				cmp(eax, 1); // 1, 2
 669  				je("@b");
 670  				cmp(eax, 2); // 2, 3
 671  				je("@b");
 672  				jmp("@f");
 673  				ud2();
 674  			L("@@");
 675  				inc(eax); // 4, 5
 676  				cmp(eax, 4);
 677  				je("@b");
 678  				break;
 679  			case 5:
 680  			L("@@");
 681  			L("@@");
 682  				inc(eax);
 683  				cmp(eax, 1);
 684  				je("@b");
 685  				break;
 686  			case 6:
 687  			L("@@");
 688  			L("@@");
 689  			L("@@");
 690  				inc(eax);
 691  				cmp(eax, 1);
 692  				je("@b");
 693  				break;
 694  			case 7:
 695  				jmp("@f");
 696  			L("@@");
 697  				inc(eax); // 1, 2
 698  				cmp(eax, 1);
 699  				je("@b");
 700  				cmp(eax, 2);
 701  				jne("@f"); // not jmp
 702  				inc(eax); // 3
 703  			L("@@");
 704  				inc(eax); // 4, 5, 6
 705  				cmp(eax, 4);
 706  				je("@b");
 707  				cmp(eax, 5);
 708  				je("@b");
 709  				jmp("@f");
 710  				jmp("@f");
 711  				jmp("@b");
 712  			L("@@");
 713  				break;
 714  			}
 715  			ret();
 716  			outLocalLabel();
 717  		}
 718  	};
 719  	const int expectedTbl[] = {
 720  		2, 0, 3, 3, 5, 2, 2, 6
 721  	};
 722  	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(expectedTbl); i++) {
 723  		Code code((int)i);
 724  		int ret = code.getCode<int (*)()>()();
 725  		CYBOZU_TEST_EQUAL(ret, expectedTbl[i]);
 726  	}
 727  }
 728  
 729  CYBOZU_TEST_AUTO(test6)
 730  {
 731  	struct TestLocal : public Xbyak::CodeGenerator {
 732  		TestLocal(bool grow)
 733  			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
 734  		{
 735  			xor_(eax, eax);
 736  			inLocalLabel();
 737  			jmp("start0", T_NEAR);
 738  			L(".back");
 739  			inc(eax); // 8
 740  			jmp(".next", T_NEAR);
 741  			L("start2");
 742  			inc(eax); // 7
 743  			jmp(".back", T_NEAR);
 744  				inLocalLabel();
 745  				L(".back");
 746  				inc(eax); // 5
 747  				putNop(this, 128);
 748  				jmp(".next", T_NEAR);
 749  				L("start1");
 750  				inc(eax); // 4
 751  				jmp(".back", T_NEAR);
 752  					inLocalLabel();
 753  					L(".back");
 754  					inc(eax); // 2
 755  					jmp(".next", T_NEAR);
 756  					L("start0");
 757  					inc(eax); // 1
 758  					jmp(".back", T_NEAR);
 759  					L(".next");
 760  					inc(eax); // 3
 761  					jmp("start1", T_NEAR);
 762  					outLocalLabel();
 763  				L(".next");
 764  				inc(eax); // 6
 765  				jmp("start2", T_NEAR);
 766  				outLocalLabel();
 767  			L(".next");
 768  			inc(eax); // 9
 769  			jmp("start3", T_NEAR);
 770  				inLocalLabel();
 771  				L(".back");
 772  				inc(eax); // 14
 773  				jmp("exit", T_NEAR);
 774  			L("start4");
 775  				inc(eax); // 13
 776  				jmp(".back", T_NEAR);
 777  				outLocalLabel();
 778  			L("start3");
 779  				inc(eax); // 10
 780  				inLocalLabel();
 781  				jmp(".next", T_NEAR);
 782  				L(".back");
 783  				inc(eax); // 12
 784  				jmp("start4", T_NEAR);
 785  				L(".next");
 786  				inc(eax); // 11
 787  				jmp(".back", T_NEAR);
 788  				outLocalLabel();
 789  			outLocalLabel();
 790  			L("exit");
 791  			inc(eax); // 15
 792  			ret();
 793  		}
 794  	};
 795  
 796  	for (int i = 0; i < 2; i++) {
 797  		const bool grow = i == 1;
 798  		printf("test6 grow=%d\n", i);
 799  		TestLocal code(grow);
 800  		if (grow) code.ready();
 801  		int (*f)() = code.getCode<int (*)()>();
 802  		int a = f();
 803  		CYBOZU_TEST_EQUAL(a, 15);
 804  	}
 805  }
 806  
 807  CYBOZU_TEST_AUTO(test_jcc)
 808  {
 809  	struct A : Xbyak::CodeGenerator {
 810  		A()
 811  		{
 812  			add(eax, 5);
 813  			ret();
 814  		}
 815  	};
 816  	struct B : Xbyak::CodeGenerator {
 817  		B(bool grow, const void *p) : Xbyak::CodeGenerator(grow ? 0 : 4096, grow ? Xbyak::AutoGrow : 0)
 818  		{
 819  			mov(eax, 1);
 820  			add(eax, 2);
 821  			jnz(p);
 822  		}
 823  	};
 824  	A a;
 825  	const void *p = a.getCode<const void*>();
 826  	for (int i = 0; i < 2; i++) {
 827  		bool grow = i == 1;
 828  		B b(grow, p);
 829  		if (grow) {
 830  			b.ready();
 831  		}
 832  		int (*f)() = b.getCode<int (*)()>();
 833  		CYBOZU_TEST_EQUAL(f(), 8);
 834  	}
 835  }
 836  
 837  CYBOZU_TEST_AUTO(testNewLabel)
 838  {
 839  	struct Code : Xbyak::CodeGenerator {
 840  		Code(bool grow)
 841  			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
 842  		{
 843  			xor_(eax, eax);
 844  			{
 845  				Label label1;
 846  				Label label2;
 847  				Label label3;
 848  				Label label4;
 849  				Label exit;
 850  				jmp(label1, T_NEAR);
 851  			L(label2);
 852  				inc(eax); // 2
 853  				jmp(label3, T_NEAR);
 854  			L(label4);
 855  				inc(eax); // 4
 856  				jmp(exit, T_NEAR);
 857  				putNop(this, 128);
 858  			L(label3);
 859  				inc(eax); // 3
 860  				jmp(label4, T_NEAR);
 861  			L(label1);
 862  				inc(eax); // 1
 863  				jmp(label2, T_NEAR);
 864  			L(exit);
 865  			}
 866  			{
 867  				Label label1;
 868  				Label label2;
 869  				Label label3;
 870  				Label label4;
 871  				Label exit;
 872  				jmp(label1);
 873  			L(label2);
 874  				inc(eax); // 6
 875  				jmp(label3);
 876  			L(label4);
 877  				inc(eax); // 8
 878  				jmp(exit);
 879  			L(label3);
 880  				inc(eax); // 7
 881  				jmp(label4);
 882  			L(label1);
 883  				inc(eax); // 5
 884  				jmp(label2);
 885  			L(exit);
 886  			}
 887  			Label callLabel;
 888  			{	// eax == 8
 889  				Label label1;
 890  				Label label2;
 891  			L(label1);
 892  				inc(eax); // 9, 10, 11, 13
 893  				cmp(eax, 9);
 894  				je(label1);
 895  				// 10, 11, 13
 896  				inc(eax); // 11, 12, 13
 897  				cmp(eax, 11);
 898  				je(label1);
 899  				// 12, 13
 900  				cmp(eax, 12);
 901  				je(label2);
 902  				inc(eax); // 14
 903  				cmp(eax, 14);
 904  				je(label2);
 905  				ud2();
 906  			L(label2); // 14
 907  				inc(eax); // 13, 15
 908  				cmp(eax, 13);
 909  				je(label1);
 910  			}
 911  			call(callLabel);
 912  			ret();
 913  		L(callLabel);
 914  			inc(eax); // 16
 915  			ret();
 916  		}
 917  	};
 918  	for (int i = 0; i < 2; i++) {
 919  		const bool grow = i == 1;
 920  		printf("testNewLabel grow=%d\n", grow);
 921  		Code code(grow);
 922  		if (grow) code.ready();
 923  		int (*f)() = code.getCode<int (*)()>();
 924  		int r = f();
 925  		CYBOZU_TEST_EQUAL(r, 16);
 926  	}
 927  }
 928  
 929  CYBOZU_TEST_AUTO(returnLabel)
 930  {
 931  	struct Code : Xbyak::CodeGenerator {
 932  		Code()
 933  		{
 934  			xor_(eax, eax);
 935  		Label L1 = L();
 936  			test(eax, eax);
 937  			Label exit;
 938  			jnz(exit);
 939  			inc(eax); // 1
 940  			Label L2;
 941  			call(L2);
 942  			jmp(L1);
 943  		L(L2);
 944  			inc(eax); // 2
 945  			ret();
 946  		L(exit);
 947  			inc(eax); // 3
 948  			ret();
 949  		}
 950  	};
 951  	Code code;
 952  	int (*f)() = code.getCode<int (*)()>();
 953  	int r = f();
 954  	CYBOZU_TEST_EQUAL(r, 3);
 955  }
 956  
 957  CYBOZU_TEST_AUTO(testAssign)
 958  {
 959  	struct Code : Xbyak::CodeGenerator {
 960  		Code(bool grow)
 961  			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
 962  		{
 963  			xor_(eax, eax);
 964  			Label dst, src;
 965  		L(src);
 966  			inc(eax);
 967  			cmp(eax, 1);
 968  			je(dst);
 969  			inc(eax); // 2, 3, 5
 970  			cmp(eax, 5);
 971  			putNop(this, 128);
 972  			jne(dst, T_NEAR);
 973  			ret();
 974  		assignL(dst, src);
 975  			// test of copy  label
 976  			{
 977  				Label sss(dst);
 978  				{
 979  					Label ttt;
 980  					ttt = src;
 981  				}
 982  			}
 983  		}
 984  	};
 985  	for (int i = 0; i < 2; i++) {
 986  		const bool grow = i == 0;
 987  		printf("testAssign grow=%d\n", grow);
 988  		Code code(grow);
 989  		if (grow) code.ready();
 990  		int (*f)() = code.getCode<int (*)()>();
 991  		int ret = f();
 992  		CYBOZU_TEST_EQUAL(ret, 5);
 993      }
 994  }
 995  
 996  CYBOZU_TEST_AUTO(doubleDefine)
 997  {
 998  	struct Code : Xbyak::CodeGenerator {
 999  		Code()
1000  		{
1001  			{
1002  				Label label;
1003  			L(label);
1004  				// forbitten double L()
1005  				CYBOZU_TEST_EXCEPTION(L(label), Xbyak::Error);
1006  			}
1007  			{
1008  				Label label;
1009  				jmp(label);
1010  				CYBOZU_TEST_ASSERT(hasUndefinedLabel());
1011  			}
1012  			{
1013  				Label label1, label2;
1014  			L(label1);
1015  				jmp(label2);
1016  				assignL(label2, label1);
1017  				// forbitten double assignL
1018  				CYBOZU_TEST_EXCEPTION(assignL(label2, label1), Xbyak::Error);
1019  			}
1020  			{
1021  				Label label1, label2;
1022  			L(label1);
1023  				jmp(label2);
1024  				// forbitten assignment to label1 set by L()
1025  				CYBOZU_TEST_EXCEPTION(assignL(label1, label2), Xbyak::Error);
1026  			}
1027  		}
1028  	} code;
1029  }
1030  
1031  struct GetAddressCode1 : Xbyak::CodeGenerator {
1032  	void test()
1033  	{
1034  		Xbyak::Label L1, L2, L3;
1035  		nop();
1036  	L(L1);
1037  		const uint8_t *p1 = getCurr();
1038  		CYBOZU_TEST_EQUAL_POINTER(L1.getAddress(), p1);
1039  
1040  		nop();
1041  		jmp(L2);
1042  		nop();
1043  		jmp(L3);
1044  	L(L2);
1045  		CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), getCurr());
1046  		// L3 is not defined
1047  		CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), 0);
1048  
1049  		// L3 is set by L1
1050  		assignL(L3, L1);
1051  		CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), p1);
1052  	}
1053  };
1054  
1055  struct CodeLabelTable : Xbyak::CodeGenerator {
1056  	enum { ret0 = 3 };
1057  	enum { ret1 = 5 };
1058  	enum { ret2 = 8 };
1059  	CodeLabelTable()
1060  	{
1061  		using namespace Xbyak;
1062  #ifdef XBYAK64_WIN
1063  		const Reg64& p0 = rcx;
1064  		const Reg64& a = rax;
1065  #elif defined (XBYAK64_GCC)
1066  		const Reg64& p0 = rdi;
1067  		const Reg64& a = rax;
1068  #else
1069  		const Reg32& p0 = edx;
1070  		const Reg32& a = eax;
1071  		mov(edx, ptr [esp + 4]);
1072  #endif
1073  		Label labelTbl, L0, L1, L2;
1074  		mov(a, labelTbl);
1075  		jmp(ptr [a + p0 * sizeof(void*)]);
1076  	L(labelTbl);
1077  		putL(L0);
1078  		putL(L1);
1079  		putL(L2);
1080  	L(L0);
1081  		mov(a, ret0);
1082  		ret();
1083  	L(L1);
1084  		mov(a, ret1);
1085  		ret();
1086  	L(L2);
1087  		mov(a, ret2);
1088  		ret();
1089  	}
1090  };
1091  
1092  CYBOZU_TEST_AUTO(LabelTable)
1093  {
1094  	CodeLabelTable c;
1095  	int (*f)(int) = c.getCode<int (*)(int)>();
1096  	CYBOZU_TEST_EQUAL(f(0), c.ret0);
1097  	CYBOZU_TEST_EQUAL(f(1), c.ret1);
1098  	CYBOZU_TEST_EQUAL(f(2), c.ret2);
1099  }
1100  
1101  CYBOZU_TEST_AUTO(getAddress1)
1102  {
1103  	GetAddressCode1 c;
1104  	c.test();
1105  }
1106  
1107  struct GetAddressCode2 : Xbyak::CodeGenerator {
1108  	Xbyak::Label L1, L2, L3;
1109  	size_t a1;
1110  	size_t a3;
1111  	explicit GetAddressCode2(int size)
1112  		: Xbyak::CodeGenerator(size, size == 4096 ? 0 : Xbyak::AutoGrow)
1113  		, a1(0)
1114  		, a3(0)
1115  	{
1116  		bool autoGrow = size != 4096;
1117  		nop();
1118  	L(L1);
1119  		if (autoGrow) {
1120  			CYBOZU_TEST_EQUAL_POINTER(L1.getAddress(), 0);
1121  		}
1122  		a1 = getSize();
1123  		nop();
1124  		jmp(L2);
1125  		if (autoGrow) {
1126  			CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), 0);
1127  		}
1128  	L(L3);
1129  		a3 = getSize();
1130  		if (autoGrow) {
1131  			CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), 0);
1132  		}
1133  		nop();
1134  		assignL(L2, L1);
1135  		if (autoGrow) {
1136  			CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), 0);
1137  		}
1138  	}
1139  };
1140  
1141  CYBOZU_TEST_AUTO(getAddress2)
1142  {
1143  	const int sizeTbl[] = {
1144  		2, 128, // grow
1145  		4096 // not grow
1146  	};
1147  	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(sizeTbl); i++) {
1148  		int size = sizeTbl[i];
1149  		GetAddressCode2 c(size);
1150  		c.ready();
1151  		const uint8_t *p = c.getCode();
1152  		CYBOZU_TEST_EQUAL(c.L1.getAddress(), p + c.a1);
1153  		CYBOZU_TEST_EQUAL(c.L3.getAddress(), p + c.a3);
1154  		CYBOZU_TEST_EQUAL(c.L2.getAddress(), p + c.a1);
1155  	}
1156  }
1157  
1158  #ifdef XBYAK64
1159  CYBOZU_TEST_AUTO(rip)
1160  {
1161  	int a[] = { 1, 10 };
1162  	int b[] = { 100, 1000 };
1163  	struct Code : Xbyak::CodeGenerator {
1164  		Code(const int *a, const int *b)
1165  		{
1166  			Label label1, label2;
1167  			jmp("@f");
1168  		L(label1);
1169  			db(a[0], 4);
1170  			db(a[1], 4);
1171  		L("@@");
1172  			mov(eax, ptr [rip + label1]);       // a[0]
1173  			mov(ecx, ptr [rip + label1+4]);     // a[1]
1174  			mov(edx, ptr [rip + label2-8+2+6]); // b[0]
1175  			add(ecx, ptr [rip + 16+label2-12]); // b[1]
1176  			add(eax, ecx);
1177  			add(eax, edx);
1178  			ret();
1179  		L(label2);
1180  			db(b[0], 4);
1181  			db(b[1], 4);
1182  
1183  			// error
1184  			CYBOZU_TEST_EXCEPTION(rip + label1 + label2, Xbyak::Error);
1185  		}
1186  	} code(a, b);
1187  	int ret = code.getCode<int (*)()>()();
1188  	CYBOZU_TEST_EQUAL(ret, a[0] + a[1] + b[0] + b[1]);
1189  }
1190  
1191  int ret1234()
1192  {
1193  	return 1234;
1194  }
1195  
1196  int ret9999()
1197  {
1198  	return 9999;
1199  }
1200  
1201  CYBOZU_TEST_AUTO(rip_jmp)
1202  {
1203  	struct Code : Xbyak::CodeGenerator {
1204  		Code()
1205  		{
1206  			Label label;
1207  			xor_(eax, eax);
1208  			call(ptr [rip + label]);
1209  			mov(ecx, eax);
1210  			call(ptr [rip + label + 8]);
1211  			add(eax, ecx);
1212  			ret();
1213  		L(label);
1214  			db((size_t)ret1234, 8);
1215  			db((size_t)ret9999, 8);
1216  		}
1217  	} code;
1218  	int ret = code.getCode<int (*)()>()();
1219  	CYBOZU_TEST_EQUAL(ret, ret1234() + ret9999());
1220  }
1221  
1222  #if 0
1223  CYBOZU_TEST_AUTO(rip_addr)
1224  {
1225  	/*
1226  		we can't assume |&x - &code| < 2GiB anymore
1227  	*/
1228  	static int x = 5;
1229  	struct Code : Xbyak::CodeGenerator {
1230  		Code()
1231  		{
1232  			mov(eax, 123);
1233  			mov(ptr[rip + &x], eax);
1234  			ret();
1235  		}
1236  	} code;
1237  	code.getCode<void (*)()>()();
1238  	CYBOZU_TEST_EQUAL(x, 123);
1239  }
1240  #endif
1241  
1242  #ifndef __APPLE__
1243  CYBOZU_TEST_AUTO(rip_addr_with_fixed_buf)
1244  {
1245  	MIE_ALIGN(4096) static char buf[8192];
1246  	static char *p = buf + 4096;
1247  	static int *x0 = (int*)buf;
1248  	static int *x1 = x0 + 1;
1249  	struct Code : Xbyak::CodeGenerator {
1250  		Code() : Xbyak::CodeGenerator(4096, p)
1251  		{
1252  			mov(eax, 123);
1253  			mov(ptr[rip + x0], eax);
1254  			mov(dword[rip + x1], 456);
1255  			mov(byte[rip + 1 + x1 + 3], 99);
1256  			ret();
1257  		}
1258  	} code;
1259  	code.setProtectModeRE();
1260  	code.getCode<void (*)()>()();
1261  	CYBOZU_TEST_EQUAL(*x0, 123);
1262  	CYBOZU_TEST_EQUAL(*x1, 456);
1263  	CYBOZU_TEST_EQUAL(buf[8], 99);
1264  	code.setProtectModeRW();
1265  }
1266  #endif
1267  #endif
1268  
1269  struct ReleaseTestCode : Xbyak::CodeGenerator {
1270  	ReleaseTestCode(Label& L1, Label& L2, Label& L3)
1271  	{
1272  		L(L1);
1273  		jmp(L1);
1274  		L(L2);
1275  		jmp(L3); // not assigned
1276  	}
1277  };
1278  
1279  /*
1280  	code must unlink label if code is destroyed
1281  */
1282  CYBOZU_TEST_AUTO(release_label_after_code)
1283  {
1284  	puts("---");
1285  	{
1286  		Label L1, L2, L3, L4, L5;
1287  		{
1288  			ReleaseTestCode code(L1, L2, L3);
1289  			CYBOZU_TEST_ASSERT(L1.getId() > 0);
1290  			CYBOZU_TEST_ASSERT(L1.getAddress() != 0);
1291  			CYBOZU_TEST_ASSERT(L2.getId() > 0);
1292  			CYBOZU_TEST_ASSERT(L2.getAddress() != 0);
1293  			CYBOZU_TEST_ASSERT(L3.getId() > 0);
1294  			CYBOZU_TEST_ASSERT(L3.getAddress() == 0); // L3 is not assigned
1295  			code.assignL(L4, L1);
1296  			L5 = L1;
1297  			printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId());
1298  		}
1299  		puts("code is released");
1300  		CYBOZU_TEST_ASSERT(L1.getId() == 0);
1301  		CYBOZU_TEST_ASSERT(L1.getAddress() == 0);
1302  		CYBOZU_TEST_ASSERT(L2.getId() == 0);
1303  		CYBOZU_TEST_ASSERT(L2.getAddress() == 0);
1304  //		CYBOZU_TEST_ASSERT(L3.getId() == 0); // L3 is not assigned so not cleared
1305  		CYBOZU_TEST_ASSERT(L3.getAddress() == 0);
1306  		CYBOZU_TEST_ASSERT(L4.getId() == 0);
1307  		CYBOZU_TEST_ASSERT(L4.getAddress() == 0);
1308  		CYBOZU_TEST_ASSERT(L5.getId() == 0);
1309  		CYBOZU_TEST_ASSERT(L5.getAddress() == 0);
1310  		printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId());
1311  	}
1312  }
1313  
1314  struct JmpTypeCode : Xbyak::CodeGenerator {
1315  	void nops()
1316  	{
1317  		for (int i = 0; i < 130; i++) {
1318  			nop();
1319  		}
1320  	}
1321  	// return jmp code size
1322  	size_t gen(bool pre, bool large, Xbyak::CodeGenerator::LabelType type)
1323  	{
1324  		Label label;
1325  		if (pre) {
1326  			L(label);
1327  			if (large) nops();
1328  			size_t pos = getSize();
1329  			jmp(label, type);
1330  			return getSize() - pos;
1331  		} else {
1332  			size_t pos = getSize();
1333  			jmp(label, type);
1334  			size_t size = getSize() - pos;
1335  			if (large) nops();
1336  			L(label);
1337  			return size;
1338  		}
1339  	}
1340  };
1341  
1342  CYBOZU_TEST_AUTO(setDefaultJmpNEAR)
1343  {
1344  	const Xbyak::CodeGenerator::LabelType T_SHORT = Xbyak::CodeGenerator::T_SHORT;
1345  	const Xbyak::CodeGenerator::LabelType T_NEAR = Xbyak::CodeGenerator::T_NEAR;
1346  	const Xbyak::CodeGenerator::LabelType T_AUTO = Xbyak::CodeGenerator::T_AUTO;
1347  	const struct {
1348  		bool pre;
1349  		bool large;
1350  		Xbyak::CodeGenerator::LabelType type;
1351  		size_t expect1; // 0 means exception
1352  		size_t expect2;
1353  	} tbl[] = {
1354  		{ false, false, T_SHORT, 2, 2 },
1355  		{ false, false, T_NEAR, 5, 5 },
1356  		{ false, true, T_SHORT, 0, 0 },
1357  		{ false, true, T_NEAR, 5, 5 },
1358  
1359  		{ true, false, T_SHORT, 2, 2 },
1360  		{ true, false, T_NEAR, 5, 5 },
1361  		{ true, true, T_SHORT, 0, 0 },
1362  		{ true, true, T_NEAR, 5, 5 },
1363  
1364  		{ false, false, T_AUTO, 2, 5 },
1365  		{ false, true, T_AUTO, 0, 5 },
1366  		{ true, false, T_AUTO, 2, 2 },
1367  		{ true, true, T_AUTO, 5, 5 },
1368  	};
1369  	JmpTypeCode code1, code2;
1370  	code2.setDefaultJmpNEAR(true);
1371  	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
1372  		if (tbl[i].expect1) {
1373  			size_t size = code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
1374  			CYBOZU_TEST_EQUAL(size, tbl[i].expect1);
1375  		} else {
1376  			CYBOZU_TEST_EXCEPTION(code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
1377  		}
1378  		if (tbl[i].expect2) {
1379  			size_t size = code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
1380  			CYBOZU_TEST_EQUAL(size, tbl[i].expect2);
1381  		} else {
1382  			CYBOZU_TEST_EXCEPTION(code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
1383  		}
1384  	}
1385  }
1386  
1387  CYBOZU_TEST_AUTO(ambiguousFarJmp)
1388  {
1389  	struct Code : Xbyak::CodeGenerator {
1390  #ifdef XBYAK32
1391  		void genJmp() { jmp(ptr[eax], T_FAR); }
1392  		void genCall() { call(ptr[eax], T_FAR); }
1393  #else
1394  		void genJmp() { jmp(ptr[rax], T_FAR); }
1395  		void genCall() { call(ptr[rax], T_FAR); }
1396  #endif
1397  	} code;
1398  	CYBOZU_TEST_EXCEPTION(code.genJmp(), std::exception);
1399  	CYBOZU_TEST_EXCEPTION(code.genCall(), std::exception);
1400  }