a1ac3750f Merge branch 'dev'
5f4ba971f v6.68
cac2c175f update doc
1b08a8248 add test of prefetchiti
bef70d9b1 add prefetchit{0,1}
f66785876 add detection of prefetchiti
124617ac9 Merge branch 'dev'
1bce8be17 Merge commit 'fbb18f6' into dev
bebfe64a3 [test] X32 is optional and remove CFLAGS
d8c332cef Merge branch 'Tachi107-small-changes' into dev
fbb18f69d ci: use containers
8a974696c test: simplify makefile
1efe9fe7c Merge branch 'dev'
bb70083e6 v6.67
436e452d7 update doc
47ff6ef42 I get an error after all on GitHub action
445c0dcec add test of CMPccXADD
c9347907d add CMPccXADD
dc792cc56 add detection of cmpccxadd
62be84cc8 fix detection of boost
b5ac7b0f0 Merge branch 'dev'
05dd400e0 recover a removed line
94eff6246 v6.66
ec3fadeba update doc
00bfaaa7f add test of rao-int
0f2f1aaa6 support rio-int
6c047f480 detect rao-int
f07c5c255 fix args of EmptyAllocator::alloc in test
04d3eb5f5 stop if a test script causes an error
1c1d2366f disable boost sample
cfb1127c3 tweak
5fcbeb7c4 [sample] change the way of detection of boost
bafc1ee60 CXX uses g++ as default value
d8cabc6cb remove warning of blace
bc73a0816 remove -fno-operator-names option
6989aea94 use CXX instead of g++
a7c5a1bd7 use English
1bfbd8c4d Fix incorrect format strings
0ecef5c28 Merge branch 'dev'
7556c20ba update doc
a15709271 v6.65
3b83aab3e add detect_x32 to TARGET
8c64bbbc3 use gcc instead of dpkg for portability
5e9a9b96f test_avx512.sh runs on x32
8ae01b0c2 disable some tests on x32
83b3da217 x32 does not check large disp
693ab8c9d sizeof(void*) = 4 on x32, so disable the test
348e3e548 Merge branch 'dev'
11b9c4dc0 v6.64
459636196 add T_M_K flag to vpmov*
1d3722928 add include path
5e27eddae move CrearError from LabelManager::reset() to CodeGenerator::reset()
f8ea5c28d Merge branch 'dev'
20b2b1eae v6.63
3706869f8 desc. of setDefaultEncoding
d6f2d7577 add test of setDefaultEncoding
3b0a19c41 vpmadd52{h,l}uq for avx-ifma
95752ebd7 add tAVX_IFMA
cd36e31ea [sample] show AMX_FP16/AVX_VNNI_INT8/AVX_NE_CONVERT
e5858af27 add setDefaultEncoding
2f7fb0220 modify gen.cpp for AVX-NE-CONVERT/AVX-VNNI-INT8/AMX-FP16
1c5cb7efa add AVX-NE-CONVERT instructions
564fe9acd add AVX-VNNI-INT8 instructions
cd14d07b1 add AMX-FP16 instruction
7811f593c Merge pull request #161 from scribam/patch-1
2218f6c08 Update changelog.md
7bccdbbb4 Merge pull request #160 from herumi/dev
5fcf87596 compile nasm-2.15 instead of apt install
e31961ea8 v6.62
ff4f9e65c update doc
9c8fb81db disable wrong detection of gcc -Warray-bounds
6b7519659 add serialize
e16582696 Merge branch 'JonLiu1993-vcpkg-installition' into dev
edbb410fb Add vcpkg installation instructions
055d31242 Merge branch 'dev'
21ab98441 Merge branch 'akodanka-enable_CIV' into dev
ed4d598e3 Changes to compile xbyak project for openvino
b652430c4 mingw uses __cpuidex
48457bfa0 Merge branch 'dev'
29cb524d1 v6.61.2
1a9a0b0e1 avoid including algorithm header in xbyak_util.h
6fadefd04 Merge branch 'dev'
fc1c18a9d update doc
f7cae7f11 v6.61.1
6f5ec5cf3 Merge branch 'doyaGu-master' into dev
4554d6bb9 Fix error related to XBYAK_NOEXCEPT
git-subtree-dir: externals/xbyak
git-subtree-split: a1ac3750f9a639b5a6c6d6c7da4259b8d6790989
12 KiB
Usage
Inherit Xbyak::CodeGenerator class and make the class method.
#include <xbyak/xbyak.h>
struct Code : Xbyak::CodeGenerator {
Code(int x)
{
mov(eax, x);
ret();
}
};
Or you can pass the instance of CodeGenerator without inheriting.
void genCode(Xbyak::CodeGenerator& code, int x) {
using namespace Xbyak::util;
code.mov(eax, x);
code.ret();
}
Make an instance of the class and get the function
pointer by calling getCode() and call it.
Code c(5);
int (*f)() = c.getCode<int (*)()>();
printf("ret=%d\n", f()); // ret = 5
Syntax
Similar to MASM/NASM syntax with parentheses.
NASM Xbyak
mov eax, ebx --> mov(eax, ebx);
inc ecx inc(ecx);
ret --> ret();
Addressing
Use qword, dword, word and byte if it is necessary to specify the size of memory,
otherwise use ptr.
(ptr|qword|dword|word|byte) [base + index * (1|2|4|8) + displacement]
[rip + 32bit disp] ; x64 only
NASM Xbyak
mov eax, [ebx+ecx] --> mov(eax, ptr [ebx+ecx]);
mov al, [ebx+ecx] --> mov(al, ptr [ebx + ecx]);
test byte [esp], 4 --> test(byte [esp], 4);
inc qword [rax] --> inc(qword [rax]);
Note: qword, ... are member variables, then don't use dword as unsigned int type.
How to use Selector (Segment Register)
mov eax, [fs:eax] --> putSeg(fs);
mov(eax, ptr [eax]);
mov ax, cs --> mov(ax, cs);
Note: Segment class is not derived from Operand.
AVX
vaddps(xmm1, xmm2, xmm3); // xmm1 <- xmm2 + xmm3
vaddps(xmm2, xmm3, ptr [rax]); // use ptr to access memory
vgatherdpd(xmm1, ptr [ebp + 256 + xmm2*4], xmm3);
Note:
If XBYAK_ENABLE_OMITTED_OPERAND is defined, then you can use two operand version for backward compatibility.
But the newer version will not support it.
vaddps(xmm2, xmm3); // xmm2 <- xmm2 + xmm3
AVX-512
vaddpd zmm2, zmm5, zmm30 --> vaddpd(zmm2, zmm5, zmm30);
vaddpd xmm30, xmm20, [rax] --> vaddpd(xmm30, xmm20, ptr [rax]);
vaddps xmm30, xmm20, [rax] --> vaddps(xmm30, xmm20, ptr [rax]);
vaddpd zmm2{k5}, zmm4, zmm2 --> vaddpd(zmm2 | k5, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2 --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2,{rd-sae} --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2 | T_rd_sae);
vaddpd(zmm2 | k5 | T_z | T_rd_sae, zmm4, zmm2); // the position of `|` is arbitrary.
vcmppd k4{k3}, zmm1, zmm2, {sae}, 5 --> vcmppd(k4 | k3, zmm1, zmm2 | T_sae, 5);
vaddpd xmm1, xmm2, [rax+256] --> vaddpd(xmm1, xmm2, ptr [rax+256]);
vaddpd xmm1, xmm2, [rax+256]{1to2} --> vaddpd(xmm1, xmm2, ptr_b [rax+256]);
vaddpd ymm1, ymm2, [rax+256]{1to4} --> vaddpd(ymm1, ymm2, ptr_b [rax+256]);
vaddpd zmm1, zmm2, [rax+256]{1to8} --> vaddpd(zmm1, zmm2, ptr_b [rax+256]);
vaddps zmm1, zmm2, [rax+rcx*8+8]{1to16} --> vaddps(zmm1, zmm2, ptr_b [rax+rcx*8+8]);
vmovsd [rax]{k1}, xmm4 --> vmovsd(ptr [rax] | k1, xmm4);
vcvtpd2dq xmm16, oword [eax+33] --> vcvtpd2dq(xmm16, xword [eax+33]); // use xword for m128 instead of oword
vcvtpd2dq(xmm16, ptr [eax+33]); // default xword
vcvtpd2dq xmm21, [eax+32]{1to2} --> vcvtpd2dq(xmm21, ptr_b [eax+32]);
vcvtpd2dq xmm0, yword [eax+33] --> vcvtpd2dq(xmm0, yword [eax+33]); // use yword for m256
vcvtpd2dq xmm19, [eax+32]{1to4} --> vcvtpd2dq(xmm19, yword_b [eax+32]); // use yword_b to broadcast
vfpclassps k5{k3}, zword [rax+64], 5 --> vfpclassps(k5|k3, zword [rax+64], 5); // specify m512
vfpclasspd k5{k3}, [rax+64]{1to2}, 5 --> vfpclasspd(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 128-bit
vfpclassps k5{k3}, [rax+64]{1to4}, 5 --> vfpclassps(k5|k3, yword_b [rax+64], 5); // broadcast 64-bit to 256-bit
vpdpbusd(xm0, xm1, xm2); // default encoding is EVEX
vpdpbusd(xm0, xm1, xm2, EvexEncoding); // same as the above
vpdpbusd(xm0, xm1, xm2, VexEncoding); // VEX encoding
setDefaultEncoding(VexEncoding); // default encoding is VEX
vpdpbusd(xm0, xm1, xm2); // VEX encoding
- setDefaultEncoding(PreferredEncoding encoding);
- Set the default encoding to select EVEX or VEX.
- The default value is EvexEncoding.
- This function affects only an instruction that has a PreferredEncoding argument such as vpdpbusd.
Remark
k1, ...,k7are opmask registers.k0is dealt as no mask.- e.g.
vmovaps(zmm0|k0, ptr[rax]);andvmovaps(zmm0|T_z, ptr[rax]);are same tovmovaps(zmm0, ptr[rax]);.
- use
| T_z,| T_sae,| T_rn_sae,| T_rd_sae,| T_ru_sae,| T_rz_saeinstead of,{z},,{sae},,{rn-sae},,{rd-sae},,{ru-sae},,{rz-sae}respectively. k4 | k3is different fromk3 | k4.- use
ptr_bfor broadcast{1toX}. X is automatically determined. - specify
xword/yword/zword(_b)for m128/m256/m512 if necessary.
Label
Two kinds of Label are supported. (String literal and Label class).
String literal
L("L1");
jmp("L1");
jmp("L2");
...
a few mnemonics (8-bit displacement jmp)
...
L("L2");
jmp("L3", T_NEAR);
...
a lot of mnemonics (32-bit displacement jmp)
...
L("L3");
- Call
hasUndefinedLabel()to verify your code has no undefined label. - you can use a label for immediate value of mov like as
mov(eax, "L2").
Support @@, @f, @b like MASM
L("@@"); // <A>
jmp("@b"); // jmp to <A>
jmp("@f"); // jmp to <B>
L("@@"); // <B>
jmp("@b"); // jmp to <B>
mov(eax, "@b");
jmp(eax); // jmp to <B>
Local label
Label symbols beginning with a period between inLocalLabel() and outLocalLabel()
are treated as a local label.
inLocalLabel() and outLocalLabel() can be nested.
void func1()
{
inLocalLabel();
L(".lp"); // <A> ; local label
...
jmp(".lp"); // jmp to <A>
L("aaa"); // global label <C>
outLocalLabel();
inLocalLabel();
L(".lp"); // <B> ; local label
func1();
jmp(".lp"); // jmp to <B>
inLocalLabel();
jmp("aaa"); // jmp to <C>
}
short and long jump
Xbyak deals with jump mnemonics of an undefined label as short jump if no type is specified. So if the size between jmp and label is larger than 127 byte, then xbyak will cause an error.
jmp("short-jmp"); // short jmp
// small code
L("short-jmp");
jmp("long-jmp");
// long code
L("long-jmp"); // throw exception
Then specify T_NEAR for jmp.
jmp("long-jmp", T_NEAR); // long jmp
// long code
L("long-jmp");
Or call setDefaultJmpNEAR(true); once, then the default type is set to T_NEAR.
jmp("long-jmp"); // long jmp
// long code
L("long-jmp");
Label class
L() and jxx() support Label class.
Xbyak::Label label1, label2;
L(label1);
...
jmp(label1);
...
jmp(label2);
...
L(label2);
Use putL for jmp table
Label labelTbl, L0, L1, L2;
mov(rax, labelTbl);
// rdx is an index of jump table
jmp(ptr [rax + rdx * sizeof(void*)]);
L(labelTbl);
putL(L0);
putL(L1);
putL(L2);
L(L0);
....
L(L1);
....
assignL(dstLabel, srcLabel) binds dstLabel with srcLabel.
Label label2;
Label label1 = L(); // make label1 ; same to Label label1; L(label1);
...
jmp(label2); // label2 is not determined here
...
assignL(label2, label1); // label2 <- label1
The jmp in the above code jumps to label1 assigned by assignL.
Note:
- srcLabel must be used in
L(). - dstLabel must not be used in
L().
Label::getAddress() returns the address specified by the label instance and 0 if not specified.
// not AutoGrow mode
Label label;
assert(label.getAddress() == 0);
L(label);
assert(label.getAddress() == getCurr());
Rip ; relative addressing
Label label;
mov(eax, ptr [rip + label]); // eax = 4
...
L(label);
dd(4);
int x;
...
mov(eax, ptr[rip + &x]); // throw exception if the difference between &x and current position is larger than 2GiB
Far jump
Use word|dword|qword instead of ptr to specify the address size.
32 bit mode
jmp(word[eax], T_FAR); // jmp m16:16(FF /5)
jmp(dword[eax], T_FAR); // jmp m16:32(FF /5)
64 bit mode
jmp(word[rax], T_FAR); // jmp m16:16(FF /5)
jmp(dword[rax], T_FAR); // jmp m16:32(FF /5)
jmp(qword[rax], T_FAR); // jmp m16:64(REX.W FF /5)
The same applies to call.
Code size
The default max code size is 4096 bytes.
Specify the size in constructor of CodeGenerator() if necessary.
class Quantize : public Xbyak::CodeGenerator {
public:
Quantize()
: CodeGenerator(8192)
{
}
...
};
User allocated memory
You can make jit code on prepared memory.
Call setProtectModeRE yourself to change memory mode if using the prepared memory.
uint8_t alignas(4096) buf[8192]; // C++11 or later
struct Code : Xbyak::CodeGenerator {
Code() : Xbyak::CodeGenerator(sizeof(buf), buf)
{
mov(rax, 123);
ret();
}
};
int main()
{
Code c;
c.setProtectModeRE(); // set memory to Read/Exec
printf("%d\n", c.getCode<int(*)()>()());
}
Note: See ../sample/test0.cpp.
AutoGrow
The memory region for jit is automatically extended if necessary when AutoGrow is specified in a constructor of CodeGenerator.
Call ready() or readyRE() before calling getCode() to fix jump address.
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(<default memory size>, Xbyak::AutoGrow)
{
...
}
};
Code c;
// generate code for jit
c.ready(); // mode = Read/Write/Exec
Note:
- Don't use the address returned by
getCurr()before callingready()because it may be invalid address.
Read/Exec mode
Xbyak set Read/Write/Exec mode to memory to run jit code.
If you want to use Read/Exec mode for security, then specify DontSetProtectRWE for CodeGenerator and
call setProtectModeRE() after generating jit code.
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
{
mov(eax, 123);
ret();
}
};
Code c;
c.setProtectModeRE();
...
Call readyRE() instead of ready() when using AutoGrow mode.
See protect-re.cpp.
Exception-less mode
If XBYAK_NO_EXCEPTION is defined, then gcc/clang can compile xbyak with -fno-exceptions.
In stead of throwing an exception, Xbyak::GetError() returns non-zero value (e.g. ERR_BAD_ADDRESSING) if there is something wrong.
The status will not be changed automatically, then you should reset it by Xbyak::ClearError().
CodeGenerator::reset() calls ClearError().
Macro
- XBYAK32 is defined on 32bit.
- XBYAK64 is defined on 64bit.
- XBYAK64_WIN is defined on 64bit Windows(VC).
- XBYAK64_GCC is defined on 64bit gcc, cygwin.
- define XBYAK_USE_OP_NAMES on gcc with
-fno-operator-namesif you want to useand(), .... - define XBYAK_ENABLE_OMITTED_OPERAND if you use omitted destination such as
vaddps(xmm2, xmm3);(deprecated in the future). - define XBYAK_UNDEF_JNL if Bessel function jnl is defined as macro.
- define XBYAK_NO_EXCEPTION for a compiler option
-fno-exceptions. - define XBYAK_USE_MEMFD on Linux then /proc/self/maps shows the area used by xbyak.
- define XBYAK_OLD_DISP_CHECK if the old disp check is necessary (deprecated in the future).
Sample
- test0.cpp ; tiny sample (x86, x64)
- quantize.cpp ; JIT optimized quantization by fast division (x86 only)
- calc.cpp ; assemble and estimate a given polynomial (x86, x64)
- bf.cpp ; JIT brainfuck (x86, x64)