diff --git a/.gitattributes b/.gitattributes index be8495baaf..8f17e7217c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9674,6 +9674,7 @@ tests/test/tclass8.pp svneol=native#text/plain tests/test/tclass9.pp svneol=native#text/pascal tests/test/tclassinfo1.pp svneol=native#text/pascal tests/test/tclrprop.pp svneol=native#text/plain +tests/test/tcmov1.pp svneol=native#text/plain tests/test/tcmp.pp svneol=native#text/plain tests/test/tcmp0.pp svneol=native#text/plain tests/test/tconstref1.pp svneol=native#text/pascal diff --git a/compiler/i386/i386atts.inc b/compiler/i386/i386atts.inc index f012e395d6..a4c6890789 100644 --- a/compiler/i386/i386atts.inc +++ b/compiler/i386/i386atts.inc @@ -201,8 +201,8 @@ attsufNONE, attsufNONE, attsufNONE, attsufNONE, -attsufINT, -attsufINT, +attsufINTdual, +attsufINTdual, attsufINT, attsufNONE, attsufINT, diff --git a/compiler/utils/mkx86ins.pp b/compiler/utils/mkx86ins.pp index c2df79bfdb..715178aa94 100644 --- a/compiler/utils/mkx86ins.pp +++ b/compiler/utils/mkx86ins.pp @@ -280,6 +280,11 @@ begin dec(attopcode[0]); attsuffix:='attsufINT'; end; + 'Y' : + begin + dec(attopcode[0]); + attsuffix:='attsufINTdual'; + end; 'F' : begin dec(attopcode[0]); diff --git a/compiler/x86/itcpugas.pas b/compiler/x86/itcpugas.pas index 88ba80d8fc..fe41d324f6 100644 --- a/compiler/x86/itcpugas.pas +++ b/compiler/x86/itcpugas.pas @@ -29,7 +29,7 @@ interface cgbase,cpubase; type - TAttSuffix = (AttSufNONE,AttSufINT,AttSufFPU,AttSufFPUint); + TAttSuffix = (AttSufNONE,AttSufINT,AttSufFPU,AttSufFPUint,AttSufINTdual); const {$ifdef x86_64} @@ -52,6 +52,22 @@ interface 't', '' ); + { suffix-to-opsize conversion tables, used in asmreadrer } + { !! S_LQ excluded: movzlq does not exist, movslq is processed + as a separate instruction w/o suffix (aka movsxd), and there are + no more instructions needing it. } + att_sizesuffixstr : array[0..11] of string[2] = ( + '','BW','BL','WL','BQ','WQ',{'LQ',}'B','W','L','S','Q','T' + ); + att_sizesuffix : array[0..11] of topsize = ( + S_NO,S_BW,S_BL,S_WL,S_BQ,S_WQ,{S_LQ,}S_B,S_W,S_L,S_FS,S_IQ,S_FX + ); + att_sizefpusuffix : array[0..11] of topsize = ( + S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,{S_NO,}S_NO,S_NO,S_FL,S_FS,S_IQ,S_FX + ); + att_sizefpuintsuffix : array[0..11] of topsize = ( + S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,{S_NO,}S_NO,S_NO,S_IL,S_IS,S_IQ,S_NO + ); {$else x86_64} gas_opsize2str : array[topsize] of string[2] = ('', 'b','w','l','q','bw','bl','wl', @@ -62,6 +78,19 @@ interface 't', '' ); + { suffix-to-opsize conversion tables, used in asmreadrer } + att_sizesuffixstr : array[0..9] of string[2] = ( + '','BW','BL','WL','B','W','L','S','Q','T' + ); + att_sizesuffix : array[0..9] of topsize = ( + S_NO,S_BW,S_BL,S_WL,S_B,S_W,S_L,S_FS,S_IQ,S_FX + ); + att_sizefpusuffix : array[0..9] of topsize = ( + S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_FL,S_FS,S_IQ,S_FX + ); + att_sizefpuintsuffix : array[0..9] of topsize = ( + S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_IL,S_IS,S_IQ,S_NO + ); {$endif x86_64} diff --git a/compiler/x86/rax86att.pas b/compiler/x86/rax86att.pas index 522362e19b..84c5ac38a1 100644 --- a/compiler/x86/rax86att.pas +++ b/compiler/x86/rax86att.pas @@ -759,27 +759,13 @@ Implementation function tx86attreader.is_asmopcode(const s: string):boolean; - const - { We need first to check the long prefixes, else we get probs - with things like movsbl } - att_sizesuffixstr : array[0..9] of string[2] = ( - '','BW','BL','WL','B','W','L','S','Q','T' - ); - att_sizesuffix : array[0..9] of topsize = ( - S_NO,S_BW,S_BL,S_WL,S_B,S_W,S_L,S_FS,S_IQ,S_FX - ); - att_sizefpusuffix : array[0..9] of topsize = ( - S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_FL,S_FS,S_IQ,S_FX - ); - att_sizefpuintsuffix : array[0..9] of topsize = ( - S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_IL,S_IS,S_IQ,S_NO - ); var cond : string[4]; cnd : tasmcond; len, j, - sufidx : longint; + sufidx, + suflen : longint; Begin is_asmopcode:=FALSE; @@ -790,13 +776,20 @@ Implementation { search for all possible suffixes } for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do begin - len:=length(s)-length(att_sizesuffixstr[sufidx]); - if copy(s,len+1,length(att_sizesuffixstr[sufidx]))=att_sizesuffixstr[sufidx] then + suflen:=length(att_sizesuffixstr[sufidx]); + len:=length(s)-suflen; + if copy(s,len+1,suflen)=att_sizesuffixstr[sufidx] then begin { Search opcodes } if len>0 then begin actopcode:=tasmop(PtrUInt(iasmops.Find(copy(s,1,len)))); + + { two-letter suffix is allowed by just a few instructions (movsx,movzx), + and it is always required whenever allowed } + if (gas_needsuffix[actopcode]=attsufINTdual) xor (suflen=2) then + continue; + if actopcode<>A_NONE then begin if gas_needsuffix[actopcode]=attsufFPU then diff --git a/compiler/x86/x86ins.dat b/compiler/x86/x86ins.dat index 32cdd1bd54..1c84d068af 100644 --- a/compiler/x86/x86ins.dat +++ b/compiler/x86/x86ins.dat @@ -1097,12 +1097,12 @@ void \326\1\xA5 X86_64 (Ch_All, Ch_None, Ch_None) void \324\1\xA5 8086 -[MOVSX,movsX] +[MOVSX,movsY] (Ch_Wop2, Ch_Rop1, Ch_None) reg32|64,rm16 \301\320\2\x0F\xBF\110 386 reg16|32|64,rm8 \301\320\2\x0F\xBE\110 386 -[MOVZX,movzX] +[MOVZX,movzY] (Ch_Wop2, Ch_Rop1, Ch_None) reg32|64,rm16 \301\320\2\x0F\xB7\110 386 reg16|32|64,rm8 \301\320\2\x0F\xB6\110 386 @@ -3717,4 +3717,4 @@ void \2\x48\xAD X86_64 [CMPSQ] (Ch_All, Ch_None, Ch_None) -void \2\x48\xA7 X86_64 \ No newline at end of file +void \2\x48\xA7 X86_64 diff --git a/compiler/x86_64/x8664ats.inc b/compiler/x86_64/x8664ats.inc index f012e395d6..a4c6890789 100644 --- a/compiler/x86_64/x8664ats.inc +++ b/compiler/x86_64/x8664ats.inc @@ -201,8 +201,8 @@ attsufNONE, attsufNONE, attsufNONE, attsufNONE, -attsufINT, -attsufINT, +attsufINTdual, +attsufINTdual, attsufINT, attsufNONE, attsufINT, diff --git a/tests/test/tcmov1.pp b/tests/test/tcmov1.pp new file mode 100644 index 0000000000..b50e65d34b --- /dev/null +++ b/tests/test/tcmov1.pp @@ -0,0 +1,36 @@ +{ %CPU=x86_64 } +{$mode objfpc}{$asmmode att} + +// Test correct assembling of cmov instructions +// they should receive condition and size separately, +// iow cmovbq should not be processed as cmov+bq + +function test: Pointer; assembler; nostackframe; +asm + jmp .L3 +.L1: + cmovbq %rcx,%rax // 48 0f 42 c1 + cmovbl %ecx,%eax // 0f 42 c1 + cmovbw %cx,%ax // 66 0f 42 c1 + cmovlq %rcx,%rax // 48 0f 4c c1 +.L3: + lea .L1(%rip), %rax +end; + +var + x: PByte; + +begin + x := test; + if (x[0]<>$48) or (x[1]<>$0F) or (x[2]<>$42) or (x[3]<>$C1) then + Halt(1); + Inc(x,4); + if (x[0]<>$0F) or (x[1]<>$42) or (x[2]<>$C1) then + Halt(2); + Inc(x,3); + if (x[0]<>$66) or (x[1]<>$0F) or (x[2]<>$42) or (x[3]<>$C1) then + Halt(3); + Inc(x,4); + if (x[0]<>$48) or (x[1]<>$0F) or (x[2]<>$4C) or (x[3]<>$C1) then + Halt(4); +end.