mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 21:48:09 +02:00
* x86: New reference support methods to detect modification
This commit is contained in:
parent
d0c7838eec
commit
e187d49590
@ -91,6 +91,11 @@ unit aoptx86;
|
||||
}
|
||||
function GetNextInstructionUsingRegTrackingUse(Current: tai; out Next: tai; reg: TRegister): Boolean;
|
||||
function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
|
||||
|
||||
{ returns true if any of the registers in ref are modified by any
|
||||
instruction between p1 and p2, or if those instructions write to the
|
||||
reference }
|
||||
function RefModifiedBetween(Ref: TReference; RefSize: ASizeInt; p1, p2: tai): Boolean;
|
||||
private
|
||||
function SkipSimpleInstructions(var hp1: tai): Boolean;
|
||||
|
||||
@ -246,6 +251,9 @@ unit aoptx86;
|
||||
|
||||
function RefsEqual(const r1, r2: treference): boolean;
|
||||
|
||||
{ Like RefsEqual, but doesn't compare the offsets }
|
||||
function RefsAlmostEqual(const r1, r2: treference): boolean;
|
||||
|
||||
{ Note that Result is set to True if the references COULD overlap but the
|
||||
compiler cannot be sure (e.g. "(%reg1)" and "4(%reg2)" with a range of 4
|
||||
might still overlap because %reg2 could be equal to %reg1-4 }
|
||||
@ -481,6 +489,18 @@ unit aoptx86;
|
||||
end;
|
||||
|
||||
|
||||
function RefsAlmostEqual(const r1, r2: treference): boolean;
|
||||
begin
|
||||
RefsAlmostEqual :=
|
||||
(r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
|
||||
(r1.relsymbol = r2.relsymbol) and
|
||||
(r1.segment = r2.segment) and (r1.base = r2.base) and
|
||||
(r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
|
||||
{ Don't compare the offsets }
|
||||
(r1.volatility + r2.volatility = []);
|
||||
end;
|
||||
|
||||
|
||||
function RefsMightOverlap(const r1, r2: treference; const Range: asizeint): boolean;
|
||||
begin
|
||||
if (r1.symbol<>r2.symbol) then
|
||||
@ -1316,6 +1336,63 @@ unit aoptx86;
|
||||
end;
|
||||
|
||||
|
||||
function TX86AsmOptimizer.RefModifiedBetween(Ref: TReference; RefSize: ASizeInt; p1, p2: tai): Boolean;
|
||||
const
|
||||
WriteOps: array[0..3] of set of TInsChange =
|
||||
([CH_RWOP1,CH_WOP1,CH_MOP1],
|
||||
[Ch_RWOP2,Ch_WOP2,Ch_MOP2],
|
||||
[Ch_RWOP3,Ch_WOP3,Ch_MOP3],
|
||||
[Ch_RWOP4,Ch_WOP4,Ch_MOP4]);
|
||||
var
|
||||
X: Integer;
|
||||
CurrentP1Size: asizeint;
|
||||
begin
|
||||
Result := (
|
||||
(Ref.base <> NR_NO) and
|
||||
{$ifdef x86_64}
|
||||
(Ref.base <> NR_RIP) and
|
||||
{$endif x86_64}
|
||||
RegModifiedBetween(Ref.base, p1, p2)
|
||||
) or
|
||||
(
|
||||
(Ref.index <> NR_NO) and
|
||||
(Ref.index <> Ref.base) and
|
||||
RegModifiedBetween(Ref.index, p1, p2)
|
||||
);
|
||||
|
||||
{ Now check to see if the memory itself is written to }
|
||||
if not Result then
|
||||
begin
|
||||
while assigned(p1) and assigned(p2) and GetNextInstruction(p1,p1) and (p1<>p2) do
|
||||
if p1.typ = ait_instruction then
|
||||
begin
|
||||
CurrentP1Size := topsize2memsize[taicpu(p1).opsize] shr 3; { Convert to bytes }
|
||||
with insprop[taicpu(p1).opcode] do
|
||||
for X := 0 to taicpu(p1).ops - 1 do
|
||||
if (taicpu(p1).oper[X]^.typ = top_ref) and
|
||||
RefsAlmostEqual(Ref, taicpu(p1).oper[X]^.ref^) and
|
||||
{ Catch any potential overlaps }
|
||||
(
|
||||
(RefSize = 0) or
|
||||
((taicpu(p1).oper[X]^.ref^.offset - Ref.offset) < RefSize)
|
||||
) and
|
||||
(
|
||||
(CurrentP1Size = 0) or
|
||||
((Ref.offset - taicpu(p1).oper[X]^.ref^.offset) < CurrentP1Size)
|
||||
) and
|
||||
{ Reference is used, but does the instruction write to it? }
|
||||
(
|
||||
(Ch_All in Ch) or
|
||||
((WriteOps[X] * Ch) <> [])
|
||||
) then
|
||||
begin
|
||||
Result := True;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{$ifdef DEBUG_AOPTCPU}
|
||||
procedure TX86AsmOptimizer.DebugMsg(const s: string;p : tai);
|
||||
begin
|
||||
|
Loading…
Reference in New Issue
Block a user