Kaynağa Gözat

x86_64 assembler reader improvements:
+ Added new value TAttSuffix.attsufINTdual, assigned it to movsX and movzX instructions
* Moved suffix-to-size translation tables from rax86att.pas to itcpugas.pas
+ Added x86_64 specific suffix-to-size translation, enabling BQ and WQ suffixes (LQ seems unnecessary at the moment)
* Fixed logic of tx86attreader.is_asmopcode so it only assigns dual suffix to instructions that explicitly allow it. This disambiguates cases like movsbq=movs+bq vs. cmovbq=cmovb+q
* As a net result: movz[bw]q and movs[bw]q now compile for x86_64; cmovbw and cmovbl which were incorrectly handled for i386 are now fixed.
+ Test for correct assembling of cmov.

git-svn-id: trunk@17353 -

sergei 14 yıl önce
ebeveyn
işleme
f97f223de6

+ 1 - 0
.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

+ 2 - 2
compiler/i386/i386atts.inc

@@ -201,8 +201,8 @@ attsufNONE,
 attsufNONE,
 attsufNONE,
 attsufNONE,
-attsufINT,
-attsufINT,
+attsufINTdual,
+attsufINTdual,
 attsufINT,
 attsufNONE,
 attsufINT,

+ 5 - 0
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]);

+ 30 - 1
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}
 
 

+ 11 - 18
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

+ 3 - 3
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
+void                   \2\x48\xA7                                    X86_64

+ 2 - 2
compiler/x86_64/x8664ats.inc

@@ -201,8 +201,8 @@ attsufNONE,
 attsufNONE,
 attsufNONE,
 attsufNONE,
-attsufINT,
-attsufINT,
+attsufINTdual,
+attsufINTdual,
 attsufINT,
 attsufNONE,
 attsufINT,

+ 36 - 0
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.