Browse Source

* patch by J. Gareth Moreton: CMOV extensions: frame/stack pointer relative references are always valid, resolves #36675

git-svn-id: trunk@44141 -
florian 5 years ago
parent
commit
12d015a935
1 changed files with 36 additions and 11 deletions
  1. 36 11
      compiler/x86/aoptx86.pas

+ 36 - 11
compiler/x86/aoptx86.pas

@@ -61,6 +61,15 @@ unit aoptx86;
           except where the register is being written }
         function ReplaceRegisterInInstruction(const p: taicpu; const AOldReg, ANewReg: TRegister): Boolean;
 
+        { Returns true if the reference only refers to ESP or EBP (or their 64-bit equivalents),
+          or writes to a global symbol }
+        class function IsRefSafe(const ref: PReference): Boolean; static; inline;
+
+
+        { Returns true if the given MOV instruction can be safely converted to CMOV }
+        class function CanBeCMOV(p : tai) : boolean; static;
+
+
         function DeepMOVOpt(const p_mov: taicpu; const hp: taicpu): Boolean;
 
         procedure DebugMsg(const s : string; p : tai);inline;
@@ -1627,6 +1636,23 @@ unit aoptx86;
       end;
 
 
+    class function TX86AsmOptimizer.IsRefSafe(const ref: PReference): Boolean; inline;
+      begin
+        Result :=
+          (ref^.index = NR_NO) and
+          (
+{$ifdef x86_64}
+            (
+              (ref^.base = NR_RIP) and
+              (ref^.refaddr in [addr_pic, addr_pic_no_got])
+            ) or
+{$endif x86_64}
+            (ref^.base = NR_STACK_POINTER_REG) or
+            (ref^.base = current_procinfo.framepointer)
+          );
+      end;
+
+
     function TX86AsmOptimizer.DeepMOVOpt(const p_mov: taicpu; const hp: taicpu): Boolean;
       var
         CurrentReg, ReplaceReg: TRegister;
@@ -4638,7 +4664,7 @@ unit aoptx86;
       end;
 
 
-    function CanBeCMOV(p : tai) : boolean;
+    class function TX86AsmOptimizer.CanBeCMOV(p : tai) : boolean;
       begin
          CanBeCMOV:=assigned(p) and
            MatchInstruction(p,A_MOV,[S_W,S_L,S_Q]) and
@@ -4648,16 +4674,15 @@ unit aoptx86;
             or ((taicpu(p).oper[0]^.typ = top_ref) and
              (taicpu(p).oper[0]^.ref^.refaddr = addr_no))
            }
-           (MatchOpType(taicpu(p),top_reg,top_reg) or
-            { allow references, but only pure symbols or got rel. addressing with RIP as based,
-              it is not expected that this can cause a seg. violation }
-            (MatchOpType(taicpu(p),top_ref,top_reg) and
-             (((taicpu(p).oper[0]^.ref^.base=NR_NO) and (taicpu(p).oper[0]^.ref^.refaddr=addr_no)){$ifdef x86_64} or
-              ((taicpu(p).oper[0]^.ref^.base=NR_RIP) and (taicpu(p).oper[0]^.ref^.refaddr=addr_pic)){$endif x86_64}
-             ) and
-             (taicpu(p).oper[0]^.ref^.index=NR_NO) and
-             (taicpu(p).oper[0]^.ref^.offset=0)
-            )
+           (taicpu(p).oper[1]^.typ = top_reg) and
+           (
+             (taicpu(p).oper[0]^.typ = top_reg) or
+             { allow references, but only pure symbols or got rel. addressing with RIP as based,
+               it is not expected that this can cause a seg. violation }
+             (
+               (taicpu(p).oper[0]^.typ = top_ref) and
+               IsRefSafe(taicpu(p).oper[0]^.ref)
+             )
            );
       end;