Browse Source

+ added helper functions x86_param2paramless_string_op and
get_x86_string_op_size
* refactored the AT&T inline asm handling of x86 parameterized string ops, so it
uses the new helper functions

git-svn-id: trunk@37449 -

nickysn 7 years ago
parent
commit
5a5cd65559
2 changed files with 64 additions and 156 deletions
  1. 44 0
      compiler/x86/cpubase.pas
  2. 20 156
      compiler/x86/rax86att.pas

+ 44 - 0
compiler/x86/cpubase.pas

@@ -323,6 +323,8 @@ uses
     { checks whether the specified op is an x86 parameterized string instruction
       (e.g. returns true for movs, cmps, etc, but returns false for movsb, cmpsb, etc.) }
     function is_x86_parameterized_string_instruction_op(op: TAsmOp): boolean;
+    function x86_param2paramless_string_op(op: TAsmOp): TAsmOp;
+    function get_x86_string_op_size(op: TAsmOp): TOpSize;
 
 {$ifdef i8086}
     { return whether we need to add an extra FWAIT instruction before the given
@@ -708,6 +710,48 @@ implementation
       end;
 
 
+    function x86_param2paramless_string_op(op: TAsmOp): TAsmOp;
+      begin
+        case op of
+          A_MOVSB,A_MOVSW,A_MOVSD{$ifdef x86_64},A_MOVSQ{$endif}:
+            result:=A_MOVS;
+          A_CMPSB,A_CMPSW,A_CMPSD{$ifdef x86_64},A_CMPSQ{$endif}:
+            result:=A_CMPS;
+          A_SCASB,A_SCASW,A_SCASD{$ifdef x86_64},A_SCASQ{$endif}:
+            result:=A_SCAS;
+          A_LODSB,A_LODSW,A_LODSD{$ifdef x86_64},A_LODSQ{$endif}:
+            result:=A_LODS;
+          A_STOSB,A_STOSW,A_STOSD{$ifdef x86_64},A_STOSQ{$endif}:
+            result:=A_STOS;
+          A_INSB, A_INSW, A_INSD:
+            result:=A_INS;
+          A_OUTSB,A_OUTSW,A_OUTSD:
+            result:=A_OUTS;
+          else
+            internalerror(2017101201);
+        end;
+      end;
+
+
+    function get_x86_string_op_size(op: TAsmOp): TOpSize;
+      begin
+        case op of
+          A_MOVSB,A_CMPSB,A_SCASB,A_LODSB,A_STOSB,A_INSB,A_OUTSB:
+            result:=S_B;
+          A_MOVSW,A_CMPSW,A_SCASW,A_LODSW,A_STOSW,A_INSW,A_OUTSW:
+            result:=S_W;
+          A_MOVSD,A_CMPSD,A_SCASD,A_LODSD,A_STOSD,A_INSD,A_OUTSD:
+            result:=S_L;
+{$ifdef x86_64}
+          A_MOVSQ,A_CMPSQ,A_SCASQ,A_LODSQ,A_STOSQ:
+            result:=S_Q;
+{$endif x86_64}
+          else
+            internalerror(2017101202);
+        end;
+      end;
+
+
 {$ifdef i8086}
     function requires_fwait_on_8087(op: TAsmOp): boolean;
       begin

+ 20 - 156
compiler/x86/rax86att.pas

@@ -874,164 +874,28 @@ Implementation
           end; { end case }
         until false;
         instr.Ops:=operandnum;
-        { handle string instructions with memory arguments }
+        { handle string instructions with parameters }
         with instr do
-          if Ops=2 then
+          if is_x86_parameterless_string_instruction_op(opcode) and
+             (Ops>=1) and (Ops<=2) then
             begin
-              case opcode of
-                A_MOVSB:
-                  begin
-                    opcode:=A_MOVS;
-                    opsize:=S_B;
-                  end;
-                A_MOVSW:
-                  begin
-                    opcode:=A_MOVS;
-                    opsize:=S_W;
-                  end;
-                A_MOVSD:
-                  begin
-                    { distinguish between MOVS and the SSE MOVSD instruction:
-                      MOVS must have memory 2 reference operands }
-                    if (operands[1].opr.typ=OPR_REFERENCE) and (operands[2].opr.typ=OPR_REFERENCE) then
-                      begin
-                        opcode:=A_MOVS;
-                        opsize:=S_L;
-                      end;
-                  end;
-{$ifdef x86_64}
-                A_MOVSQ:
-                  begin
-                    opcode:=A_MOVS;
-                    opsize:=S_Q;
-                  end;
-{$endif x86_64}
-                A_CMPSB:
-                  begin
-                    opcode:=A_CMPS;
-                    opsize:=S_B;
-                  end;
-                A_CMPSW:
-                  begin
-                    opcode:=A_CMPS;
-                    opsize:=S_W;
-                  end;
-                A_CMPSD:
-                  begin
-                    { no need to distinguish from SSE CMPSD, because the SSE
-                      version has 3 arguments }
-                    opcode:=A_CMPS;
-                    opsize:=S_L;
-                  end;
-{$ifdef x86_64}
-                A_CMPSQ:
-                  begin
-                    opcode:=A_CMPS;
-                    opsize:=S_Q;
-                  end;
-{$endif x86_64}
-                A_INSB:
-                  begin
-                    opcode:=A_INS;
-                    opsize:=S_B;
-                  end;
-                A_INSW:
-                  begin
-                    opcode:=A_INS;
-                    opsize:=S_W;
-                  end;
-                A_INSD:
-                  begin
-                    opcode:=A_INS;
-                    opsize:=S_L;
-                  end;
-                A_OUTSB:
-                  begin
-                    opcode:=A_OUTS;
-                    opsize:=S_B;
-                  end;
-                A_OUTSW:
-                  begin
-                    opcode:=A_OUTS;
-                    opsize:=S_W;
-                  end;
-                A_OUTSD:
-                  begin
-                    opcode:=A_OUTS;
-                    opsize:=S_L;
-                  end;
-              end;
-            end
-          else if Ops=1 then
-            begin
-              case opcode of
-                A_SCASB:
-                  begin
-                    opcode:=A_SCAS;
-                    opsize:=S_B;
-                  end;
-                A_SCASW:
-                  begin
-                    opcode:=A_SCAS;
-                    opsize:=S_W;
-                  end;
-                A_SCASD:
-                  begin
-                    opcode:=A_SCAS;
-                    opsize:=S_L;
-                  end;
-{$ifdef x86_64}
-                A_SCASQ:
-                  begin
-                    opcode:=A_SCAS;
-                    opsize:=S_Q;
-                  end;
-{$endif x86_64}
-                A_LODSB:
-                  begin
-                    opcode:=A_LODS;
-                    opsize:=S_B;
-                  end;
-                A_LODSW:
-                  begin
-                    opcode:=A_LODS;
-                    opsize:=S_W;
-                  end;
-                A_LODSD:
-                  begin
-                    opcode:=A_LODS;
-                    opsize:=S_L;
-                  end;
-{$ifdef x86_64}
-                A_LODSQ:
-                  begin
-                    opcode:=A_LODS;
-                    opsize:=S_Q;
-                  end;
-{$endif x86_64}
-                A_STOSB:
-                  begin
-                    opcode:=A_STOS;
-                    opsize:=S_B;
-                  end;
-                A_STOSW:
-                  begin
-                    opcode:=A_STOS;
-                    opsize:=S_W;
-                  end;
-                A_STOSD:
-                  begin
-                    opcode:=A_STOS;
-                    opsize:=S_L;
-                  end;
-{$ifdef x86_64}
-                A_STOSQ:
-                  begin
-                    opcode:=A_STOS;
-                    opsize:=S_Q;
-                  end;
-{$endif x86_64}
-              end;
+              if opcode=A_MOVSD then
+                begin
+                  { distinguish between MOVS and the SSE MOVSD instruction:
+                    MOVS must have memory 2 reference operands (there's no need
+                    to distinguish from SSE CMPSD, because the SSE version has 3
+                    arguments and we've already checked that above) }
+                  if (Ops=2) and (operands[1].opr.typ=OPR_REFERENCE) and (operands[2].opr.typ=OPR_REFERENCE) then
+                    begin
+                      opcode:=A_MOVS;
+                      opsize:=S_L;
+                    end;
+                end
+              else
+                begin
+                  opsize:=get_x86_string_op_size(opcode);
+                  opcode:=x86_param2paramless_string_op(opcode);
+                end;
             end;
       end;