#pragma once //{ alwaysinline auto clc() { emit.byte(0xf8); } alwaysinline auto cmc() { emit.byte(0xf5); } alwaysinline auto lahf() { emit.byte(0x9f); } alwaysinline auto sahf() { emit.byte(0x9e); } alwaysinline auto stc() { emit.byte(0xf9); } alwaysinline auto ret() { emit.byte(0xc3); } //call imm32 alwaysinline auto call(imm32 it) { emit.byte(0xe8); emit.dword(it.data); } //jmp imm32 alwaysinline auto jmp(imm32 it) { emit.byte(0xe9); emit.dword(it.data); } //call reg64 alwaysinline auto call(reg64 rt) { emit.rex(0, 0, 0, rt & 8); emit.byte(0xff); emit.modrm(3, 2, rt & 7); } //lea reg64,[reg64+imm8] alwaysinline auto lea(reg64 rt, dis8 ds) { emit.rex(1, rt & 8, 0, ds.reg & 8); emit.byte(0x8d); emit.modrm(1, rt & 7, ds.reg & 7); if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); emit.byte(ds.imm); } //lea reg64,[reg64+imm32] alwaysinline auto lea(reg64 rt, dis32 ds) { emit.rex(1, rt & 8, 0, ds.reg & 8); emit.byte(0x8d); emit.modrm(2, rt & 7, ds.reg & 7); if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); emit.dword(ds.imm); } //mov reg8,imm8 alwaysinline auto mov(reg8 rt, imm8 is) { emit.rex(0, 0, 0, rt & 8); emit.byte(0xb0 | rt & 7); emit.byte(is.data); } //mov reg32,imm32 alwaysinline auto mov(reg32 rt, imm32 is) { emit.rex(0, 0, 0, rt & 8); emit.byte(0xb8 | rt & 7); emit.dword(is.data); } //mov reg64,imm32 alwaysinline auto mov(reg64 rt, imm32 is) { emit.rex(1, 0, 0, rt & 8); emit.byte(0xc7); emit.modrm(3, 0, rt & 7); emit.dword(is.data); } //mov reg64,imm64 alwaysinline auto mov(reg64 rt, imm64 is) { emit.rex(1, 0, 0, rt & 8); emit.byte(0xb8 | rt & 7); emit.qword(is.data); } //mov reg8,[mem64] alwaysinline auto mov(reg8 rt, mem64 ps) { if(unlikely(rt != al)) throw; emit.byte(0xa0); emit.qword(ps.data); } //mov reg16,[mem64] alwaysinline auto mov(reg16 rt, mem64 ps) { if(unlikely(rt != ax)) throw; emit.byte(0x66, 0xa1); emit.qword(ps.data); } //mov reg32,[mem64] alwaysinline auto mov(reg32 rt, mem64 ps) { if(unlikely(rt != eax)) throw; emit.byte(0xa1); emit.qword(ps.data); } //mov reg64,[mem64] alwaysinline auto mov(reg64 rt, mem64 ps) { if(unlikely(rt != rax)) throw; emit.rex(1, 0, 0, 0); emit.byte(0xa1); emit.qword(ps.data); } //mov [mem64],reg8 alwaysinline auto mov(mem64 pt, reg8 rs) { if(unlikely(rs != al)) throw; emit.byte(0xa2); emit.qword(pt.data); } //mov [mem64+imm8],imm8 alwaysinline auto movb(dis8 dt, imm8 is) { emit.rex(0, 0, 0, dt.reg & 8); emit.byte(0xc6); emit.modrm(1, 0, dt.reg & 7); if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); emit.byte(dt.imm); emit.byte(is.data); } //mov [mem64],reg16 alwaysinline auto mov(mem64 pt, reg16 rs) { if(unlikely(rs != ax)) throw; emit.byte(0x66, 0xa3); emit.qword(pt.data); } //mov [mem64],reg32 alwaysinline auto mov(mem64 pt, reg32 rs) { if(unlikely(rs != eax)) throw; emit.byte(0xa3); emit.qword(pt.data); } //mov [mem64],reg64 alwaysinline auto mov(mem64 pt, reg64 rs) { if(unlikely(rs != rax)) throw; emit.rex(1, 0, 0, 0); emit.byte(0xa3); emit.qword(pt.data); } //op reg8,[reg64] #define op(code) \ emit.rex(0, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(0, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); alwaysinline auto adc(reg8 rt, dis ds) { op(0x12); } alwaysinline auto add(reg8 rt, dis ds) { op(0x02); } alwaysinline auto and_(reg8 rt, dis ds) { op(0x22); } alwaysinline auto cmp(reg8 rt, dis ds) { op(0x3a); } alwaysinline auto mov(reg8 rt, dis ds) { op(0x8a); } alwaysinline auto or_(reg8 rt, dis ds) { op(0x0a); } alwaysinline auto sbb(reg8 rt, dis ds) { op(0x1a); } alwaysinline auto sub(reg8 rt, dis ds) { op(0x2a); } alwaysinline auto xor_(reg8 rt, dis ds) { op(0x32); } #undef op //op reg8,[reg64+imm8] #define op(code) \ emit.rex(0, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(1, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); \ emit.byte(ds.imm); alwaysinline auto adc(reg8 rt, dis8 ds) { op(0x12); } alwaysinline auto add(reg8 rt, dis8 ds) { op(0x02); } alwaysinline auto and_(reg8 rt, dis8 ds) { op(0x22); } alwaysinline auto cmp(reg8 rt, dis8 ds) { op(0x3a); } alwaysinline auto mov(reg8 rt, dis8 ds) { op(0x8a); } alwaysinline auto or_(reg8 rt, dis8 ds) { op(0x0a); } alwaysinline auto sbb(reg8 rt, dis8 ds) { op(0x1a); } alwaysinline auto sub(reg8 rt, dis8 ds) { op(0x2a); } alwaysinline auto xor_(reg8 rt, dis8 ds) { op(0x32); } #undef op //op reg32,[reg64] #define op(code) \ emit.rex(0, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(0, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); alwaysinline auto adc(reg32 rt, dis ds) { op(0x13); } alwaysinline auto add(reg32 rt, dis ds) { op(0x03); } alwaysinline auto and_(reg32 rt, dis ds) { op(0x23); } alwaysinline auto cmp(reg32 rt, dis ds) { op(0x3b); } alwaysinline auto mov(reg32 rt, dis ds) { op(0x8b); } alwaysinline auto or_(reg32 rt, dis ds) { op(0x0b); } alwaysinline auto sbb(reg32 rt, dis ds) { op(0x1b); } alwaysinline auto sub(reg32 rt, dis ds) { op(0x2b); } alwaysinline auto xor_(reg32 rt, dis ds) { op(0x33); } #undef op //op reg32,[reg64+imm8] #define op(code) \ emit.rex(0, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(1, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); \ emit.byte(ds.imm); alwaysinline auto adc(reg32 rt, dis8 ds) { op(0x13); } alwaysinline auto add(reg32 rt, dis8 ds) { op(0x03); } alwaysinline auto and_(reg32 rt, dis8 ds) { op(0x23); } alwaysinline auto cmp(reg32 rt, dis8 ds) { op(0x3b); } alwaysinline auto mov(reg32 rt, dis8 ds) { op(0x8b); } alwaysinline auto or_(reg32 rt, dis8 ds) { op(0x0b); } alwaysinline auto sbb(reg32 rt, dis8 ds) { op(0x1b); } alwaysinline auto sub(reg32 rt, dis8 ds) { op(0x2b); } alwaysinline auto xor_(reg32 rt, dis8 ds) { op(0x33); } #undef op //op reg64,[reg64] #define op(code) \ emit.rex(1, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(0, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); alwaysinline auto adc(reg64 rt, dis ds) { op(0x13); } alwaysinline auto add(reg64 rt, dis ds) { op(0x03); } alwaysinline auto and_(reg64 rt, dis ds) { op(0x23); } alwaysinline auto cmp(reg64 rt, dis ds) { op(0x3b); } alwaysinline auto mov(reg64 rt, dis ds) { op(0x8b); } alwaysinline auto or_(reg64 rt, dis ds) { op(0x0b); } alwaysinline auto sbb(reg64 rt, dis ds) { op(0x1b); } alwaysinline auto sub(reg64 rt, dis ds) { op(0x2b); } alwaysinline auto xor_(reg64 rt, dis ds) { op(0x33); } #undef op //op reg64,[reg64+imm8] #define op(code) \ emit.rex(1, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(1, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); \ emit.byte(ds.imm); alwaysinline auto adc(reg64 rt, dis8 ds) { op(0x13); } alwaysinline auto add(reg64 rt, dis8 ds) { op(0x03); } alwaysinline auto and_(reg64 rt, dis8 ds) { op(0x23); } alwaysinline auto cmp(reg64 rt, dis8 ds) { op(0x3b); } alwaysinline auto mov(reg64 rt, dis8 ds) { op(0x8b); } alwaysinline auto or_(reg64 rt, dis8 ds) { op(0x0b); } alwaysinline auto sbb(reg64 rt, dis8 ds) { op(0x1b); } alwaysinline auto sub(reg64 rt, dis8 ds) { op(0x2b); } alwaysinline auto xor_(reg64 rt, dis8 ds) { op(0x33); } #undef op //op reg64,[reg64+imm32] #define op(code) \ emit.rex(1, rt & 8, 0, ds.reg & 8); \ emit.byte(code); \ emit.modrm(2, rt & 7, ds.reg & 7); \ if(ds.reg == rsp || ds.reg == r12) emit.sib(0, 4, 4); \ emit.dword(ds.imm); alwaysinline auto adc(reg64 rt, dis32 ds) { op(0x13); } alwaysinline auto add(reg64 rt, dis32 ds) { op(0x03); } alwaysinline auto and_(reg64 rt, dis32 ds) { op(0x23); } alwaysinline auto cmp(reg64 rt, dis32 ds) { op(0x3b); } alwaysinline auto mov(reg64 rt, dis32 ds) { op(0x8b); } alwaysinline auto or_(reg64 rt, dis32 ds) { op(0x0b); } alwaysinline auto sbb(reg64 rt, dis32 ds) { op(0x1b); } alwaysinline auto sub(reg64 rt, dis32 ds) { op(0x2b); } alwaysinline auto xor_(reg64 rt, dis32 ds) { op(0x33); } #undef op //op [reg64+imm8],reg8 #define op(code) \ emit.rex(0, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(1, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); \ emit.byte(dt.imm); alwaysinline auto adc(dis8 dt, reg8 rs) { op(0x10); } alwaysinline auto add(dis8 dt, reg8 rs) { op(0x00); } alwaysinline auto and_(dis8 dt, reg8 rs) { op(0x20); } alwaysinline auto cmp(dis8 dt, reg8 rs) { op(0x38); } alwaysinline auto mov(dis8 dt, reg8 rs) { op(0x88); } alwaysinline auto or_(dis8 dt, reg8 rs) { op(0x08); } alwaysinline auto sbb(dis8 dt, reg8 rs) { op(0x18); } alwaysinline auto sub(dis8 dt, reg8 rs) { op(0x28); } alwaysinline auto xor_(dis8 dt, reg8 rs) { op(0x30); } #undef op //op reg64,imm32 #define op(group) \ emit.rex(1, 0, 0, rt & 8); \ emit.byte(0x81); \ emit.modrm(3, group, rt & 7); \ emit.dword(is.data); alwaysinline auto add(reg64 rt, imm32 is) { op(0); } alwaysinline auto or_(reg64 rt, imm32 is) { op(1); } alwaysinline auto adc(reg64 rt, imm32 is) { op(2); } alwaysinline auto sbb(reg64 rt, imm32 is) { op(3); } alwaysinline auto and_(reg64 rt, imm32 is) { op(4); } alwaysinline auto sub(reg64 rt, imm32 is) { op(5); } alwaysinline auto xor_(reg64 rt, imm32 is) { op(6); } alwaysinline auto cmp(reg64 rt, imm32 is) { op(7); } #undef op //op.d [reg64+imm8],imm8 #define op(group) \ emit.rex(0, 0, 0, dt.reg & 8); \ emit.byte(0x83); \ emit.modrm(1, group, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); \ emit.byte(dt.imm); \ emit.byte(is.data); alwaysinline auto addd(dis8 dt, imm8 is) { op(0); } alwaysinline auto ord (dis8 dt, imm8 is) { op(1); } alwaysinline auto adcd(dis8 dt, imm8 is) { op(2); } alwaysinline auto sbbd(dis8 dt, imm8 is) { op(3); } alwaysinline auto andd(dis8 dt, imm8 is) { op(4); } alwaysinline auto subd(dis8 dt, imm8 is) { op(5); } alwaysinline auto xord(dis8 dt, imm8 is) { op(6); } alwaysinline auto cmpd(dis8 dt, imm8 is) { op(7); } #undef op //op [reg64],reg32 #define op(code) \ emit.rex(0, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(0, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); alwaysinline auto adc(dis dt, reg32 rs) { op(0x11); } alwaysinline auto add(dis dt, reg32 rs) { op(0x01); } alwaysinline auto and_(dis dt, reg32 rs) { op(0x21); } alwaysinline auto cmp(dis dt, reg32 rs) { op(0x39); } alwaysinline auto mov(dis dt, reg32 rs) { op(0x89); } alwaysinline auto or_(dis dt, reg32 rs) { op(0x09); } alwaysinline auto sbb(dis dt, reg32 rs) { op(0x19); } alwaysinline auto sub(dis dt, reg32 rs) { op(0x29); } alwaysinline auto xor_(dis dt, reg32 rs) { op(0x31); } #undef op //op [reg64+imm8],reg32 #define op(code) \ emit.rex(0, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(1, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); \ emit.byte(dt.imm); alwaysinline auto adc(dis8 dt, reg32 rs) { op(0x11); } alwaysinline auto add(dis8 dt, reg32 rs) { op(0x01); } alwaysinline auto and_(dis8 dt, reg32 rs) { op(0x21); } alwaysinline auto cmp(dis8 dt, reg32 rs) { op(0x39); } alwaysinline auto mov(dis8 dt, reg32 rs) { op(0x89); } alwaysinline auto or_(dis8 dt, reg32 rs) { op(0x09); } alwaysinline auto sbb(dis8 dt, reg32 rs) { op(0x19); } alwaysinline auto sub(dis8 dt, reg32 rs) { op(0x29); } alwaysinline auto xor_(dis8 dt, reg32 rs) { op(0x31); } #undef op //op [reg64],reg64 #define op(code) \ emit.rex(0, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(0, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); alwaysinline auto adc(dis dt, reg64 rs) { op(0x11); } alwaysinline auto add(dis dt, reg64 rs) { op(0x01); } alwaysinline auto and_(dis dt, reg64 rs) { op(0x21); } alwaysinline auto cmp(dis dt, reg64 rs) { op(0x39); } alwaysinline auto mov(dis dt, reg64 rs) { op(0x89); } alwaysinline auto or_(dis dt, reg64 rs) { op(0x09); } alwaysinline auto sbb(dis dt, reg64 rs) { op(0x19); } alwaysinline auto sub(dis dt, reg64 rs) { op(0x29); } alwaysinline auto xor_(dis dt, reg64 rs) { op(0x31); } #undef op //op [reg64+imm8],reg64 #define op(code) \ emit.rex(1, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(1, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); \ emit.byte(dt.imm); alwaysinline auto adc(dis8 dt, reg64 rs) { op(0x11); } alwaysinline auto add(dis8 dt, reg64 rs) { op(0x01); } alwaysinline auto and_(dis8 dt, reg64 rs) { op(0x21); } alwaysinline auto cmp(dis8 dt, reg64 rs) { op(0x39); } alwaysinline auto mov(dis8 dt, reg64 rs) { op(0x89); } alwaysinline auto or_(dis8 dt, reg64 rs) { op(0x09); } alwaysinline auto sbb(dis8 dt, reg64 rs) { op(0x19); } alwaysinline auto sub(dis8 dt, reg64 rs) { op(0x29); } alwaysinline auto xor_(dis8 dt, reg64 rs) { op(0x31); } #undef op //op [reg64+imm32],reg64 #define op(code) \ emit.rex(1, rs & 8, 0, dt.reg & 8); \ emit.byte(code); \ emit.modrm(2, rs & 7, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); \ emit.dword(dt.imm); alwaysinline auto adc(dis32 dt, reg64 rs) { op(0x11); } alwaysinline auto add(dis32 dt, reg64 rs) { op(0x01); } alwaysinline auto and_(dis32 dt, reg64 rs) { op(0x21); } alwaysinline auto cmp(dis32 dt, reg64 rs) { op(0x39); } alwaysinline auto mov(dis32 dt, reg64 rs) { op(0x89); } alwaysinline auto or_(dis32 dt, reg64 rs) { op(0x09); } alwaysinline auto sbb(dis32 dt, reg64 rs) { op(0x19); } alwaysinline auto sub(dis32 dt, reg64 rs) { op(0x29); } alwaysinline auto xor_(dis32 dt, reg64 rs) { op(0x31); } #undef op //op reg32,reg8 #define op(code) \ emit.rex(0, rt & 8, 0, rs & 8); \ emit.byte(0x0f, code); \ emit.modrm(3, rt & 7, rs & 7); alwaysinline auto movsx(reg32 rt, reg8 rs) { op(0xbe); } alwaysinline auto movzx(reg32 rt, reg8 rs) { op(0xb6); } #undef op //op reg32,reg16 #define op(code) \ emit.rex(0, rt & 8, 0, rs & 8); \ emit.byte(0x0f, code); \ emit.modrm(3, rt & 7, rs & 7); alwaysinline auto movsx(reg32 rt, reg16 rs) { op(0xbf); } alwaysinline auto movzx(reg32 rt, reg16 rs) { op(0xb7); } #undef op alwaysinline auto movsxd(reg64 rt, reg32 rs) { emit.rex(1, rt & 8, 0, rs & 8); emit.byte(0x63); emit.modrm(3, rt & 7, rs & 7); } //incd [reg64+imm8] alwaysinline auto incd(dis8 dt) { emit.rex(0, 0, 0, dt.reg & 8); emit.byte(0xff); emit.modrm(1, 0, dt.reg & 7); if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); emit.byte(dt.imm); } //decd [reg64+imm8] alwaysinline auto decd(dis8 dt) { emit.rex(0, 0, 0, dt.reg & 8); emit.byte(0xff); emit.modrm(1, 1, dt.reg & 7); if(dt.reg == rsp || dt.reg == r12) emit.sib(0, 4, 4); emit.byte(dt.imm); } //inc reg32 alwaysinline auto inc(reg32 rt) { emit.rex(0, 0, 0, rt & 8); emit.byte(0xff); emit.modrm(3, 0, rt & 7); } //dec reg32 alwaysinline auto dec(reg32 rt) { emit.rex(0, 0, 0, rt & 8); emit.byte(0xff); emit.modrm(3, 1, rt & 7); } //inc reg64 alwaysinline auto inc(reg64 rt) { emit.rex(1, 0, 0, rt & 8); emit.byte(0xff); emit.modrm(3, 0, rt & 7); } //dec reg64 alwaysinline auto dec(reg64 rt) { emit.rex(1, 0, 0, rt & 8); emit.byte(0xff); emit.modrm(3, 1, rt & 7); } #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0xd0); \ emit.modrm(3, code, rt & 7); alwaysinline auto rol(reg8 rt) { op(0); } alwaysinline auto ror(reg8 rt) { op(1); } alwaysinline auto rcl(reg8 rt) { op(2); } alwaysinline auto rcr(reg8 rt) { op(3); } alwaysinline auto shl(reg8 rt) { op(4); } alwaysinline auto shr(reg8 rt) { op(5); } alwaysinline auto sal(reg8 rt) { op(6); } alwaysinline auto sar(reg8 rt) { op(7); } #undef op #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0xd1); \ emit.modrm(3, code, rt & 7); alwaysinline auto rol(reg32 rt) { op(0); } alwaysinline auto ror(reg32 rt) { op(1); } alwaysinline auto rcl(reg32 rt) { op(2); } alwaysinline auto rcr(reg32 rt) { op(3); } alwaysinline auto shl(reg32 rt) { op(4); } alwaysinline auto shr(reg32 rt) { op(5); } alwaysinline auto sal(reg32 rt) { op(6); } alwaysinline auto sar(reg32 rt) { op(7); } #undef op #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0xc1); \ emit.modrm(3, code, rt & 7); \ emit.byte(is.data); alwaysinline auto rol(reg32 rt, imm8 is) { op(0); } alwaysinline auto ror(reg32 rt, imm8 is) { op(1); } alwaysinline auto rcl(reg32 rt, imm8 is) { op(2); } alwaysinline auto rcr(reg32 rt, imm8 is) { op(3); } alwaysinline auto shl(reg32 rt, imm8 is) { op(4); } alwaysinline auto shr(reg32 rt, imm8 is) { op(5); } alwaysinline auto sal(reg32 rt, imm8 is) { op(6); } alwaysinline auto sar(reg32 rt, imm8 is) { op(7); } #undef op #define op(code) \ if(unlikely(rs != cl)) throw; \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0xd3); \ emit.modrm(3, code, rt & 7); alwaysinline auto rol(reg32 rt, reg8 rs) { op(0); } alwaysinline auto ror(reg32 rt, reg8 rs) { op(1); } alwaysinline auto rcl(reg32 rt, reg8 rs) { op(2); } alwaysinline auto rcr(reg32 rt, reg8 rs) { op(3); } alwaysinline auto shl(reg32 rt, reg8 rs) { op(4); } alwaysinline auto shr(reg32 rt, reg8 rs) { op(5); } alwaysinline auto sal(reg32 rt, reg8 rs) { op(6); } alwaysinline auto sar(reg32 rt, reg8 rs) { op(7); } #undef op #define op(code) \ emit.rex(1, 0, 0, rt & 8); \ emit.byte(0xc1); \ emit.modrm(3, code, rt & 7); \ emit.byte(is.data); alwaysinline auto rol(reg64 rt, imm8 is) { op(0); } alwaysinline auto ror(reg64 rt, imm8 is) { op(1); } alwaysinline auto rcl(reg64 rt, imm8 is) { op(2); } alwaysinline auto rcr(reg64 rt, imm8 is) { op(3); } alwaysinline auto shl(reg64 rt, imm8 is) { op(4); } alwaysinline auto shr(reg64 rt, imm8 is) { op(5); } alwaysinline auto sal(reg64 rt, imm8 is) { op(6); } alwaysinline auto sar(reg64 rt, imm8 is) { op(7); } #undef op #define op(code) \ if(unlikely(rs != cl)) throw; \ emit.rex(1, 0, 0, rt & 8); \ emit.byte(0xd3); \ emit.modrm(3, code, rt & 7); alwaysinline auto rol(reg64 rt, reg8 rs) { op(0); } alwaysinline auto ror(reg64 rt, reg8 rs) { op(1); } alwaysinline auto rcl(reg64 rt, reg8 rs) { op(2); } alwaysinline auto rcr(reg64 rt, reg8 rs) { op(3); } alwaysinline auto shl(reg64 rt, reg8 rs) { op(4); } alwaysinline auto shr(reg64 rt, reg8 rs) { op(5); } alwaysinline auto sal(reg64 rt, reg8 rs) { op(6); } alwaysinline auto sar(reg64 rt, reg8 rs) { op(7); } #undef op //push reg alwaysinline auto push(reg64 rt) { emit.rex(0, 0, 0, rt & 8); emit.byte(0x50 | rt & 7); } //pop reg alwaysinline auto pop(reg64 rt) { emit.rex(0, 0, 0, rt & 8); emit.byte(0x58 | rt & 7); } #define op(code) \ emit.rex(0, rs & 8, 0, rt & 8); \ emit.byte(code); \ emit.modrm(3, rs & 7, rt & 7); alwaysinline auto adc (reg8 rt, reg8 rs) { op(0x10); } alwaysinline auto add (reg8 rt, reg8 rs) { op(0x00); } alwaysinline auto and_(reg8 rt, reg8 rs) { op(0x20); } alwaysinline auto cmp (reg8 rt, reg8 rs) { op(0x38); } alwaysinline auto mov (reg8 rt, reg8 rs) { op(0x88); } alwaysinline auto or_ (reg8 rt, reg8 rs) { op(0x08); } alwaysinline auto sbb (reg8 rt, reg8 rs) { op(0x18); } alwaysinline auto sub (reg8 rt, reg8 rs) { op(0x28); } alwaysinline auto test(reg8 rt, reg8 rs) { op(0x84); } alwaysinline auto xor_(reg8 rt, reg8 rs) { op(0x30); } #undef op #define op(code) \ emit.byte(0x66); \ emit.rex(0, rs & 8, 0, rt & 8); \ emit.byte(code); \ emit.modrm(3, rs & 7, rt & 7); alwaysinline auto adc (reg16 rt, reg16 rs) { op(0x11); } alwaysinline auto add (reg16 rt, reg16 rs) { op(0x01); } alwaysinline auto and_(reg16 rt, reg16 rs) { op(0x21); } alwaysinline auto cmp (reg16 rt, reg16 rs) { op(0x39); } alwaysinline auto mov (reg16 rt, reg16 rs) { op(0x89); } alwaysinline auto or_ (reg16 rt, reg16 rs) { op(0x09); } alwaysinline auto sbb (reg16 rt, reg16 rs) { op(0x19); } alwaysinline auto sub (reg16 rt, reg16 rs) { op(0x29); } alwaysinline auto test(reg16 rt, reg16 rs) { op(0x85); } alwaysinline auto xor_(reg16 rt, reg16 rs) { op(0x31); } #undef op #define op(code) \ emit.rex(0, rs & 8, 0, rt & 8); \ emit.byte(code); \ emit.modrm(3, rs & 7, rt & 7); alwaysinline auto adc (reg32 rt, reg32 rs) { op(0x11); } alwaysinline auto add (reg32 rt, reg32 rs) { op(0x01); } alwaysinline auto and_(reg32 rt, reg32 rs) { op(0x21); } alwaysinline auto cmp (reg32 rt, reg32 rs) { op(0x39); } alwaysinline auto mov (reg32 rt, reg32 rs) { op(0x89); } alwaysinline auto or_ (reg32 rt, reg32 rs) { op(0x09); } alwaysinline auto sbb (reg32 rt, reg32 rs) { op(0x19); } alwaysinline auto sub (reg32 rt, reg32 rs) { op(0x29); } alwaysinline auto test(reg32 rt, reg32 rs) { op(0x85); } alwaysinline auto xor_(reg32 rt, reg32 rs) { op(0x31); } #undef op #define op(code) \ emit.rex(1, rs & 8, 0, rt & 8); \ emit.byte(code); \ emit.modrm(3, rs & 7, rt & 7); alwaysinline auto adc (reg64 rt, reg64 rs) { op(0x11); } alwaysinline auto add (reg64 rt, reg64 rs) { op(0x01); } alwaysinline auto and_(reg64 rt, reg64 rs) { op(0x21); } alwaysinline auto cmp (reg64 rt, reg64 rs) { op(0x39); } alwaysinline auto mov (reg64 rt, reg64 rs) { op(0x89); } alwaysinline auto or_ (reg64 rt, reg64 rs) { op(0x09); } alwaysinline auto sbb (reg64 rt, reg64 rs) { op(0x19); } alwaysinline auto sub (reg64 rt, reg64 rs) { op(0x29); } alwaysinline auto test(reg64 rt, reg64 rs) { op(0x85); } alwaysinline auto xor_(reg64 rt, reg64 rs) { op(0x31); } #undef op #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0x83); \ emit.modrm(3, code, rt & 7); \ emit.byte(is.data); alwaysinline auto adc(reg32 rt, imm8 is) { op(2); } alwaysinline auto add(reg32 rt, imm8 is) { op(0); } alwaysinline auto and_(reg32 rt, imm8 is) { op(4); } alwaysinline auto cmp(reg32 rt, imm8 is) { op(7); } alwaysinline auto or_(reg32 rt, imm8 is) { op(1); } alwaysinline auto sbb(reg32 rt, imm8 is) { op(3); } alwaysinline auto sub(reg32 rt, imm8 is) { op(5); } alwaysinline auto xor_(reg32 rt, imm8 is) { op(6); } #undef op #define op(code) \ emit.rex(1, 0, 0, rt & 8); \ emit.byte(0x83); \ emit.modrm(3, code, rt & 7); \ emit.byte(is.data); alwaysinline auto adc(reg64 rt, imm8 is) { op(2); } alwaysinline auto add(reg64 rt, imm8 is) { op(0); } alwaysinline auto and_(reg64 rt, imm8 is) { op(4); } alwaysinline auto cmp(reg64 rt, imm8 is) { op(7); } alwaysinline auto or_(reg64 rt, imm8 is) { op(1); } alwaysinline auto sbb(reg64 rt, imm8 is) { op(3); } alwaysinline auto sub(reg64 rt, imm8 is) { op(5); } alwaysinline auto xor_(reg64 rt, imm8 is) { op(6); } #undef op #define op(code, group) \ if(rt == al) { \ emit.byte(code); \ emit.byte(is.data); \ } else { \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0x80); \ emit.modrm(3, group, rt & 7); \ emit.byte(is.data); \ } alwaysinline auto adc(reg8 rt, imm8 is) { op(0x14, 2); } alwaysinline auto add(reg8 rt, imm8 is) { op(0x04, 0); } alwaysinline auto and_(reg8 rt, imm8 is) { op(0x24, 4); } alwaysinline auto cmp(reg8 rt, imm8 is) { op(0x3c, 7); } alwaysinline auto or_(reg8 rt, imm8 is) { op(0x0c, 1); } alwaysinline auto sbb(reg8 rt, imm8 is) { op(0x1c, 3); } alwaysinline auto sub(reg8 rt, imm8 is) { op(0x2c, 5); } alwaysinline auto xor_(reg8 rt, imm8 is) { op(0x34, 6); } #undef op #define op(code, group) \ if(rt == eax) { \ emit.byte(code); \ emit.dword(is.data); \ } else { \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0x81); \ emit.modrm(3, group, rt & 7); \ emit.dword(is.data); \ } alwaysinline auto adc(reg32 rt, imm32 is) { op(0x15, 2); } alwaysinline auto add(reg32 rt, imm32 is) { op(0x05, 0); } alwaysinline auto and_(reg32 rt, imm32 is) { op(0x25, 4); } alwaysinline auto cmp(reg32 rt, imm32 is) { op(0x3d, 7); } alwaysinline auto or_(reg32 rt, imm32 is) { op(0x0d, 1); } alwaysinline auto sbb(reg32 rt, imm32 is) { op(0x1d, 3); } alwaysinline auto sub(reg32 rt, imm32 is) { op(0x2d, 5); } alwaysinline auto xor_(reg32 rt, imm32 is) { op(0x35, 6); } #undef op #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0xf7); \ emit.modrm(3, code, rt & 7); alwaysinline auto not_(reg32 rt) { op(2); } alwaysinline auto neg (reg32 rt) { op(3); } alwaysinline auto mul (reg32 rt) { op(4); } alwaysinline auto imul(reg32 rt) { op(5); } alwaysinline auto div (reg32 rt) { op(6); } alwaysinline auto idiv(reg32 rt) { op(7); } #undef op #define op(code) \ emit.rex(1, 0, 0, rt & 8); \ emit.byte(0xf7); \ emit.modrm(3, code, rt & 7); alwaysinline auto not_(reg64 rt) { op(2); } alwaysinline auto neg (reg64 rt) { op(3); } alwaysinline auto mul (reg64 rt) { op(4); } alwaysinline auto imul(reg64 rt) { op(5); } alwaysinline auto div (reg64 rt) { op(6); } alwaysinline auto idiv(reg64 rt) { op(7); } #undef op #define op(code) \ emit.byte(code); \ emit.byte(it.data); #define r imm8 it{resolve(l, 1, 1)} alwaysinline auto jmp (imm8 it) { op(0xeb); } alwaysinline auto jmp8(label l) { r; op(0xeb); } alwaysinline auto jnz (imm8 it) { op(0x75); } alwaysinline auto jnz8(label l) { r; op(0x75); } alwaysinline auto jz (imm8 it) { op(0x74); } alwaysinline auto jz8 (label l) { r; op(0x74); } #undef r #undef op #define op(code) \ emit.byte(0x0f); \ emit.byte(code); \ emit.dword(it.data); #define r imm32 it{resolve(l, 2, 4)} alwaysinline auto jnz(imm32 it) { op(0x85); } alwaysinline auto jnz(label l) { r; op(0x85); } alwaysinline auto jz (imm32 it) { op(0x84); } alwaysinline auto jz (label l) { r; op(0x84); } #undef r #undef op //op reg8 #define op(code) \ emit.rex(0, 0, 0, rt & 8); \ emit.byte(0x0f); \ emit.byte(code); \ emit.modrm(3, 0, rt & 7); alwaysinline auto seta (reg8 rt) { op(0x97); } alwaysinline auto setbe(reg8 rt) { op(0x96); } alwaysinline auto setb (reg8 rt) { op(0x92); } alwaysinline auto setc (reg8 rt) { op(0x92); } alwaysinline auto setg (reg8 rt) { op(0x9f); } alwaysinline auto setge(reg8 rt) { op(0x9d); } alwaysinline auto setl (reg8 rt) { op(0x9c); } alwaysinline auto setle(reg8 rt) { op(0x9e); } alwaysinline auto setnc(reg8 rt) { op(0x93); } alwaysinline auto setno(reg8 rt) { op(0x91); } alwaysinline auto setnp(reg8 rt) { op(0x9b); } alwaysinline auto setns(reg8 rt) { op(0x99); } alwaysinline auto setnz(reg8 rt) { op(0x95); } alwaysinline auto seto (reg8 rt) { op(0x90); } alwaysinline auto setp (reg8 rt) { op(0x9a); } alwaysinline auto sets (reg8 rt) { op(0x98); } alwaysinline auto setz (reg8 rt) { op(0x94); } #undef op //op [reg64] #define op(code) \ emit.rex(0, 0, 0, dt.reg & 8); \ emit.byte(0x0f); \ emit.byte(code); \ if(dt.reg == rsp || dt.reg == r12) { \ emit.modrm(0, 0, dt.reg & 7); \ emit.sib(0, 4, 4); \ } else if(dt.reg == rbp || dt.reg == r13) { \ emit.modrm(1, 0, dt.reg & 7); \ emit.byte(0x00); \ } else { \ emit.modrm(0, 0, dt.reg & 7); \ } alwaysinline auto seta (dis dt) { op(0x97); } alwaysinline auto setbe(dis dt) { op(0x96); } alwaysinline auto setb (dis dt) { op(0x92); } alwaysinline auto setc (dis dt) { op(0x92); } alwaysinline auto setg (dis dt) { op(0x9f); } alwaysinline auto setge(dis dt) { op(0x9d); } alwaysinline auto setl (dis dt) { op(0x9c); } alwaysinline auto setle(dis dt) { op(0x9e); } alwaysinline auto setnc(dis dt) { op(0x93); } alwaysinline auto setno(dis dt) { op(0x91); } alwaysinline auto setnp(dis dt) { op(0x9b); } alwaysinline auto setns(dis dt) { op(0x99); } alwaysinline auto setnz(dis dt) { op(0x95); } alwaysinline auto seto (dis dt) { op(0x90); } alwaysinline auto setp (dis dt) { op(0x9a); } alwaysinline auto sets (dis dt) { op(0x98); } alwaysinline auto setz (dis dt) { op(0x94); } #undef op //op [reg64+imm8] #define op(code) \ emit.rex(0, 0, 0, dt.reg & 8); \ emit.byte(0x0f); \ emit.byte(code); \ emit.modrm(1, 0, dt.reg & 7); \ if(dt.reg == rsp || dt.reg == r12) { \ emit.sib(0, 4, 4); \ } \ emit.byte(dt.imm); alwaysinline auto seta (dis8 dt) { op(0x97); } alwaysinline auto setbe(dis8 dt) { op(0x96); } alwaysinline auto setb (dis8 dt) { op(0x92); } alwaysinline auto setc (dis8 dt) { op(0x92); } alwaysinline auto setg (dis8 dt) { op(0x9f); } alwaysinline auto setge(dis8 dt) { op(0x9d); } alwaysinline auto setl (dis8 dt) { op(0x9c); } alwaysinline auto setle(dis8 dt) { op(0x9e); } alwaysinline auto setnc(dis8 dt) { op(0x93); } alwaysinline auto setno(dis8 dt) { op(0x91); } alwaysinline auto setnp(dis8 dt) { op(0x9b); } alwaysinline auto setns(dis8 dt) { op(0x99); } alwaysinline auto setnz(dis8 dt) { op(0x95); } alwaysinline auto seto (dis8 dt) { op(0x90); } alwaysinline auto setp (dis8 dt) { op(0x9a); } alwaysinline auto sets (dis8 dt) { op(0x98); } alwaysinline auto setz (dis8 dt) { op(0x94); } #undef op //call imm64 (pseudo-op) alwaysinline auto call(imm64 target, reg64 scratch) { s64 dist = distance(target.data) - 5; if(dist < INT32_MIN || dist > INT32_MAX) { mov(scratch, target); call(scratch); } else { call(imm32{dist}); } } //jmp label (pseudo-op) alwaysinline auto jmp(label l) { jmp(imm32{resolve(l, 1, 4)}); } //};