f6fdb5f55a
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
380 lines
7.1 KiB
C++
380 lines
7.1 KiB
C++
/*
|
|
toy vm
|
|
register A, B : 32bit
|
|
PC : program counter
|
|
|
|
mem_ 4byte x 65536
|
|
|
|
all instructions are fixed at 4 bytes.
|
|
all immediate values are 16-bit.
|
|
|
|
R = A or B
|
|
vldiR, imm ; R = imm
|
|
vldR, idx ; R = mem_[idx]
|
|
vstR, idx ; mem_[idx] = R
|
|
vaddiR, imm ; R += imm
|
|
vsubiR, imm ; R -= imm
|
|
vaddR, idx ; R += mem_[idx]
|
|
vsubR, idx ; R -= mem_[idx]
|
|
vputR ; print R
|
|
vjnzR, offset; if (R != 0) then jmp(PC += offset(signed))
|
|
*/
|
|
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
|
|
#pragma warning(disable:4514)
|
|
#pragma warning(disable:4786)
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include <vector>
|
|
#define XBYAK_NO_OP_NAMES
|
|
#include "xbyak/xbyak.h"
|
|
#include "xbyak/xbyak_util.h"
|
|
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
|
|
|
|
#ifdef XBYAK64
|
|
#error "only 32bit"
|
|
#endif
|
|
|
|
using namespace Xbyak;
|
|
|
|
class ToyVm : public Xbyak::CodeGenerator {
|
|
typedef std::vector<uint32_t> Buffer;
|
|
public:
|
|
enum Reg {
|
|
A, B
|
|
};
|
|
enum Code {
|
|
LD, LDI, ST, ADD, ADDI, SUB, SUBI, PUT, JNZ,
|
|
END_OF_CODE
|
|
};
|
|
ToyVm()
|
|
: mark_(0)
|
|
{
|
|
::memset(mem_, 0, sizeof(mem_));
|
|
}
|
|
void vldi(Reg r, uint16_t imm) { encode(LDI, r, imm); }
|
|
void vld(Reg r, uint16_t idx) { encode(LD, r, idx); }
|
|
void vst(Reg r, uint16_t idx) { encode(ST, r, idx); }
|
|
void vadd(Reg r, uint16_t idx) { encode(ADD, r, idx); }
|
|
void vaddi(Reg r, uint16_t imm) { encode(ADDI, r, imm); }
|
|
void vsub(Reg r, uint16_t idx) { encode(SUB, r, idx); }
|
|
void vsubi(Reg r, uint16_t imm) { encode(SUBI, r, imm); }
|
|
void vjnz(Reg r, int offset) { encode(JNZ, r, static_cast<uint16_t>(offset)); }
|
|
void vput(Reg r) { encode(PUT, r); }
|
|
void setMark()
|
|
{
|
|
mark_ = (int)code_.size();
|
|
}
|
|
int getMarkOffset()
|
|
{
|
|
return mark_ - (int)code_.size() - 1;
|
|
}
|
|
void run()
|
|
{
|
|
bool debug = false;//true;
|
|
uint32_t reg[2] = { 0, 0 };
|
|
const size_t end = code_.size();
|
|
uint32_t pc = 0;
|
|
for (;;) {
|
|
uint32_t x = code_[pc];
|
|
uint32_t code, r, imm;
|
|
decode(code, r, imm, x);
|
|
if (debug) {
|
|
printf("---\n");
|
|
printf("A %08x B %08x\n", reg[0], reg[1]);
|
|
printf("mem_[] = %08x %08x %08x\n", mem_[0], mem_[1], mem_[2]);
|
|
printf("pc=%4d, code=%02x, r=%d, imm=%04x\n", pc, code, r, imm);
|
|
}
|
|
switch (code) {
|
|
case LDI:
|
|
reg[r] = imm;
|
|
break;
|
|
case LD:
|
|
reg[r] = mem_[imm];
|
|
break;
|
|
case ST:
|
|
mem_[imm] = reg[r];
|
|
break;
|
|
case ADD:
|
|
reg[r] += mem_[imm];
|
|
break;
|
|
case ADDI:
|
|
reg[r] += imm;
|
|
break;
|
|
case SUB:
|
|
reg[r] -= mem_[imm];
|
|
break;
|
|
case SUBI:
|
|
reg[r] -= imm;
|
|
break;
|
|
case PUT:
|
|
printf("%c %8u(0x%08x)\n", 'A' + r, reg[r], reg[r]);
|
|
break;
|
|
case JNZ:
|
|
if (reg[r] != 0) pc += static_cast<signed short>(imm);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
pc++;
|
|
if (pc >= end) break;
|
|
} // for (;;)
|
|
}
|
|
void recompile()
|
|
{
|
|
using namespace Xbyak;
|
|
/*
|
|
esi : A
|
|
edi : B
|
|
ebx : mem_
|
|
for speed up
|
|
mem_[0] : eax
|
|
mem_[1] : ecx
|
|
mem_[2] : edx
|
|
*/
|
|
push(ebx);
|
|
push(esi);
|
|
push(edi);
|
|
|
|
const Reg32 reg[2] = { esi, edi };
|
|
const Reg32 mem(ebx);
|
|
|
|
const Reg32 memTbl[] = { eax, ecx, edx };
|
|
const size_t memTblNum = NUM_OF_ARRAY(memTbl);
|
|
for (size_t i = 0; i < memTblNum; i++) xor_(memTbl[i], memTbl[i]);
|
|
|
|
xor_(esi, esi);
|
|
xor_(edi, edi);
|
|
mov(mem, (size_t)mem_);
|
|
const size_t end = code_.size();
|
|
uint32_t pc = 0;
|
|
uint32_t labelNum = 0;
|
|
for (;;) {
|
|
uint32_t x = code_[pc];
|
|
uint32_t code, r, imm;
|
|
decode(code, r, imm, x);
|
|
L(Label::toStr(labelNum++));
|
|
switch (code) {
|
|
case LDI:
|
|
mov(reg[r], imm);
|
|
break;
|
|
case LD:
|
|
if (imm < memTblNum) {
|
|
mov(reg[r], memTbl[imm]);
|
|
} else {
|
|
mov(reg[r], ptr[mem + imm * 4]);
|
|
}
|
|
break;
|
|
case ST:
|
|
if (imm < memTblNum) {
|
|
mov(memTbl[imm], reg[r]);
|
|
} else {
|
|
mov(ptr [mem + imm * 4], reg[r]);
|
|
}
|
|
break;
|
|
case ADD:
|
|
if (imm < memTblNum) {
|
|
add(reg[r], memTbl[imm]);
|
|
} else {
|
|
add(reg[r], ptr [mem + imm * 4]);
|
|
}
|
|
break;
|
|
case ADDI:
|
|
add(reg[r], imm);
|
|
break;
|
|
case SUB:
|
|
if (imm < memTblNum) {
|
|
sub(reg[r], memTbl[imm]);
|
|
} else {
|
|
sub(reg[r], ptr [mem + imm * 4]);
|
|
}
|
|
break;
|
|
case SUBI:
|
|
sub(reg[r], imm);
|
|
break;
|
|
case PUT:
|
|
{
|
|
static const char *str = "%c %8d(0x%08x)\n";
|
|
push(eax);
|
|
push(edx);
|
|
push(ecx);
|
|
push(reg[r]);
|
|
push(reg[r]);
|
|
push('A' + r);
|
|
push((int)str);
|
|
call(reinterpret_cast<const void*>(printf));
|
|
add(esp, 4 * 4);
|
|
pop(ecx);
|
|
pop(edx);
|
|
pop(eax);
|
|
}
|
|
break;
|
|
case JNZ:
|
|
test(reg[r], reg[r]);
|
|
jnz(Label::toStr(labelNum + static_cast<signed short>(imm)));
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
pc++;
|
|
if (pc >= end) break;
|
|
} // for (;;)
|
|
|
|
pop(edi);
|
|
pop(esi);
|
|
pop(ebx);
|
|
ret();
|
|
}
|
|
private:
|
|
uint32_t mem_[65536];
|
|
Buffer code_;
|
|
int mark_;
|
|
void decode(uint32_t& code, uint32_t& r, uint32_t& imm, uint32_t x)
|
|
{
|
|
code = x >> 24;
|
|
r = (x >> 16) & 0xff;
|
|
imm = x & 0xffff;
|
|
}
|
|
void encode(Code code, Reg r, uint16_t imm = 0)
|
|
{
|
|
uint32_t x = (code << 24) | (r << 16) | imm;
|
|
code_.push_back(x);
|
|
}
|
|
};
|
|
|
|
class Fib : public ToyVm {
|
|
public:
|
|
Fib(int n)
|
|
{
|
|
if (n >= 65536) {
|
|
fprintf(stderr, "current version support only imm16\n");
|
|
return;
|
|
}
|
|
/*
|
|
A : c
|
|
B : temporary
|
|
mem_[0] : p
|
|
mem_[1] : t
|
|
mem_[2] : n
|
|
*/
|
|
vldi(A, 1); // c
|
|
vst(A, 0); // p(1)
|
|
vldi(B, static_cast<uint16_t>(n));
|
|
vst(B, 2); // n
|
|
// lp
|
|
setMark();
|
|
vst(A, 1); // t = c
|
|
vadd(A, 0); // c += p
|
|
vld(B, 1);
|
|
vst(B, 0); // p = t
|
|
// vput(A);
|
|
vld(B, 2);
|
|
vsubi(B, 1);
|
|
vst(B, 2); // n--
|
|
vjnz(B, getMarkOffset());
|
|
vput(A);
|
|
}
|
|
void runByJIT()
|
|
{
|
|
getCode<void (*)()>();
|
|
}
|
|
};
|
|
|
|
void fibC(uint32_t n)
|
|
{
|
|
uint32_t p, c, t;
|
|
p = 1;
|
|
c = 1;
|
|
lp:
|
|
t = c;
|
|
c += p;
|
|
p = t;
|
|
n--;
|
|
if (n != 0) goto lp;
|
|
printf("c=%u(0x%08x)\n", c, c);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
try {
|
|
const int n = 10000;
|
|
Fib fib(n);
|
|
|
|
fib.recompile();
|
|
|
|
{
|
|
Xbyak::util::Clock clk;
|
|
clk.begin();
|
|
fib.run();
|
|
clk.end();
|
|
printf("vm %.2fKclk\n", clk.getClock() * 1e-3);
|
|
}
|
|
|
|
{
|
|
Xbyak::util::Clock clk;
|
|
clk.begin();
|
|
fib.runByJIT();
|
|
clk.end();
|
|
printf("jit %.2fKclk\n", clk.getClock() * 1e-3);
|
|
}
|
|
|
|
{
|
|
Xbyak::util::Clock clk;
|
|
clk.begin();
|
|
fibC(n);
|
|
clk.end();
|
|
printf("native C %.2fKclk\n", clk.getClock() * 1e-3);
|
|
}
|
|
} catch (std::exception& e) {
|
|
printf("ERR:%s\n", e.what());
|
|
} catch (...) {
|
|
printf("unknown error\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
the code generated by Xbyak
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
xor eax,eax
|
|
xor ecx,ecx
|
|
xor edx,edx
|
|
xor esi,esi
|
|
xor edi,edi
|
|
mov ebx,0EFF58h
|
|
mov esi,1
|
|
mov eax,esi
|
|
mov edi,2710h
|
|
mov edx,edi
|
|
.lp:
|
|
mov ecx,esi
|
|
add esi,eax
|
|
mov edi,ecx
|
|
mov eax,edi
|
|
mov edi,edx
|
|
sub edi,1
|
|
mov edx,edi
|
|
test edi,edi
|
|
jne .lp
|
|
push eax
|
|
push edx
|
|
push ecx
|
|
push esi
|
|
push esi
|
|
push 41h
|
|
push 42C434h
|
|
call printf (409342h)
|
|
add esp,10h
|
|
pop ecx
|
|
pop edx
|
|
pop eax
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
ret
|
|
*/
|