mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-03 20:50:39 +02:00
* arm/a64: New "OptPass2TST" routine to catch "TST; B.c; AND -> ANDS; B.c" optimisation
This commit is contained in:
parent
9f19f582c4
commit
b18c10d0d8
@ -1266,6 +1266,8 @@ Implementation
|
|||||||
A_LDR,
|
A_LDR,
|
||||||
A_STR:
|
A_STR:
|
||||||
Result:=OptPass2LDRSTR(p);
|
Result:=OptPass2LDRSTR(p);
|
||||||
|
A_TST:
|
||||||
|
Result := OptPass2TST(p);
|
||||||
else
|
else
|
||||||
;
|
;
|
||||||
end;
|
end;
|
||||||
|
@ -2396,6 +2396,8 @@ Implementation
|
|||||||
Result := OptPass2STM(p);
|
Result := OptPass2STM(p);
|
||||||
A_STR:
|
A_STR:
|
||||||
Result := OptPass2STR(p);
|
Result := OptPass2STR(p);
|
||||||
|
A_TST:
|
||||||
|
Result := OptPass2TST(p);
|
||||||
else
|
else
|
||||||
;
|
;
|
||||||
end;
|
end;
|
||||||
|
@ -59,6 +59,7 @@ Type
|
|||||||
function OptPass1And(var p: tai): Boolean; virtual;
|
function OptPass1And(var p: tai): Boolean; virtual;
|
||||||
|
|
||||||
function OptPass2AND(var p: tai): Boolean;
|
function OptPass2AND(var p: tai): Boolean;
|
||||||
|
function OptPass2TST(var p: tai): Boolean;
|
||||||
End;
|
End;
|
||||||
|
|
||||||
function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
|
function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
|
||||||
@ -1692,5 +1693,120 @@ Implementation
|
|||||||
Result:=true;
|
Result:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TARMAsmOptimizer.OptPass2TST(var p: tai): Boolean;
|
||||||
|
var
|
||||||
|
hp1, hp2: tai;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
if
|
||||||
|
{$ifndef AARCH64}
|
||||||
|
(taicpu(p).condition = C_None) and
|
||||||
|
{$endif AARCH64}
|
||||||
|
GetNextInstruction(p, hp1) and
|
||||||
|
MatchInstruction(hp1, A_B, [C_EQ, C_NE], [PF_None]) and
|
||||||
|
GetNextInstructionUsingReg(hp1, hp2, taicpu(p).oper[0]^.reg) then
|
||||||
|
begin
|
||||||
|
case taicpu(hp2).opcode of
|
||||||
|
A_AND:
|
||||||
|
{ Change:
|
||||||
|
tst r1,##
|
||||||
|
(r2 not in use, or r2 = r1)
|
||||||
|
b.c .Lbl
|
||||||
|
...
|
||||||
|
and r2,r1,##
|
||||||
|
|
||||||
|
Optimise to:
|
||||||
|
ands r2,r1,##
|
||||||
|
b.c .Lbl
|
||||||
|
...
|
||||||
|
}
|
||||||
|
if (taicpu(hp2).oppostfix in [PF_None, PF_S]) and
|
||||||
|
{$ifndef AARCH64}
|
||||||
|
(taicpu(hp2).condition = C_None) and
|
||||||
|
{$endif AARCH64}
|
||||||
|
(taicpu(hp2).ops = taicpu(p).ops + 1) and
|
||||||
|
not RegInUsedRegs(taicpu(hp2).oper[0]^.reg, UsedRegs) and
|
||||||
|
MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[0]^.reg) and
|
||||||
|
MatchOperand(taicpu(hp2).oper[2]^, taicpu(p).oper[1]^) and
|
||||||
|
(
|
||||||
|
(taicpu(hp2).ops = 3) or
|
||||||
|
MatchOperand(taicpu(hp2).oper[3]^, taicpu(p).oper[2]^)
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not (cs_opt_level3 in current_settings.optimizerswitches) or
|
||||||
|
(
|
||||||
|
{ Make sure the target register isn't used in between }
|
||||||
|
not RegUsedBetween(taicpu(hp2).oper[0]^.reg, hp1, hp2) and
|
||||||
|
(
|
||||||
|
{ If the second operand is a register, make sure it isn't modified in between }
|
||||||
|
(taicpu(p).oper[1]^.typ <> top_reg) or
|
||||||
|
not RegModifiedBetween(taicpu(p).oper[1]^.reg, hp1, hp2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) then
|
||||||
|
begin
|
||||||
|
AllocRegBetween(taicpu(hp2).oper[0]^.reg, p, hp2, UsedRegs);
|
||||||
|
|
||||||
|
if (taicpu(hp2).oppostfix = PF_S) then
|
||||||
|
AllocRegBetween(NR_DEFAULTFLAGS, p, hp2, UsedRegs);
|
||||||
|
|
||||||
|
DebugMsg(SPeepholeOptimization + 'TST; B.c; AND -> ANDS; B.c (TstBcAnd2AndsBc)', p);
|
||||||
|
taicpu(hp2).oppostfix := PF_S;
|
||||||
|
|
||||||
|
Asml.Remove(hp2);
|
||||||
|
Asml.InsertAfter(hp2, p);
|
||||||
|
|
||||||
|
RemoveCurrentP(p, hp2);
|
||||||
|
Result := True;
|
||||||
|
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
A_TST:
|
||||||
|
{ Change:
|
||||||
|
tst r1,##
|
||||||
|
b.c .Lbl
|
||||||
|
... (flags not modified)
|
||||||
|
tst r1,##
|
||||||
|
|
||||||
|
Remove second tst
|
||||||
|
}
|
||||||
|
if
|
||||||
|
{$ifndef AARCH64}
|
||||||
|
(taicpu(hp2).condition = C_None) and
|
||||||
|
{$endif AARCH64}
|
||||||
|
(taicpu(hp2).ops = taicpu(p).ops) and
|
||||||
|
MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^.reg) and
|
||||||
|
MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[1]^) and
|
||||||
|
(
|
||||||
|
(taicpu(hp2).ops = 2) or
|
||||||
|
MatchOperand(taicpu(hp2).oper[2]^, taicpu(p).oper[2]^)
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not (cs_opt_level3 in current_settings.optimizerswitches) or
|
||||||
|
(
|
||||||
|
{ Make sure the flags aren't modified in between }
|
||||||
|
not RegModifiedBetween(NR_DEFAULTFLAGS, hp1, hp2) and
|
||||||
|
(
|
||||||
|
{ If the second operand is a register, make sure it isn't modified in between }
|
||||||
|
(taicpu(p).oper[1]^.typ <> top_reg) or
|
||||||
|
not RegModifiedBetween(taicpu(p).oper[1]^.reg, hp1, hp2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) then
|
||||||
|
begin
|
||||||
|
DebugMsg(SPeepholeOptimization + 'TST; B.c; TST -> TST; B.c (TstBcTst2TstBc)', p);
|
||||||
|
|
||||||
|
AllocRegBetween(NR_DEFAULTFLAGS, hp1, hp2, UsedRegs);
|
||||||
|
RemoveInstruction(hp2);
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user