mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-16 17:39:20 +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 GetNextInstructionUsingRegTrackingUse(Current: tai; out Next: tai; reg: TRegister): Boolean;
|
||||||
function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
|
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
|
private
|
||||||
function SkipSimpleInstructions(var hp1: tai): Boolean;
|
function SkipSimpleInstructions(var hp1: tai): Boolean;
|
||||||
|
|
||||||
@ -246,6 +251,9 @@ unit aoptx86;
|
|||||||
|
|
||||||
function RefsEqual(const r1, r2: treference): boolean;
|
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
|
{ 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
|
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 }
|
might still overlap because %reg2 could be equal to %reg1-4 }
|
||||||
@ -481,6 +489,18 @@ unit aoptx86;
|
|||||||
end;
|
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;
|
function RefsMightOverlap(const r1, r2: treference; const Range: asizeint): boolean;
|
||||||
begin
|
begin
|
||||||
if (r1.symbol<>r2.symbol) then
|
if (r1.symbol<>r2.symbol) then
|
||||||
@ -1316,6 +1336,63 @@ unit aoptx86;
|
|||||||
end;
|
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}
|
{$ifdef DEBUG_AOPTCPU}
|
||||||
procedure TX86AsmOptimizer.DebugMsg(const s: string;p : tai);
|
procedure TX86AsmOptimizer.DebugMsg(const s: string;p : tai);
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user