503 lines
16 KiB
PHP
503 lines
16 KiB
PHP
|
|
if ~ defined AVX2
|
|
|
|
restore AVX2 ; this ensures that symbol cannot be forward-referenced
|
|
AVX2 = 1
|
|
|
|
include 'avx.inc'
|
|
|
|
iterate context, @dest,@src,@src2,@aux
|
|
|
|
namespace context
|
|
|
|
define visize
|
|
|
|
calminstruction AVX.parse_vsib_operand#context operand
|
|
|
|
local i, pre, suf
|
|
|
|
compute segment_prefix, 0
|
|
|
|
compute size, 0
|
|
compute displacement_size, 0
|
|
|
|
transform operand
|
|
|
|
match pre suf, operand
|
|
jno no_size_prefix
|
|
transform pre, x86
|
|
jno no_size_prefix
|
|
match :size, pre
|
|
jno no_size_prefix
|
|
arrange operand, suf
|
|
no_size_prefix:
|
|
|
|
match [address], operand
|
|
jyes memory_operand
|
|
match =ptr? address, operand
|
|
jyes memory_operand
|
|
|
|
jump invalid_operand
|
|
|
|
memory_operand:
|
|
compute type, 'mem'
|
|
|
|
match segment:address, address
|
|
jno segment_prefix_ok
|
|
check segment eq 1 elementof segment & 1 metadataof segment relativeto x86.sreg
|
|
jno invalid_operand
|
|
compute segment, 1 metadataof segment - x86.sreg
|
|
check segment >= 4
|
|
jyes segment_prefix_386
|
|
compute segment_prefix, 26h + segment shl 3
|
|
jump segment_prefix_ok
|
|
segment_prefix_386:
|
|
compute segment_prefix, 64h + segment-4
|
|
segment_prefix_ok:
|
|
|
|
match pre suf, address
|
|
jno no_address_size_prefix
|
|
transform pre, x86
|
|
jno no_address_size_prefix
|
|
match :pre, pre
|
|
jno no_address_size_prefix
|
|
arrange address, suf
|
|
check pre = 4 | pre = 8
|
|
jno invalid_address_size
|
|
compute mode, pre shl 3
|
|
no_address_size_prefix:
|
|
|
|
compute mode, 0
|
|
compute scale, 0
|
|
compute index, 0
|
|
compute base, 0
|
|
compute auto_relative, 0
|
|
|
|
check size
|
|
jyes size_override
|
|
compute size, sizeof address
|
|
size_override:
|
|
|
|
compute address, address
|
|
compute base_registers, 0
|
|
compute index_registers, 0
|
|
compute i, 1
|
|
extract_registers:
|
|
check i > elementsof address
|
|
jyes registers_extracted
|
|
check i metadataof address relativeto SSE.reg | i metadataof address relativeto AVX.reg
|
|
jyes index_term
|
|
check i metadataof address relativeto x86.r32 | i metadataof address relativeto x86.r64
|
|
jno next_term
|
|
compute base_registers, base_registers + i elementof address * i scaleof address
|
|
jump next_term
|
|
index_term:
|
|
compute index_registers, index_registers + i elementof address * i scaleof address
|
|
next_term:
|
|
compute i, i+1
|
|
jump extract_registers
|
|
registers_extracted:
|
|
compute displacement, address - base_registers - index_registers
|
|
compute auto_relative, 0
|
|
|
|
check elementsof index_registers = 1
|
|
jno invalid_address
|
|
compute scale, 1 scaleof index_registers
|
|
compute index, 0 scaleof (1 metadataof index_registers)
|
|
check scale and (scale-1) | scale > 8
|
|
jyes invalid_address
|
|
check 1 metadataof index_registers relativeto SSE.reg
|
|
jyes xmm_index
|
|
compute visize, 32
|
|
jump index_ok
|
|
xmm_index:
|
|
compute visize, 16
|
|
index_ok:
|
|
|
|
compute rm, 4
|
|
check elementsof base_registers = 1 & 1 scaleof base_registers = 1
|
|
jyes base_and_index
|
|
check elementsof base_registers = 0
|
|
jno invalid_address
|
|
compute base, 5
|
|
compute displacement_size, 4
|
|
compute mod, 0
|
|
compute mode, x86.mode
|
|
check mode > 16
|
|
jyes ready
|
|
compute mode, 32
|
|
jump ready
|
|
base_and_index:
|
|
compute base, 0 scaleof (1 metadataof base_registers)
|
|
check mode & mode <> 0 scaleof (1 metadataof (1 metadataof base_registers)) shl 3
|
|
jyes invalid_address
|
|
compute mode, 0 scaleof (1 metadataof (1 metadataof base_registers)) shl 3
|
|
|
|
setup_displacement:
|
|
check displacement relativeto 0
|
|
jno displacement_32bit
|
|
check displacement = 0 & rm and 111b <> 5 & (rm <> 4 | base and 111b <> 5)
|
|
jyes displacement_empty
|
|
check displacement < 80h & displacement >= -80h
|
|
jyes displacement_8bit
|
|
check displacement - 1 shl mode >= -80h & displacement < 1 shl mode
|
|
jyes displacement_8bit_wrap
|
|
displacement_32bit:
|
|
compute displacement_size, 4
|
|
compute mod, 2
|
|
jump ready
|
|
displacement_8bit_wrap:
|
|
compute displacement, displacement - 1 shl mode
|
|
displacement_8bit:
|
|
compute displacement_size, 1
|
|
compute mod, 1
|
|
jump ready
|
|
index_only:
|
|
compute displacement_size, 4
|
|
compute mod, 0
|
|
jump ready
|
|
displacement_empty:
|
|
compute displacement_size, 0
|
|
compute mod, 0
|
|
|
|
ready:
|
|
|
|
exit
|
|
|
|
invalid_operand:
|
|
err 'invalid operand'
|
|
exit
|
|
invalid_address:
|
|
err 'invalid address'
|
|
exit
|
|
invalid_address_size:
|
|
err 'invalid address size'
|
|
exit
|
|
|
|
end calminstruction
|
|
|
|
end namespace
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode,asize>, vpgatherdd,90h,4, vpgatherqd,91h,8, vgatherdps,92h,4, vgatherqps,93h,8
|
|
|
|
macro instr? dest*,src*,mask*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_vsib_operand@src src
|
|
AVX.parse_operand@aux mask
|
|
if @dest.type = 'mmreg' & @src.type = 'mem' & @aux.type = 'mmreg'
|
|
if @src.size and not 4 | (@dest.size > 16 & @dest.size * (asize shr 2) > @src.visize) | (@src.visize > 16 & @dest.size * (asize shr 2) < @src.visize)
|
|
err 'invalid operand size'
|
|
else if @aux.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
else if @dest.rm = @aux.rm | @dest.rm = @src.index | @aux.rm = @src.index
|
|
err 'disallowed combination of registers'
|
|
end if
|
|
AVX.store_instruction@src @src.visize,VEX_66_0F38_W0,opcode,@dest.rm,@aux.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode,asize>, vpgatherdq,90h,4, vpgatherqq,91h,8, vgatherdpd,92h,4, vgatherqpd,93h,8
|
|
|
|
macro instr? dest*,src*,mask*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_vsib_operand@src src
|
|
AVX.parse_operand@aux mask
|
|
if @dest.type = 'mmreg' & @src.type = 'mem' & @aux.type = 'mmreg'
|
|
if @src.size and not 8 | (@dest.size > 16 & @dest.size * (asize shr 2) > @src.visize * 2) | (@src.visize > 16 & @dest.size * (asize shr 2) < @src.visize * 2)
|
|
err 'invalid operand size'
|
|
else if @aux.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
else if @dest.rm = @aux.rm | @dest.rm = @src.index | @aux.rm = @src.index
|
|
err 'disallowed combination of registers'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F38_W1,opcode,@dest.rm,@aux.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode>, packsswb,63h, packuswb,67h, packssdw,6Bh, paddb,0FCh, paddw,0FDh, paddd,0FEh, paddq,0D4h, paddsb,0ECh, paddsw,0EDh, paddusb,0DCh, paddusw,0DDh, \
|
|
pand,0DBh, pandn,0DFh, pavgb,0E0h, pavgw,0E3h, pcmpeqb,74h, pcmpeqw,75h, pcmpeqd,76h, pcmpgtb,64h, pcmpgtw,65h, pcmpgtd,66h, \
|
|
pmaddwd,0F5h, pmaxsw,0EEh, pmaxub,0DEh, pminsw,0EAh, pminub,0DAh, pmulhuw,0E4h, pmulhw,0E5h, pmullw,0D5h, pmuludq,0F4h, \
|
|
por,0EBh, psadbw,0F6h, psubb,0F8h, psubw,0F9h, psubd,0FAh, psubq,0FBh, psubsb,0E8h, psubsw,0E9h, psubusb,0D8h, psubusw,0D9h, \
|
|
punpckhbw,68h, punpckhwd,69h, punpckhdq,6Ah, punpckhqdq,6Dh, punpcklbw,60h, punpcklwd,61h, punpckldq,62h, punpcklqdq,6Ch, pxor,0EFh
|
|
|
|
macro v#instr? dest*,src*,src2*
|
|
AVX.basic_instruction VEX_66_0F_W0,opcode,0,dest,src,src2
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode>, packusdw,2Bh, pcmpeqq,29h, pcmpgtq,37h, phaddw,1, phaddd,2, phaddsw,3, phsubw,5, phsubd,6, phsubsw,7, pmaddubsw,4, \
|
|
pmaxsb,3Ch, pmaxsd,3Dh, pmaxuw,3Eh, pmaxud,3Fh, pminsb,38h, pminsd,39h, pminuw,3Ah, pminud,3Bh, pmulhrsw,0Bh, pmulld,40h, pmuldq,28h, \
|
|
pshufb,0, psignb,8, psignw,9, psignd,0Ah
|
|
|
|
macro v#instr? dest*,src*,src2*
|
|
AVX.basic_instruction VEX_66_0F38_W0,opcode,0,dest,src,src2
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode>, mpsadbw,42h, palignr,0Fh, pblendd,02h
|
|
|
|
macro v#instr? dest*,src*,src2*,imm*
|
|
AVX.basic_instruction_imm8 VEX_66_0F3A_W0,opcode,0,dest,src,src2,imm
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode>, pabsb,1Ch, pabsw,1Dh, pabsd,1Eh, pblendw,0Eh
|
|
|
|
macro v#instr? dest*,src*
|
|
AVX.single_source_instruction VEX_66_0F38_W0,opcode,0,dest,src
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,vex_mpw>, pshufd,VEX_66_0F_W0, pshufhw,VEX_F3_0F_W0, pshuflw,VEX_F2_0F_W0
|
|
|
|
macro v#instr? dest*,src*,imm*
|
|
AVX.single_source_instruction_imm8 vex_mpw,70h,0,dest,src,imm
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,vex_mpw,opcode>, vpsllvd,VEX_66_0F38_W0,47h, vpsllvq,VEX_66_0F38_W1,47h, vpsrlvd,VEX_66_0F38_W0,45h, vpsrlvq,VEX_66_0F38_W1,45h, vpsravd,VEX_66_0F38_W0,46h
|
|
|
|
macro instr? dest*,src*,src2*
|
|
AVX.basic_instruction vex_mpw,opcode,0,dest,src,src2
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
macro vpblendvb? dest*,src*,src2*,mask*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
AVX.parse_operand@src2 src2
|
|
AVX.parse_operand@aux mask
|
|
if @dest.type = 'mmreg' & @src.type = 'mmreg' & (@src2.type = 'mem' | @src2.type = 'mmreg') & @aux.type = 'mmreg'
|
|
if @src.size <> @dest.size | @src2.size and not @dest.size | @aux.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src2 @dest.size,VEX_66_0F3A_W0,4Ch,@dest.rm,@src.rm,1,(@aux.rm and 1111b) shl 4
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
macro vpmovmskb? dest*,src*
|
|
x86.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
if @dest.type = 'reg' & @src.type = 'mmreg'
|
|
if (@dest.size <> 4 & (x86.mode < 64 | @dest.size <> 8))
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src @src.size,VEX_66_0F_W0,0D7h,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
iterate <instr,opcode,msize>, pmovsxbw,20h,8, pmovsxbd,21h,4, pmovsxbq,22h,2, pmovsxwd,23h,8, pmovsxwq,24h,4, pmovsxdq,25h,8, \
|
|
pmovzxbw,30h,8, pmovzxbd,31h,4, pmovzxbq,32h,2, pmovzxwd,33h,8, pmovzxwq,34h,4, pmovzxdq,35h,8
|
|
|
|
macro v#instr? dest*,src*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg')
|
|
if (@src.type = 'mmreg' & @src.size <> 16) | (@src.type = 'mem' & @src.size and not (msize * (@dest.size shr 4)))
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F38_W0,opcode,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,postbyte>, pslldq,7, psrldq,3
|
|
|
|
macro v#instr dest*,src*,src2*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
x86.parse_operand@src2 src2
|
|
if @dest.type = 'mmreg' & @src.type = 'mmreg' & @src2.type = 'imm'
|
|
if @src2.size and not 1
|
|
err 'invalid operand size'
|
|
else if @src.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F_W0,73h,postbyte,@dest.rm,1,@src2.imm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode_rrm,opcode,postbyte>, psllw,0F1h,71h,6, pslld,0F2h,72h,6, psllq,0F3h,73h,6, psraw,0E1h,71h,4, psrad,0E2h,72h,4, psrlw,0D1h,71h,2, psrld,0D2h,72h,2, psrlq,0D3h,73h,2
|
|
|
|
macro v#instr? dest*,src*,src2*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
AVX.parse_operand@src2 src2
|
|
if @dest.type = 'mmreg' & @src.type = 'mmreg' & (@src2.type = 'mem' | @src2.type = 'mmreg')
|
|
if @src2.size and not 16
|
|
err 'invalid operand size'
|
|
else if @src.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src2 @dest.size,VEX_66_0F_W0,opcode_rrm,@dest.rm,@src.rm
|
|
else if @dest.type = 'mmreg' & @src.type = 'mmreg' & @src2.type = 'imm'
|
|
if @src2.size and not 1
|
|
err 'invalid operand size'
|
|
else if @src.size <> @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F_W0,opcode,postbyte,@dest.rm,1,@src2.imm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
macro vmovntdqa? dest*,src*
|
|
AVX.parse_operand@dest dest
|
|
x86.parse_operand@src src
|
|
if @dest.type = 'mmreg' & @src.type = 'mem'
|
|
if @src.size and not @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F38_W0,2Ah,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
iterate <instr,w>, vpmaskmovd,0, vpmaskmovq,1
|
|
|
|
macro instr? dest*,src*,src2*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
AVX.parse_operand@src2 src2
|
|
if @dest.type = 'mmreg' & @src.type = 'mmreg' & @src2.type = 'mem'
|
|
if @src.size <> @dest.size | @src2.size and not @dest.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@src2 @dest.size,VEX_66_0F38_W#w,8Ch,@dest.rm,@src.rm
|
|
else if @dest.type = 'mem' & @src.type = 'mmreg' & @src2.type = 'mmreg'
|
|
if @src.size <> @src2.size | @dest.size and not @src.size
|
|
err 'operand sizes do not match'
|
|
end if
|
|
AVX.store_instruction@dest @src.size,VEX_66_0F38_W#w,8Eh,@src2.rm,@src.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
macro vbroadcasti128? dest*,src*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
if @dest.type = 'mmreg' & @src.type = 'mem'
|
|
if @dest.size <> 32 | @src.size and not 16
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src 32,VEX_66_0F38_W0,5Ah,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
macro vextracti128? dest*,src*,aux*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
x86.parse_operand@aux aux
|
|
if (@dest.type = 'mmreg' | @dest.type = 'mem') & @src.type = 'mmreg' & @aux.type = 'imm'
|
|
if @dest.size and not 16 | @src.size <> 32 | @aux.size and not 1
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@dest 32,VEX_66_0F3A_W0,39h,@src.rm,,1,@aux.imm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
macro vinserti128? dest*,src*,src2*,aux*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
AVX.parse_operand@src2 src2
|
|
x86.parse_operand@aux aux
|
|
if @dest.type = 'mmreg' & @src.type = 'mmreg' & (@src2.type = 'mmreg' | @src2.type = 'mem') & @aux.type = 'imm'
|
|
if @dest.size <> 32 | @src.size <> 32 | @src2.size and not 16 | @aux.size and not 1
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src2 32,VEX_66_0F3A_W0,38h,@dest.rm,@src.rm,1,@aux.imm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
macro vperm2i128? dest*,src*,src2*,imm*
|
|
AVX.basic_instruction_imm8 VEX_66_0F3A_W0,46h,32,dest,src,src2,imm
|
|
end macro
|
|
|
|
iterate <instr,opcode,msize>, vbroadcastss,18h,4, vpbroadcastb,78h,1, vpbroadcastw,79h,2, vpbroadcastd,58h,4, vpbroadcastq,59h,8
|
|
|
|
macro instr? dest*,src*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
if @dest.type = 'mmreg' & (@src.type = 'mmreg' | @src.type = 'mem')
|
|
if (@src.type='mmreg' & @src.size <> 16) | (@src.type = 'mem' & @src.size and not msize)
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src @dest.size,VEX_66_0F38_W0,opcode,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
macro vbroadcastsd? dest*,src*
|
|
AVX.parse_operand@dest dest
|
|
AVX.parse_operand@src src
|
|
if @dest.type = 'mmreg' & (@src.type = 'mmreg' | @src.type = 'mem')
|
|
if @dest.size <> 32 | (@src.type='mmreg' & @src.size <> 16) | (@src.type = 'mem' & @src.size and not 8)
|
|
err 'invalid operand size'
|
|
end if
|
|
AVX.store_instruction@src 32,VEX_66_0F38_W0,19h,@dest.rm
|
|
else
|
|
err 'invalid combination of operands'
|
|
end if
|
|
end macro
|
|
|
|
iterate <instr,opcode>, vpermq,0, vpermpd,1
|
|
|
|
macro instr? dest*,src*,imm*
|
|
AVX.single_source_instruction_imm8 VEX_66_0F3A_W1,opcode,32,dest,src,imm
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
iterate <instr,opcode>, vpermd,36h, vpermps,16h
|
|
|
|
macro instr? dest*,src*,src2*
|
|
AVX.basic_instruction VEX_66_0F38_W0,opcode,32,dest,src,src2
|
|
end macro
|
|
|
|
end iterate
|
|
|
|
end if
|