use 32bit extended encoding for mov(reg64, imm)

This commit is contained in:
MITSUNARI Shigeo 2010-06-01 16:28:14 +09:00
parent 2965c4c0ba
commit ba203dc894
15 changed files with 6359 additions and 461 deletions

View file

@ -1,5 +1,5 @@
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak version 2.26
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak version 2.27
-----------------------------------------------------------------------------
◎概要
@ -199,6 +199,7 @@ sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から
-----------------------------------------------------------------------------
◎履歴
2010/06/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
2010/05/24 ver 2.26 fix sub(rsp, 1000)
2010/04/26 ver 2.25 add jc/jnc(I forgot to implement them...)
2010/04/16 ver 2.24 change the prototype of rewrite() method

View file

@ -1,5 +1,5 @@
Xbyak 2.26 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
Xbyak 2.27 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
-----------------------------------------------------------------------------
<Abstract>
@ -148,6 +148,7 @@ http://www.opensource.org/licenses/bsd-license.php
-----------------------------------------------------------------------------
<History>
2010/Jun/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
2010/May/24 ver 2.26 fix sub(rsp, 1000)
2010/Apr/26 ver 2.25 add jc/jnc(I forgot to implement them...)
2010/Apr/16 ver 2.24 change the prototype of rewrite() method
@ -184,5 +185,5 @@ http://www.opensource.org/licenses/bsd-license.php
MITSUNARI Shigeo(herumi at nifty dot com)
---
$Revision: 1.46 $
$Date: 2010/05/24 06:13:44 $
$Revision: 1.47 $
$Date: 2010/06/01 01:21:39 $

View file

@ -20,12 +20,17 @@ normalize_prefix: normalize_prefix.cpp
g++ $(CFLAGS) normalize_prefix.cpp -o $@
test_mmx: test_mmx.cpp
g++ $(CFLAGS) test_mmx.cpp -o $@ -lpthread
jmp: jmp.cpp
g++ $(CFLAGS) jmp.cpp -o $@
test: normalize_prefix
test: normalize_prefix jmp
./test_nm.sh
./test_nm.sh Y
./test_nm.sh 64
./test_nm.sh Y64
./test_address.sh
./test_address.sh 64
./jmp
clean:
rm -rf *.o $(TARGET)

View file

@ -5,16 +5,21 @@
void genAddress(bool isJIT, const char regTbl[][5], size_t regTblNum)
{
int count = 0;
int funcNum = 1;
if (isJIT) {
puts("void gen0(){");
}
for (size_t i = 0; i < regTblNum + 1; i++) {
const char *base = regTbl[i];
for (size_t j = 0; j < regTblNum + 1; j++) {
if (j == 4) continue; /* esp is not index register */
const char *index = regTbl[j];
static const int scaleTbl[] = { 0, 1, 2, 4, 8 };
for (int k = 0; k < NUM_OF_ARRAY(scaleTbl); k++) {
for (size_t k = 0; k < NUM_OF_ARRAY(scaleTbl); k++) {
int scale = scaleTbl[k];
static const int dispTbl[] = { 0, 1, 1000, -1, -1000 };
for (int m = 0; m < NUM_OF_ARRAY(dispTbl); m++) {
for (size_t m = 0; m < NUM_OF_ARRAY(dispTbl); m++) {
int disp = dispTbl[m];
bool isFirst = true;
if (isJIT) {
@ -47,10 +52,23 @@ void genAddress(bool isJIT, const char regTbl[][5], size_t regTblNum)
} else {
printf("]\n");
}
if (isJIT) {
count++;
if ((count % 100) == 0) {
printf("}\n void gen%d(){\n", funcNum++);
}
}
}
}
}
}
if (isJIT) {
printf("}\nvoid gen(){\n");
for (int i = 0; i < funcNum; i++) {
printf(" gen%d();\n", i);
}
printf("}\n");
}
}
int main(int argc, char *argv[])
@ -60,6 +78,7 @@ int main(int argc, char *argv[])
bool isJIT = (argc > 1);
fprintf(stderr, "phase:%c %s\n", phase ? '1' : '2', isJIT ? "jit" : "asm");
if (phase) {
fprintf(stderr, "32bit reg\n");
static const char reg32Tbl[][5] = {
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
#ifdef XBYAK64
@ -69,6 +88,7 @@ int main(int argc, char *argv[])
genAddress(isJIT, reg32Tbl, NUM_OF_ARRAY(reg32Tbl));
} else {
#ifdef XBYAK64
fprintf(stderr, "64bit reg\n");
static const char reg64Tbl[][5] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
};

View file

@ -1,4 +1,5 @@
#include <stdio.h>
#include <string.h>
#include "xbyak/xbyak.h"
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
@ -82,13 +83,13 @@ int main()
{ 127, false, true, "EB7F" },
{ 128, false, false, "E980000000" },
};
for (int i = 0; i < NUM_OF_ARRAY(tbl); i++) {
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
TestJmp jmp(p->offset, p->isBack, p->isShort);
const uint8 *q = (const uint8*)jmp.getCode();
char buf[32];
if (p->isBack) q += p->offset; /* skip nop */
for (int j = 0; j < jmp.getSize() - p->offset; j++) {
for (size_t j = 0; j < jmp.getSize() - p->offset; j++) {
sprintf(&buf[j * 2], "%02X", q[j]);
}
if (strcmp(buf, p->result) != 0) {

View file

@ -62,6 +62,7 @@ const uint64 NOPARA = 1ULL << (bitEnd - 1);
class Test {
const bool isXbyak_;
int funcNum_;
// check all op1, op2, op3
void put(const char *nm, uint64 op1 = NOPARA, uint64 op2 = NOPARA, uint64 op3 = NOPARA) const
{
@ -811,6 +812,31 @@ class Test {
put(p, REG8|REG8_3|MEM, REG8|REG8_3);
put(p, REG32e|REG16|REG8|REG8_3|EAX|AX|AL|MEM32|MEM16|MEM8, IMM);
}
void putMov64() const
{
const struct {
const char *a;
const char *b;
} tbl[] = {
{ "0", "dword 0" },
{ "0x123", "dword 0x123" },
{ "0x12345678", "dword 0x12345678" },
{ "0x7fffffff", "dword 0x7fffffff" },
{ "0xffffffff", "0xffffffff" },
{ "0x80000000", "0x80000000" },
{ "2147483648U", "2147483648" },
{ "0x80000001", "0x80000001" },
{ "0xffffffffffffffff", "dword 0xffffffffffffffff" },
{ "-1", "dword -1" },
{ "0xffffffff80000000", "dword 0xffffffff80000000" },
{ "0xffffffff80000001", "dword 0xffffffff80000001" },
{ "0xffffffff12345678", "0xffffffff12345678" },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
put("mov", REG64, tbl[i].a, tbl[i].b);
}
put("mov", REG32e|REG16|REG8|RAX|EAX|AX|AL, IMM);
}
void putEtc() const
{
const char *p = "ret";
@ -821,7 +847,7 @@ class Test {
put(p, REG64|MEM|MEM_ONLY_DISP, REG64|RAX);
put(p, AX|REG16|MEM|MEM_ONLY_DISP, REG16|AX);
put(p, AL|REG8|REG8_3|MEM|MEM_ONLY_DISP, REG8|REG8_3|AL);
put(p, REG32e|REG16|REG8|RAX|EAX|AX|AL, MEM|IMM|MEM_ONLY_DISP);
put(p, REG32e|REG16|REG8|RAX|EAX|AX|AL, MEM|MEM_ONLY_DISP);
put(p, MEM32|MEM16|MEM8, IMM);
put(p, REG64, "0x1234567890abcdefLL", "0x1234567890abcdef");
#ifdef XBYAK64
@ -1117,32 +1143,72 @@ class Test {
public:
Test(bool isXbyak)
: isXbyak_(isXbyak)
, funcNum_(1)
{
if (!isXbyak_) return;
printf("%s",
" void gen0()\n"
" {\n");
}
void put() const
/*
gcc and vc give up to compile this source,
so I split functions.
*/
void separateFunc()
{
if (!isXbyak_) return;
printf(
" }\n"
" void gen%d()\n"
" {\n", funcNum_++);
}
~Test()
{
if (!isXbyak_) return;
printf("%s",
" }\n"
" void gen()\n"
" {\n");
for (int i = 0; i < funcNum_; i++) {
printf(
" gen%d();\n", i);
}
printf(
" }\n");
}
void put()
{
#ifndef USE_YASM
putSIMPLE();
putReg1();
putRorM();
separateFunc();
putPushPop();
putTest();
separateFunc();
putEtc();
putShift();
putShxd();
separateFunc();
putBs();
putMMX1();
putMMX2();
separateFunc();
putMMX3();
putMMX4();
putMMX5();
separateFunc();
putXMM1();
putXMM2();
putXMM3();
putXMM4();
separateFunc();
putCmov();
putFpuMem16_32();
putFpuMem32_64();
separateFunc();
putFpuMem16_32_64();
put("clflush", MEM); // current nasm is ok
putFpu();
@ -1150,7 +1216,9 @@ public:
putFpuFpu();
putSSSE3();
putSSE4_1();
separateFunc();
putSSE4_2();
putMov64();
#endif
}
};
@ -1160,4 +1228,3 @@ int main(int argc, char *[])
Test test(argc > 1);
test.put();
}

File diff suppressed because it is too large Load diff

View file

@ -6,21 +6,9 @@ using namespace Xbyak;
class Sample : public CodeGenerator {
void operator=(const Sample&);
public:
void gen()
{
try {
#include "nm.cpp"
} catch (Xbyak::Error err) {
printf("ERR:%s(%d)\n", ConvertErrorToString(err), err);
} catch (...) {
printf("unkwon error\n");
}
}
};
#define _STR(x) #x
#define TEST(syntax) err = true; try { syntax; err = false; } catch (Xbyak::Error) { } catch (...) { } if (!err) printf("should be err:%s;\n", _STR(syntax))
@ -38,8 +26,14 @@ public:
};
int main()
{
Sample s;
s.gen();
try {
Sample s;
s.gen();
} catch (Xbyak::Error err) {
printf("ERR:%s(%d)\n", Xbyak::ConvertErrorToString(err), err);
} catch (...) {
printf("unknown error\n");
}
ErrorSample es;
es.gen();
}

View file

@ -3,7 +3,7 @@ if /i "%1"=="64" (
set OPT2=-DXBYAK64
set OPT3=win64
) else (
set OPT2=
set OPT2=-DXBYAK32
set OPT3=win32
)
@ -20,12 +20,16 @@ if /i "%1"=="64" (
goto end
:sub
echo cl address.cpp %OPT% %OPT2%
cl address.cpp %OPT% %OPT2%
address %1% > a.asm
echo nasm -f %OPT3% -l a.lst a.asm
nasm -f %OPT3% -l a.lst a.asm
awk "{print $3}" < a.lst > ok.lst
echo address %1% jit > nm.cpp
address %1% jit > nm.cpp
cl -I../ -DTEST_NM nm_frame.cpp %OPT% %OPT2%
echo cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
nm_frame > x.lst
diff x.lst ok.lst
wc x.lst

View file

@ -1,5 +1,5 @@
pushd ..\gen
call update
popd
cl -I../ -DTEST_NM jmp.cpp %OPT%
cl -I../ -DXBYAK_TEST jmp.cpp %OPT%
jmp

View file

@ -18,8 +18,8 @@ if /i "%1"=="Y" (
set OPT3=win64
set FILTER=normalize_prefix
) else (
set EXE=nasm.exe -DXBYAK32
set OPT2=
set EXE=nasm.exe
set OPT2=-DXBYAK32
set OPT3=win32
)
pushd ..\gen
@ -36,7 +36,7 @@ if /i "%Y%"=="1" (
awk "{if (index($3, ""-"")) { conti=substr($3, 0, length($3) - 1) } else { conti = conti $3; print conti; conti = """" }} " < a.lst |%FILTER% > ok.lst
)
make_nm jit > nm.cpp
cl -I../ -DTEST_NM nm_frame.cpp %OPT% %OPT2%
cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
nm_frame |%FILTER% > x.lst
diff x.lst ok.lst
wc x.lst

View file

@ -36,7 +36,7 @@ awk '{if (index($3, "-")) { conti=substr($3, 0, length($3) - 1) } else { conti =
echo "xbyak"
./make_nm jit > nm.cpp
echo "compile nm_frame.cpp"
g++ $CFLAGS -DTEST_NM nm_frame.cpp -o nm_frame
g++ $CFLAGS -DXBYAK_TEST nm_frame.cpp -o nm_frame
./nm_frame | $FILTER > x.lst
diff ok.lst x.lst && echo "ok"
exit 0

View file

@ -4,9 +4,9 @@
@file xbyak.h
@brief Xbyak ; JIT assembler for x86(IA32)/x64 by C++
@author herumi
@version $Revision: 1.188 $
@version $Revision: 1.191 $
@url http://homepage1.nifty.com/herumi/soft/xbyak.html
@date $Date: 2010/05/24 06:13:44 $
@date $Date: 2010/06/01 05:26:11 $
@note modified new BSD license
http://www.opensource.org/licenses/bsd-license.php
*/
@ -55,7 +55,7 @@ namespace Xbyak {
enum {
DEFAULT_MAX_CODE_SIZE = 2048,
VERSION = 0x2260, /* 0xABCD = A.BC(D) */
VERSION = 0x2270, /* 0xABCD = A.BC(D) */
};
#ifndef MIE_INTEGER_TYPE_DEFINED
@ -144,7 +144,7 @@ namespace inner {
enum { debug = 1 };
static inline uint32 GetPtrDist(const void *p1, const void *p2 = 0)
static inline uint32 GetPtrDist(const void *p1, const void *p2)
{
uint64 diff = static_cast<const char *>(p1) - static_cast<const char *>(p2);
#ifdef XBYAK64
@ -154,6 +154,7 @@ static inline uint32 GetPtrDist(const void *p1, const void *p2 = 0)
}
static inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; }
static inline bool IsInInt32(uint64 x) { return 0xFFFFFFFF80000000ULL <= x || x <= 0x7FFFFFFFU; }
}
@ -555,7 +556,11 @@ public:
explicit AddressFrame(uint32 bit) : bit_(bit) { }
Address operator[](const void *disp) const
{
Reg32e r(Reg(), Reg(), 0, inner::GetPtrDist(disp));
size_t adr = reinterpret_cast<size_t>(disp);
#ifdef XBYAK64
if (adr > 0xFFFFFFFFU) throw ERR_OFFSET_IS_TOO_BIG;
#endif
Reg32e r(Reg(), Reg(), 0, adr);
return operator[](r);
}
#ifdef XBYAK64
@ -1216,13 +1221,32 @@ protected:
opRM_RM(reg1, reg2, B10001000);
}
}
void mov(const Operand& op, uint64 imm)
void mov(const Operand& op,
#ifdef XBYAK64
uint64
#else
uint32
#endif
imm)
{
verifyMemHasSize(op);
if (op.isREG()) {
int w = op.isBit(8) ? 0 : 1;
rex(op); db(B10110000 | (w << 3) | (op.getIdx() & 7));
db(imm, op.getBit() / 8);
rex(op);
int code, size;
#ifdef XBYAK64
if (op.isBit(64) && inner::IsInInt32(imm)) {
db(B11000111);
code = B11000000;
size = 4;
} else
#endif
{
code = B10110000 | ((op.isBit(8) ? 0 : 1) << 3);
size = op.getBit() / 8;
}
db(code | (op.getIdx() & 7));
db(imm, size);
} else if (op.isMEM()) {
opModM(static_cast<const Address&>(op), Reg(0, Operand::REG, op.getBit()), B11000110);
int size = op.getBit() / 8; if (size > 4) size = 4;
@ -1398,7 +1422,7 @@ public:
// if (hasUndefinedLabel()) throw ERR_LABEL_IS_NOT_FOUND;
return top_;
}
#ifdef TEST_NM
#ifdef XBYAK_TEST
void dump(bool doClear = true)
{
CodeArray::dump();

View file

@ -1,4 +1,4 @@
const char *getVersionString() const { return "2.26"; }
const char *getVersionString() const { return "2.27"; }
void packssdw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x6B); }
void packsswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x63); }
void packuswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x67); }

View file

@ -95,25 +95,25 @@ public:
if (data[2] == get32bitAsBE(amd)) {
type_ |= tAMD;
getCpuid(0x80000001, data);
if (data[3] & (1 << 31)) type_ |= t3DN;
if (data[3] & (1 << 15)) type_ |= tCMOV;
if (data[3] & (1 << 30)) type_ |= tE3DN;
if (data[3] & (1 << 22)) type_ |= tMMX2;
if (data[3] & (1U << 31)) type_ |= t3DN;
if (data[3] & (1U << 15)) type_ |= tCMOV;
if (data[3] & (1U << 30)) type_ |= tE3DN;
if (data[3] & (1U << 22)) type_ |= tMMX2;
}
if (data[2] == get32bitAsBE(intel)) {
type_ |= tINTEL;
}
getCpuid(1, data);
if (data[2] & (1 << 0)) type_ |= tSSE3;
if (data[2] & (1 << 9)) type_ |= tSSSE3;
if (data[2] & (1 << 19)) type_ |= tSSE41;
if (data[2] & (1 << 20)) type_ |= tSSE42;
if (data[2] & (1 << 23)) type_ |= tPOPCNT;
if (data[2] & (1U << 0)) type_ |= tSSE3;
if (data[2] & (1U << 9)) type_ |= tSSSE3;
if (data[2] & (1U << 19)) type_ |= tSSE41;
if (data[2] & (1U << 20)) type_ |= tSSE42;
if (data[2] & (1U << 23)) type_ |= tPOPCNT;
if (data[3] & (1 << 15)) type_ |= tCMOV;
if (data[3] & (1 << 23)) type_ |= tMMX;
if (data[3] & (1 << 25)) type_ |= tMMX2 | tSSE;
if (data[3] & (1 << 26)) type_ |= tSSE2;
if (data[3] & (1U << 15)) type_ |= tCMOV;
if (data[3] & (1U << 23)) type_ |= tMMX;
if (data[3] & (1U << 25)) type_ |= tMMX2 | tSSE;
if (data[3] & (1U << 26)) type_ |= tSSE2;
}
bool has(Type type) const
{