* arm/a64: New "OptPass2TST" routine to catch "TST; B.c; AND -> ANDS; B.c" optimisation

This commit is contained in:
J. Gareth "Curious Kit" Moreton 2023-10-28 00:26:08 +01:00 committed by FPK
parent 9f19f582c4
commit b18c10d0d8
3 changed files with 120 additions and 0 deletions

View File

@ -1266,6 +1266,8 @@ Implementation
A_LDR,
A_STR:
Result:=OptPass2LDRSTR(p);
A_TST:
Result := OptPass2TST(p);
else
;
end;

View File

@ -2396,6 +2396,8 @@ Implementation
Result := OptPass2STM(p);
A_STR:
Result := OptPass2STR(p);
A_TST:
Result := OptPass2TST(p);
else
;
end;

View File

@ -59,6 +59,7 @@ Type
function OptPass1And(var p: tai): Boolean; virtual;
function OptPass2AND(var p: tai): Boolean;
function OptPass2TST(var p: tai): Boolean;
End;
function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
@ -1692,5 +1693,120 @@ Implementation
Result:=true;
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.