Merge branch 'dev'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a13462..e4d0e53 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 2.6...3.0.2)
 
-project(xbyak LANGUAGES CXX VERSION 6.71)
+project(xbyak LANGUAGES CXX VERSION 6.72)
 
 file(GLOB headers xbyak/*.h)
 
diff --git a/doc/changelog.md b/doc/changelog.md
index 0045b7c..6820eb5 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -1,5 +1,6 @@
 # History
 
+* 2023/Aug/02 ver 6.72 add xbegin/xabort/xend
 * 2023/Jul/27 ver 6.71 Allocator supports huge page
 * 2023/Jul/05 ver 6.70 add alias of vclmulqdq, correct alias of pclmulqdq
 * 2023/Jun/27 ver 6.69.2 add constexpr to `TypeT operator|` (thanks to Wunkolo)
diff --git a/gen/gen_code.cpp b/gen/gen_code.cpp
index f638016..c62fa35 100644
--- a/gen/gen_code.cpp
+++ b/gen/gen_code.cpp
@@ -720,6 +720,7 @@
 			{ "wbinvd", 0x0F, 0x09 },
 			{ "wrmsr", 0x0F, 0x30 },
 			{ "xlatb", 0xD7 },
+			{ "xend", 0x0f, 0x01, 0xd5 },
 
 			{ "popf", 0x9D },
 			{ "pushf", 0x9C },
@@ -1113,6 +1114,8 @@
 		puts("void umwait(const Reg32& r) { int idx = r.getIdx(); if (idx > 7) XBYAK_THROW(ERR_BAD_PARAMETER) db(0xF2); db(0x0F); db(0xAE); setModRM(3, 6, idx); }");
 		puts("void clwb(const Address& addr) { db(0x66); opMIB(addr, esi, 0x0F, 0xAE); }");
 		puts("void cldemote(const Address& addr) { opMIB(addr, eax, 0x0F, 0x1C); }");
+		puts("void xabort(uint8_t imm) { db(0xC6); db(0xF8); db(imm); }");
+		puts("void xbegin(uint32_t rel) { db(0xC7); db(0xF8); dd(rel); }");
 	}
 	{
 		const struct Tbl {
diff --git a/meson.build b/meson.build
index dbe4d25..1dfdf15 100644
--- a/meson.build
+++ b/meson.build
@@ -5,7 +5,7 @@
 project(
 	'xbyak',
 	'cpp',
-	version: '6.71',
+	version: '6.72',
 	license: 'BSD-3-Clause',
 	default_options: 'b_ndebug=if-release'
 )
diff --git a/readme.md b/readme.md
index ccf9c39..adbbfb9 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,5 @@
 
-# Xbyak 6.71 [![Badge Build]][Build Status]
+# Xbyak 6.72 [![Badge Build]][Build Status]
 
 *A C++ JIT assembler for x86 (IA32), x64 (AMD64, x86-64)*
 
diff --git a/readme.txt b/readme.txt
index ba8c153..606dc7a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,5 +1,5 @@
 

-    C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 6.71

+    C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 6.72

 

 -----------------------------------------------------------------------------

 ◎概要

@@ -402,6 +402,7 @@
 -----------------------------------------------------------------------------

 ◎履歴

 

+2023/08/02 ver 6.72 xabort, xbegin, xend追加

 2023/07/27 ver 6.71 Allocatorでhuge pageを考慮する。

 2023/07/05 ver 6.70 vpclmulqdqのailas追加

 2023/06/27 ver 6.69.2 `TypeT operator|`にconstexpr追加(thanks to Wunkolo)

diff --git a/test/Makefile b/test/Makefile
index 6a68dfc..28d8e6f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -115,3 +115,4 @@
 	$(CXX) $(CFLAGS) lib_run.cpp lib_test.cpp -o lib_run
 make_nm: make_nm.cpp $(XBYAK_INC)
 
+.PHONY: test
diff --git a/test/make_nm.cpp b/test/make_nm.cpp
index f54fade..b257dcd 100644
--- a/test/make_nm.cpp
+++ b/test/make_nm.cpp
@@ -558,6 +558,7 @@
 			"wbinvd",
 			"wrmsr",
 			"xlatb",
+			"xend",
 
 			"popf",
 			"pushf",
@@ -1333,6 +1334,7 @@
 #ifdef XBYAK64
 		put("cmpxchg16b", MEM);
 		put("fxrstor64", MEM);
+		put("xbegin", "0x12345678");
 #endif
 		{
 			const char tbl[][8] = {
@@ -1355,6 +1357,7 @@
 		put("xchg", EAX|REG32, EAX|REG32|MEM);
 		put("xchg", MEM, EAX|REG32);
 		put("xchg", REG64, REG64|MEM);
+		put("xabort", IMM8);
 	}
 	void putShift() const
 	{
diff --git a/test/normalize_prefix.cpp b/test/normalize_prefix.cpp
index 889d925..f85a341 100644
--- a/test/normalize_prefix.cpp
+++ b/test/normalize_prefix.cpp
@@ -8,14 +8,25 @@
 
 typedef unsigned char uint8_t;
 
-std::string normalize(const std::string& line)
+std::string normalize(std::string line)
 {
+	size_t pos = line.find('(');
+	/* nasm generates byte codes containing () for xbegin, so remove it. */
+	if (pos != std::string::npos) {
+		line.erase(pos, 1);
+		pos = line.find(')');
+		if (pos == std::string::npos) {
+			fprintf(stderr, "line error {%s}\n", line.c_str());
+			return "";
+		}
+		line.erase(pos, 1);
+	}
 	static const char tbl[][3] = { "66", "67", "F2", "F3" };
 	size_t tblNum = sizeof(tbl) / sizeof(tbl[0]);
 	typedef std::set<std::string> StringSet;
 	StringSet suf;
 
-	size_t pos = 0;
+	pos = 0;
 	for (; pos < line.size(); pos += 2) {
 		bool found = false;
 		for (size_t i = 0; i < tblNum; i++) {
diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h
index 9751557..d273704 100644
--- a/xbyak/xbyak.h
+++ b/xbyak/xbyak.h
@@ -155,7 +155,7 @@
 
 enum {
 	DEFAULT_MAX_CODE_SIZE = 4096,
-	VERSION = 0x6710 /* 0xABCD = A.BC(.D) */
+	VERSION = 0x6720 /* 0xABCD = A.BC(.D) */
 };
 
 #ifndef MIE_INTEGER_TYPE_DEFINED
diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h
index c98f837..d67b1a8 100644
--- a/xbyak/xbyak_mnemonic.h
+++ b/xbyak/xbyak_mnemonic.h
@@ -1,4 +1,4 @@
-const char *getVersionString() const { return "6.71"; }
+const char *getVersionString() const { return "6.72"; }
 void aadd(const Address& addr, const Reg32e &reg) { opModM(addr, reg, 0x0F, 0x38, 0x0FC); }
 void aand(const Address& addr, const Reg32e &reg) { db(0x66); opModM(addr, reg, 0x0F, 0x38, 0x0FC); }
 void adc(const Operand& op, uint32_t imm) { opRM_I(op, imm, 0x10, 2); }
@@ -1374,7 +1374,10 @@
 void wait() { db(0x9B); }
 void wbinvd() { db(0x0F); db(0x09); }
 void wrmsr() { db(0x0F); db(0x30); }
+void xabort(uint8_t imm) { db(0xC6); db(0xF8); db(imm); }
 void xadd(const Operand& op, const Reg& reg) { opModRM(reg, op, (op.isREG() && reg.isREG() && op.getBit() == reg.getBit()), op.isMEM(), 0x0F, 0xC0 | (reg.isBit(8) ? 0 : 1)); }
+void xbegin(uint32_t rel) { db(0xC7); db(0xF8); dd(rel); }
+void xend() { db(0x0F); db(0x01); db(0xD5); }
 void xgetbv() { db(0x0F); db(0x01); db(0xD0); }
 void xlatb() { db(0xD7); }
 void xor_(const Operand& op, uint32_t imm) { opRM_I(op, imm, 0x30, 6); }