if ~ defined SSE2 restore SSE2 ; this ensures that symbol cannot be forward-referenced SSE2 = 1 include 'sse.inc' iterate , sqrt,51h, rsqrt,52h, rcp,53h, add,58h, mul,59h, sub,5Ch, min,5Dh, div,5Eh, max,5Fh macro instr#pd? dest*,src* SSE.basic_instruction 66h,ext,16,dest,src end macro macro instr#sd? dest*,src* SSE.basic_instruction 0F2h,ext,8,dest,src end macro end iterate iterate , and,54h, andn,55h, or,56h, xor,57h, unpckl,14h, unpckh,15h macro instr#pd? dest*,src* SSE.basic_instruction 66h,ext,16,dest,src end macro end iterate macro cmppd? dest*,src*,code* SSE.basic_instruction_imm8 66h,0C2h,16,dest,src,code end macro macro SSE.cmpsd? dest*,src*,code* SSE.basic_instruction_imm8 0F2h,0C2h,8,dest,src,code end macro calminstruction cmpsd? args& match , args jno sse xcall x86.store_operand_prefix, (4) emit 1, 0A7h exit sse: arrange args, =SSE.=cmpsd args assemble args end calminstruction iterate , eq,0, lt,1, le,2, unord,3, neq,4, nlt,5, nle,6, ord,7 macro cmp#cond#pd? dest*,src* cmppd dest,src,code end macro macro cmp#cond#sd? dest*,src* cmpsd dest,src,code end macro end iterate macro shufpd? dest*,src*,imm* SSE.basic_instruction_imm8 66h,0C6h,16,dest,src,imm end macro iterate , movapd,28h, movupd,10h macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if (@dest.size or @src.size) and not 16 err 'invalid operand size' end if if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,ext>,@dest.rm else if @dest.type = 'mem' & @src.type = 'mmreg' @dest.opcode_prefix = 66h x86.store_instruction@dest <0Fh,ext+1>,@src.rm else err 'invalid combination of operands' end if end macro end iterate iterate , movlpd,12h, movhpd,16h macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & @src.type = 'mem' if @dest.size <> 16 | @src.size and not 8 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,ext>,@dest.rm else if @dest.type = 'mem' & @src.type = 'mmreg' if @dest.size and not 8 | @src.size <> 16 err 'invalid operand size' end if @dest.opcode_prefix = 66h x86.store_instruction@dest <0Fh,ext+1>,@src.rm else err 'invalid combination of operands' end if end macro end iterate macro SSE.movsd? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if @dest.size <> 16 | (@src.type = 'mem' & @src.size and not 8) | (@src.type = 'mmreg' & @src.size <> 16) err 'invalid operand size' end if @src.opcode_prefix = 0F2h x86.store_instruction@src <0Fh,10h>,@dest.rm else if @dest.type = 'mem' & @src.type = 'mmreg' if @dest.size and not 8 | @src.size <> 16 err 'invalid operand size' end if @dest.opcode_prefix = 0F2h x86.store_instruction@dest <0Fh,11h>,@src.rm else err 'invalid combination of operands' end if end macro calminstruction movsd? args& match , args jno sse xcall x86.store_operand_prefix, (4) emit 1, 0A5h exit sse: arrange args, =SSE.=movsd args assemble args end calminstruction iterate , movdqa,66h, movdqu,0F3h macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if (@dest.size or @src.size) and not 16 err 'invalid operand size' end if if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') @src.opcode_prefix = pre x86.store_instruction@src <0Fh,6Fh>,@dest.rm else if @dest.type = 'mem' & @src.type = 'mmreg' @dest.opcode_prefix = pre x86.store_instruction@dest <0Fh,7Fh>,@src.rm else err 'invalid combination of operands' end if end macro end iterate iterate , movntpd,2Bh, movntdq,0E7h macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mem' & @src.type = 'mmreg' if (@dest.size or @src.size) and not 16 err 'invalid operand size' end if @dest.opcode_prefix = 66h x86.store_instruction@dest <0Fh,ext>,@src.rm else err 'invalid combination of operands' end if end macro end iterate macro movmskpd? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'reg' & @src.type = 'mmreg' if (@dest.size <> 4 & (x86.mode < 64 | @dest.size <> 8)) | @src.size <> 16 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,50h>,@dest.rm else err 'invalid combination of operands' end if end macro macro maskmovdqu? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & @src.type = 'mmreg' if (@dest.size or @src.size) <> 16 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,0F7h>,@dest.rm else err 'invalid combination of operands' end if end macro iterate , ucomisd,2Eh, comisd,2Fh macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if @dest.size <> 16 | (@src.type = 'mem' & @src.size and not 8) | (@src.type = 'mmreg' & @src.size <> 16) err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,ext>,@dest.rm else err 'invalid combination of operands' end if end macro end iterate macro cvtps2pd? dest*,src* SSE.basic_instruction 0,5Ah,8,dest,src end macro macro cvtpd2ps? dest*,src* SSE.basic_instruction 66h,5Ah,16,dest,src end macro macro cvtsd2ss? dest*,src* SSE.basic_instruction 0F2h,5Ah,8,dest,src end macro macro cvtss2sd? dest*,src* SSE.basic_instruction 0F3h,5Ah,4,dest,src end macro macro cvtdq2ps? dest*,src* SSE.basic_instruction 0,5Bh,16,dest,src end macro macro cvtps2dq? dest*,src* SSE.basic_instruction 66h,5Bh,16,dest,src end macro macro cvttps2dq? dest*,src* SSE.basic_instruction 0F3h,5Bh,16,dest,src end macro macro cvttpd2dq? dest*,src* SSE.basic_instruction 66h,0E6h,16,dest,src end macro macro cvtpd2dq? dest*,src* SSE.basic_instruction 0F2h,0E6h,16,dest,src end macro macro cvtdq2pd? dest*,src* SSE.basic_instruction 0F3h,0E6h,8,dest,src end macro macro movdq2q? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & @src.type = 'mmreg' if @dest.size <> 8 | @src.size <> 16 err 'invalid operand size' end if @src.opcode_prefix = 0F2h x86.store_instruction@src <0Fh,0D6h>,@dest.rm else err 'invalid combination of operands' end if end macro macro movq2dq? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & @src.type = 'mmreg' if @dest.size <> 16 | @src.size <> 8 err 'invalid operand size' end if @src.opcode_prefix = 0F3h x86.store_instruction@src <0Fh,0D6h>,@dest.rm else err 'invalid combination of operands' end if end macro macro cvtpi2pd? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if @dest.size <> 16 | @src.size and not 8 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,2Ah>,@dest.rm else err 'invalid combination of operands' end if end macro macro cvtsi2sd? dest*,src* SSE.parse_operand@dest dest x86.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'reg') if @src.size = 0 err 'operand size not specified' else if @dest.size <> 16 | @src.size < 4 err 'invalid operand size' end if x86.select_operand_prefix@src @src.size @src.opcode_prefix = 0F2h x86.store_instruction@src <0Fh,2Ah>,@dest.rm else err 'invalid combination of operands' end if end macro iterate , cvttpd2pi,2Ch, cvtpd2pi,2Dh macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if @dest.size <> 8 | @src.size and not 16 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,ext>,@dest.rm else err 'invalid combination of operands' end if end macro end iterate iterate , cvttsd2si,2Ch, cvtsd2si,2Dh macro instr? dest*,src* x86.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'reg' & (@src.type = 'mem' | @src.type = 'mmreg') if @dest.size < 4 | (@src.type = 'mem' & @src.size and not 8) | (@src.type = 'mmreg' & @src.size <>16) err 'invalid operand size' end if x86.select_operand_prefix@src @dest.size @src.opcode_prefix = 0F2h x86.store_instruction@src <0Fh,ext>,@dest.rm else err 'invalid combination of operands' end if end macro end iterate calminstruction MMX.select_operand_prefix rm_operand*,size* local sym, prefix check size = 16 jno no_prefix compute prefix, 66h arrange sym, rm_operand.=prefix publish sym, prefix exit no_prefix: check size <> 8 jno done err 'invalid operand size' done: end calminstruction calminstruction MMX.basic_instruction ext,dest,src call SSE.parse_operand@dest, dest call SSE.parse_operand@src, src check @src.size and not @dest.size jno size_ok err 'operand sizes do not match' size_ok: check @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') jno invalid_combination_of_operands call MMX.select_operand_prefix, @src,@dest.size xcall x86.store_instruction@src, <0Fh,ext>,@dest.rm exit invalid_combination_of_operands: err 'invalid combination of operands' end calminstruction calminstruction MMX.bit_shift_instruction ext,dest,src call SSE.parse_operand@dest, dest call SSE.parse_operand@src, src check @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') jyes mmreg_rm check @dest.type = 'mmreg' & @src.type = 'imm' jyes mmreg_imm err 'invalid combination of operands' exit mmreg_rm: check @src.size and not @dest.size jno mmreg_rm_ok err 'operand sizes do not match' mmreg_rm_ok: call MMX.select_operand_prefix, @src,@dest.size xcall x86.store_instruction@src, <0Fh,ext>,@dest.rm exit mmreg_imm: check @src.size and not 1 jno rm_mmreg_ok err 'invalid operand size' rm_mmreg_ok: local iext, irm compute iext, 70h+(ext and 0Fh) compute irm, ((ext shr 4)-0Ch) shl 1 call MMX.select_operand_prefix, @dest,@dest.size xcall x86.store_instruction@dest, <0Fh,iext>,irm,byte,@src.imm end calminstruction iterate , paddq,0D4h, pmuludq,0F4h, psubq,0FBh macro instr? dest*,src* MMX.basic_instruction ext,dest,src end macro end iterate macro movq? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if (@src.type = 'mem' & @src.size and not 8) | (@src.type = 'mmreg' & @src.size <> @dest.size) err 'invalid operand size' end if if @dest.size = 8 x86.store_instruction@src <0Fh,6Fh>,@dest.rm else @src.opcode_prefix = 0F3h x86.store_instruction@src <0Fh,7Eh>,@dest.rm end if else if @dest.type = 'mem' & @src.type = 'mmreg' if @dest.size and not 8 err 'invalid operand size' end if if @src.size = 8 x86.store_instruction@dest <0Fh,7Fh>,@src.rm else @dest.opcode_prefix = 66h x86.store_instruction@dest <0Fh,0D6h>,@src.rm end if else if @dest.type = 'reg' & @src.type = 'mmreg' if @dest.size <> 8 err 'invalid operand size' end if if @src.size = 16 @dest.opcode_prefix = 66h end if @dest.prefix = 48h x86.store_instruction@dest <0Fh,7Eh>,@src.rm else if @dest.type = 'mmreg' & @src.type = 'reg' if @src.size <> 8 err 'invalid operand size' end if if @dest.size = 16 @src.opcode_prefix = 66h end if @src.prefix = 48h x86.store_instruction@src <0Fh,6Eh>,@dest.rm else err 'invalid combination of operands' end if end macro macro movd? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'reg') if @src.size and not 4 err 'invalid operand size' end if MMX.select_operand_prefix @src,@dest.size x86.store_instruction@src <0Fh,6Eh>,@dest.rm else if (@dest.type = 'mem' | @dest.type = 'reg') & @src.type = 'mmreg' if @dest.size and not 4 err 'invalid operand size' end if MMX.select_operand_prefix @dest,@src.size x86.store_instruction@dest <0Fh,7Eh>,@src.rm else err 'invalid combination of operands' end if end macro macro pinsrw? dest*,src*,sel* SSE.parse_operand@dest dest x86.parse_operand@src src x86.parse_operand@aux sel if @dest.type = 'mmreg' & (@src.type = 'reg' | @src.type = 'mem') & @aux.type = 'imm' if (@src.type = 'reg' & @src.size <> 4) | (@src.type = 'mem' & @src.size and not 2) | @aux.size and not 1 err 'invalid operand size' end if MMX.select_operand_prefix @src,@dest.size x86.store_instruction@src <0Fh,0C4h>,@dest.rm,1,@aux.imm else err 'invalid combination of operands' end if end macro macro pextrw? dest*,src*,sel* x86.parse_operand@dest dest SSE.parse_operand@src src x86.parse_operand@aux sel if @dest.type = 'reg' & @src.type = 'mmreg' & @aux.type = 'imm' if x86.mode = 64 & @dest.size = 8 @dest.size = 4 end if if @dest.size <> 4 | @aux.size and not 1 err 'invalid operand size' end if MMX.select_operand_prefix @src,@src.size x86.store_instruction@src <0Fh,0C5h>,@dest.rm,1,@aux.imm else err 'invalid combination of operands' end if end macro iterate , pshufd,66h, pshuflw,0F2h, pshufhw,0F3h macro instr? dest*,src*,sel* SSE.parse_operand@dest dest SSE.parse_operand@src src x86.parse_operand@aux sel if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') & @aux.type = 'imm' if @dest.size <> 16 | @src.size and not 16 | @aux.size and not 1 err 'invalid operand size' end if @src.opcode_prefix = pre x86.store_instruction@src <0Fh,70h>,@dest.rm,1,@aux.imm else err 'invalid combination of operands' end if end macro end iterate macro pmovmskb? dest*,src* x86.parse_operand@dest dest SSE.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 MMX.select_operand_prefix @src,@src.size x86.store_instruction@src <0Fh,0D7h>,@dest.rm else err 'invalid combination of operands' end if end macro iterate , psrldq,3, pslldq,7 macro instr? dest*,cnt* SSE.parse_operand@dest dest x86.parse_operand@aux cnt if @dest.type = 'mmreg' & @aux.type = 'imm' if @dest.size <> 16 | @aux.size and not 1 err 'invalid operand size' end if @dest.opcode_prefix = 66h x86.store_instruction@dest <0Fh,73h>,postbyte,1,@aux.imm else err 'invalid combination of operands' end if end macro end iterate iterate , punpcklqdq,6Ch, punpckhqdq,6Dh macro instr? dest*,src* SSE.parse_operand@dest dest SSE.parse_operand@src src if @dest.type = 'mmreg' & (@src.type = 'mem' | @src.type = 'mmreg') if (@dest.size or @src.size) and not 16 err 'invalid operand size' end if @src.opcode_prefix = 66h x86.store_instruction@src <0Fh,ext>,@dest.rm else err 'invalid combination of operands' end if end macro end iterate macro movnti? dest*,src* x86.parse_operand@dest dest x86.parse_operand@src src if @dest.type = 'mem' & @src.type = 'reg' if @dest.size and not @src.size err 'operand sizes do not match' else if @src.size <> 4 & @src.size <> 8 err 'invalid operand size' end if x86.select_operand_prefix@dest @src.size x86.store_instruction@dest <0Fh,0C3h>,@src.rm else err 'invalid combination of operands' end if end macro macro clflush? src* x86.parse_operand@src src if @src.type = 'mem' if @src.size and not 1 err 'invalid operand size' end if x86.store_instruction@src <0Fh,0AEh>,7 else err 'invalid operand' end if end macro macro lfence? db 0Fh,0AEh,0E8h end macro macro mfence? db 0Fh,0AEh,0F0h end macro end if