mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-04 14:10:22 +02:00
* x86: New Op/TEST optimisation that rearranges register usage for the most efficient execution
This commit is contained in:
parent
7c609ee7c4
commit
948766a37a
@ -12506,10 +12506,82 @@ unit aoptx86;
|
|||||||
function TX86AsmOptimizer.OptPass2Test(var p: tai): Boolean;
|
function TX86AsmOptimizer.OptPass2Test(var p: tai): Boolean;
|
||||||
var
|
var
|
||||||
hp1, hp2, pCond: tai;
|
hp1, hp2, pCond: tai;
|
||||||
|
SourceReg, TargetReg: TRegister;
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
|
|
||||||
{ Search ahead for CMOV instructions }
|
{ In some situations, we end up with an inefficient arrangement of
|
||||||
|
instructions in the form of:
|
||||||
|
|
||||||
|
or %reg1,%reg2
|
||||||
|
(%reg1 deallocated)
|
||||||
|
test %reg2,%reg2
|
||||||
|
mov x,%reg2
|
||||||
|
|
||||||
|
we may be able to swap and rearrange the registers to produce:
|
||||||
|
|
||||||
|
or %reg2,%reg1
|
||||||
|
mov x,%reg2
|
||||||
|
test %reg1,%reg1
|
||||||
|
(%reg1 deallocated)
|
||||||
|
}
|
||||||
|
if (cs_opt_level3 in current_settings.optimizerswitches) and
|
||||||
|
(taicpu(p).oper[1]^.typ = top_reg) and
|
||||||
|
(
|
||||||
|
MatchOperand(taicpu(p).oper[0]^, taicpu(p).oper[1]^.reg) or
|
||||||
|
MatchOperand(taicpu(p).oper[0]^, -1)
|
||||||
|
) and
|
||||||
|
GetNextInstruction(p, hp1) and
|
||||||
|
MatchInstruction(hp1, A_MOV, []) and
|
||||||
|
(taicpu(hp1).oper[1]^.typ = top_reg) and
|
||||||
|
SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, taicpu(p).oper[1]^.reg) then
|
||||||
|
begin
|
||||||
|
TargetReg := taicpu(p).oper[1]^.reg;
|
||||||
|
|
||||||
|
{ Now look backwards to find a simple commutative operation: ADD,
|
||||||
|
IMUL (2-register version), OR, AND or XOR - whose destination
|
||||||
|
register is the same as TEST }
|
||||||
|
hp2 := p;
|
||||||
|
while GetLastInstruction(hp2, hp2) and (hp2.typ = ait_instruction) do
|
||||||
|
if RegInInstruction(TargetReg, hp2) then
|
||||||
|
begin
|
||||||
|
if MatchInstruction(hp2, [A_ADD, A_IMUL, A_OR, A_AND, A_XOR], [taicpu(p).opsize]) and
|
||||||
|
MatchOpType(taicpu(hp2), top_reg, top_reg) and
|
||||||
|
(taicpu(hp2).oper[1]^.reg = TargetReg) and
|
||||||
|
(taicpu(hp2).oper[0]^.reg <> TargetReg) then
|
||||||
|
begin
|
||||||
|
SourceReg := taicpu(hp2).oper[0]^.reg;
|
||||||
|
|
||||||
|
if
|
||||||
|
{ Make sure the MOV doesn't use the other register }
|
||||||
|
not RegInOp(SourceReg, taicpu(hp1).oper[0]^) and
|
||||||
|
{ And make sure the source register is not used afterwards }
|
||||||
|
not RegInUsedRegs(SourceReg, UsedRegs) then
|
||||||
|
begin
|
||||||
|
DebugMsg(SPeepholeOptimization + 'OpTest2OpTest (register swap) done', hp2);
|
||||||
|
|
||||||
|
taicpu(hp2).oper[0]^.reg := TargetReg;
|
||||||
|
taicpu(hp2).oper[1]^.reg := SourceReg;
|
||||||
|
|
||||||
|
if taicpu(p).oper[0]^.typ = top_reg then
|
||||||
|
taicpu(p).oper[0]^.reg := SourceReg;
|
||||||
|
|
||||||
|
taicpu(p).oper[1]^.reg := SourceReg;
|
||||||
|
|
||||||
|
IncludeRegInUsedRegs(SourceReg, UsedRegs);
|
||||||
|
AllocRegBetween(SourceReg, hp2, p, UsedRegs);
|
||||||
|
|
||||||
|
Include(OptsToCheck, aoc_ForceNewIteration);
|
||||||
|
{ We can still check the following optimisations since
|
||||||
|
the instruction is still a TEST }
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Search ahead3 for CMOV instructions }
|
||||||
if (cs_opt_level2 in current_settings.optimizerswitches) then
|
if (cs_opt_level2 in current_settings.optimizerswitches) then
|
||||||
begin
|
begin
|
||||||
hp1 := p;
|
hp1 := p;
|
||||||
|
Loading…
Reference in New Issue
Block a user