mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 03:48:07 +02:00
o refactored some peephole optimizer code:
* updated TAOptObj.RegUsedAfterInstruction with the arm implementation and removed the arm specific implementation * RegLoadedWithNewValue and InstructionLoadsFromReg are now a methods of TAoptBase * moved RegEndOfLife to TAOptObj * during this refactoring, fixed also TCpuAsmOptimizer.RegLoadedWithNewValue for arm regarding post/preindexed memory references: those modify the register but do not load it with a new value in the sense of RegLoadedWithNewValue git-svn-id: trunk@33000 -
This commit is contained in:
parent
273f88a54c
commit
1266491085
@ -95,6 +95,12 @@ unit aoptbase;
|
||||
|
||||
{ returns true if reg is modified by any instruction between p1 and p2 }
|
||||
function RegModifiedBetween(reg: TRegister; p1, p2: tai): Boolean;
|
||||
|
||||
{ returns true if reg is loaded with a new value by hp }
|
||||
function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; Virtual;
|
||||
|
||||
{ returns true if hp loads a value from reg }
|
||||
function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; Virtual;
|
||||
end;
|
||||
|
||||
function labelCanBeSkipped(p: tai_label): boolean;
|
||||
@ -285,6 +291,20 @@ unit aoptbase;
|
||||
end;
|
||||
|
||||
|
||||
function TAoptBase.RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean;
|
||||
begin
|
||||
{ save approximation }
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
|
||||
function TAoptBase.InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean;
|
||||
begin
|
||||
{ save approximation }
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
|
||||
{ ******************* Processor dependent stuff *************************** }
|
||||
|
||||
Function TAOptBase.RegMaxSize(Reg: TRegister): TRegister;
|
||||
|
@ -315,6 +315,10 @@ Unit AoptObj;
|
||||
{ reg used after p? }
|
||||
function RegUsedAfterInstruction(reg: Tregister; p: tai; var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
|
||||
{ returns true if reg reaches it's end of life at p, this means it is either
|
||||
reloaded with a new value or it is deallocated afterwards }
|
||||
function RegEndOfLife(reg: TRegister;p: taicpu): boolean;
|
||||
|
||||
{ traces sucessive jumps to their final destination and sets it, e.g.
|
||||
je l1 je l3
|
||||
<code> <code>
|
||||
@ -1117,15 +1121,25 @@ Unit AoptObj;
|
||||
End;
|
||||
|
||||
|
||||
function TAOptObj.RegUsedAfterInstruction(reg: Tregister; p: tai;
|
||||
var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
begin
|
||||
AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
|
||||
RegUsedAfterInstruction :=
|
||||
(AllUsedRegs[getregtype(reg)].IsUsed(reg)); { optimization and
|
||||
(not(getNextInstruction(p,p)) or
|
||||
not(regLoadedWithNewValue(supreg,false,p))); }
|
||||
end;
|
||||
function TAOptObj.RegUsedAfterInstruction(reg: Tregister; p: tai;var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
begin
|
||||
AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
|
||||
RegUsedAfterInstruction :=
|
||||
AllUsedRegs[getregtype(reg)].IsUsed(reg) and
|
||||
not(regLoadedWithNewValue(reg,p)) and
|
||||
(
|
||||
not(GetNextInstruction(p,p)) or
|
||||
InstructionLoadsFromReg(reg,p) or
|
||||
not(regLoadedWithNewValue(reg,p))
|
||||
);
|
||||
end;
|
||||
|
||||
|
||||
function TAOptObj.RegEndOfLife(reg : TRegister;p : taicpu) : boolean;
|
||||
begin
|
||||
Result:=assigned(FindRegDealloc(reg,tai(p.Next))) or
|
||||
RegLoadedWithNewValue(reg,p);
|
||||
end;
|
||||
|
||||
|
||||
function SkipLabels(hp: tai; var hp2: tai): boolean;
|
||||
|
@ -39,11 +39,7 @@ Type
|
||||
procedure PeepHoleOptPass2;override;
|
||||
Function RegInInstruction(Reg: TRegister; p1: tai): Boolean;override;
|
||||
function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
|
||||
function RegUsedAfterInstruction(reg: Tregister; p: tai;
|
||||
var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
{ returns true if reg reaches it's end of life at p, this means it is either
|
||||
reloaded with a new value or it is deallocated afterwards }
|
||||
function RegEndOfLife(reg: TRegister;p: taicpu): boolean;
|
||||
|
||||
{ gets the next tai object after current that contains info relevant
|
||||
to the optimizer in p1 which used the given register or does a
|
||||
change in program flow.
|
||||
@ -55,6 +51,9 @@ Type
|
||||
{ outputs a debug message into the assembler file }
|
||||
procedure DebugMsg(const s: string; p: tai);
|
||||
|
||||
function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
|
||||
|
||||
function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
|
||||
protected
|
||||
function LookForPreindexedPattern(p: taicpu): boolean;
|
||||
function LookForPostindexedPattern(p: taicpu): boolean;
|
||||
@ -167,67 +166,6 @@ Implementation
|
||||
end;
|
||||
end;
|
||||
|
||||
function regLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
p := taicpu(hp);
|
||||
regLoadedWithNewValue := false;
|
||||
if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These operands do not write into a register at all }
|
||||
A_CMP, A_CMN, A_TST, A_TEQ, A_B, A_BL, A_BX, A_BLX, A_SWI, A_MSR, A_PLD:
|
||||
exit;
|
||||
{Take care of post/preincremented store and loads, they will change their base register}
|
||||
A_STR, A_LDR:
|
||||
begin
|
||||
regLoadedWithNewValue :=
|
||||
(taicpu(p).oper[1]^.typ=top_ref) and
|
||||
(taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
|
||||
(taicpu(p).oper[1]^.ref^.base = reg);
|
||||
{STR does not load into it's first register}
|
||||
if p.opcode = A_STR then exit;
|
||||
end;
|
||||
{ These four are writing into the first 2 register, UMLAL and SMLAL will also read from them }
|
||||
A_UMLAL, A_UMULL, A_SMLAL, A_SMULL:
|
||||
regLoadedWithNewValue :=
|
||||
(p.oper[1]^.typ = top_reg) and
|
||||
(p.oper[1]^.reg = reg);
|
||||
{Loads to oper2 from coprocessor}
|
||||
{
|
||||
MCR/MRC is currently not supported in FPC
|
||||
A_MRC:
|
||||
regLoadedWithNewValue :=
|
||||
(p.oper[2]^.typ = top_reg) and
|
||||
(p.oper[2]^.reg = reg);
|
||||
}
|
||||
{Loads to all register in the registerset}
|
||||
A_LDM:
|
||||
regLoadedWithNewValue := (getsupreg(reg) in p.oper[1]^.regset^);
|
||||
A_POP:
|
||||
regLoadedWithNewValue := (getsupreg(reg) in p.oper[0]^.regset^) or
|
||||
(reg=NR_STACK_POINTER_REG);
|
||||
end;
|
||||
|
||||
if regLoadedWithNewValue then
|
||||
exit;
|
||||
|
||||
case p.oper[0]^.typ of
|
||||
{This is the case}
|
||||
top_reg:
|
||||
regLoadedWithNewValue := (p.oper[0]^.reg = reg) or
|
||||
{ LDRD }
|
||||
(p.opcode=A_LDR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg));
|
||||
{LDM/STM might write a new value to their index register}
|
||||
top_ref:
|
||||
regLoadedWithNewValue :=
|
||||
(taicpu(p).oper[0]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
|
||||
(taicpu(p).oper[0]^.ref^.base = reg);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function AlignedToQWord(const ref : treference) : boolean;
|
||||
begin
|
||||
@ -249,44 +187,6 @@ Implementation
|
||||
end;
|
||||
|
||||
|
||||
function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
i: longint;
|
||||
begin
|
||||
instructionLoadsFromReg := false;
|
||||
if not (assigned(hp) and (hp.typ = ait_instruction)) then
|
||||
exit;
|
||||
p:=taicpu(hp);
|
||||
|
||||
i:=1;
|
||||
{For these instructions we have to start on oper[0]}
|
||||
if (p.opcode in [A_STR, A_LDM, A_STM, A_PLD,
|
||||
A_CMP, A_CMN, A_TST, A_TEQ,
|
||||
A_B, A_BL, A_BX, A_BLX,
|
||||
A_SMLAL, A_UMLAL]) then i:=0;
|
||||
|
||||
while(i<p.ops) do
|
||||
begin
|
||||
case p.oper[I]^.typ of
|
||||
top_reg:
|
||||
instructionLoadsFromReg := (p.oper[I]^.reg = reg) or
|
||||
{ STRD }
|
||||
((i=0) and (p.opcode=A_STR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg)));
|
||||
top_regset:
|
||||
instructionLoadsFromReg := (getsupreg(reg) in p.oper[I]^.regset^);
|
||||
top_shifterop:
|
||||
instructionLoadsFromReg := p.oper[I]^.shifterop^.rs = reg;
|
||||
top_ref:
|
||||
instructionLoadsFromReg :=
|
||||
(p.oper[I]^.ref^.base = reg) or
|
||||
(p.oper[I]^.ref^.index = reg);
|
||||
end;
|
||||
if instructionLoadsFromReg then exit; {Bailout if we found something}
|
||||
Inc(I);
|
||||
end;
|
||||
end;
|
||||
|
||||
function isValidConstLoadStoreOffset(const aoffset: longint; const pf: TOpPostfix) : boolean;
|
||||
begin
|
||||
if GenerateThumb2Code then
|
||||
@ -297,27 +197,112 @@ Implementation
|
||||
(abs(aoffset)<256);
|
||||
end;
|
||||
|
||||
function TCpuAsmOptimizer.RegUsedAfterInstruction(reg: Tregister; p: tai;
|
||||
var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
|
||||
function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
i: longint;
|
||||
begin
|
||||
AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
|
||||
RegUsedAfterInstruction :=
|
||||
AllUsedRegs[getregtype(reg)].IsUsed(reg) and
|
||||
not(regLoadedWithNewValue(reg,p)) and
|
||||
(
|
||||
not(GetNextInstruction(p,p)) or
|
||||
instructionLoadsFromReg(reg,p) or
|
||||
not(regLoadedWithNewValue(reg,p))
|
||||
);
|
||||
instructionLoadsFromReg := false;
|
||||
if not (assigned(hp) and (hp.typ = ait_instruction)) then
|
||||
exit;
|
||||
p:=taicpu(hp);
|
||||
|
||||
i:=1;
|
||||
{For these instructions we have to start on oper[0]}
|
||||
if (p.opcode in [A_STR, A_LDM, A_STM, A_PLD,
|
||||
A_CMP, A_CMN, A_TST, A_TEQ,
|
||||
A_B, A_BL, A_BX, A_BLX,
|
||||
A_SMLAL, A_UMLAL]) then i:=0;
|
||||
|
||||
while(i<p.ops) do
|
||||
begin
|
||||
case p.oper[I]^.typ of
|
||||
top_reg:
|
||||
instructionLoadsFromReg := (p.oper[I]^.reg = reg) or
|
||||
{ STRD }
|
||||
((i=0) and (p.opcode=A_STR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg)));
|
||||
top_regset:
|
||||
instructionLoadsFromReg := (getsupreg(reg) in p.oper[I]^.regset^);
|
||||
top_shifterop:
|
||||
instructionLoadsFromReg := p.oper[I]^.shifterop^.rs = reg;
|
||||
top_ref:
|
||||
instructionLoadsFromReg :=
|
||||
(p.oper[I]^.ref^.base = reg) or
|
||||
(p.oper[I]^.ref^.index = reg);
|
||||
end;
|
||||
if instructionLoadsFromReg then exit; {Bailout if we found something}
|
||||
Inc(I);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.RegEndOfLife(reg : TRegister;p : taicpu) : boolean;
|
||||
function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
Result:=assigned(FindRegDealloc(reg,tai(p.Next))) or
|
||||
RegLoadedWithNewValue(reg,p);
|
||||
p := taicpu(hp);
|
||||
Result := false;
|
||||
if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These operands do not write into a register at all }
|
||||
A_CMP, A_CMN, A_TST, A_TEQ, A_B, A_BL, A_BX, A_BLX, A_SWI, A_MSR, A_PLD:
|
||||
exit;
|
||||
{Take care of post/preincremented store and loads, they will change their base register}
|
||||
A_STR, A_LDR:
|
||||
begin
|
||||
Result := false;
|
||||
{ actually, this does not apply here because post-/preindexed does not mean that a register
|
||||
is loaded with a new value, it is only modified
|
||||
(taicpu(p).oper[1]^.typ=top_ref) and
|
||||
(taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
|
||||
(taicpu(p).oper[1]^.ref^.base = reg);
|
||||
}
|
||||
{ STR does not load into it's first register }
|
||||
if p.opcode = A_STR then
|
||||
exit;
|
||||
end;
|
||||
{ These four are writing into the first 2 register, UMLAL and SMLAL will also read from them }
|
||||
A_UMLAL, A_UMULL, A_SMLAL, A_SMULL:
|
||||
Result :=
|
||||
(p.oper[1]^.typ = top_reg) and
|
||||
(p.oper[1]^.reg = reg);
|
||||
{Loads to oper2 from coprocessor}
|
||||
{
|
||||
MCR/MRC is currently not supported in FPC
|
||||
A_MRC:
|
||||
Result :=
|
||||
(p.oper[2]^.typ = top_reg) and
|
||||
(p.oper[2]^.reg = reg);
|
||||
}
|
||||
{Loads to all register in the registerset}
|
||||
A_LDM:
|
||||
Result := (getsupreg(reg) in p.oper[1]^.regset^);
|
||||
A_POP:
|
||||
Result := (getsupreg(reg) in p.oper[0]^.regset^) or
|
||||
(reg=NR_STACK_POINTER_REG);
|
||||
end;
|
||||
|
||||
if Result then
|
||||
exit;
|
||||
|
||||
case p.oper[0]^.typ of
|
||||
{This is the case}
|
||||
top_reg:
|
||||
Result := (p.oper[0]^.reg = reg) or
|
||||
{ LDRD }
|
||||
(p.opcode=A_LDR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg));
|
||||
{LDM/STM might write a new value to their index register}
|
||||
top_ref:
|
||||
Result :=
|
||||
(taicpu(p).oper[0]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
|
||||
(taicpu(p).oper[0]^.ref^.base = reg);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
|
||||
Out Next: tai; reg: TRegister): Boolean;
|
||||
begin
|
||||
|
@ -42,6 +42,8 @@ unit aoptcpu;
|
||||
function TryRemoveMovBeforeStore(var p: tai; next: taicpu; const storeops: TAsmOpSet): boolean;
|
||||
function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
|
||||
procedure PeepHoleOptPass2; override;
|
||||
function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
|
||||
function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
@ -73,29 +75,6 @@ unit aoptcpu;
|
||||
end;
|
||||
|
||||
|
||||
function regLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
p:=taicpu(hp);
|
||||
result:=false;
|
||||
if not ((assigned(hp)) and (hp.typ=ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These instructions do not write into a register at all }
|
||||
A_NOP,
|
||||
A_C_EQ_D,A_C_EQ_S,A_C_LE_D,A_C_LE_S,A_C_LT_D,A_C_LT_S,
|
||||
A_BA,A_BC,
|
||||
A_SB,A_SH,A_SW,A_SWL,A_SWR,A_SWC1,A_SDC1:
|
||||
exit;
|
||||
end;
|
||||
|
||||
result:=(p.ops>0) and (p.oper[0]^.typ=top_reg) and
|
||||
(p.oper[0]^.reg=reg);
|
||||
end;
|
||||
|
||||
|
||||
function CanBeCMOV(p: tai; condreg: tregister): boolean;
|
||||
begin
|
||||
result:=assigned(p) and (p.typ=ait_instruction) and
|
||||
@ -151,7 +130,7 @@ unit aoptcpu;
|
||||
end;
|
||||
|
||||
|
||||
function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
i: longint;
|
||||
@ -178,6 +157,29 @@ unit aoptcpu;
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
p:=taicpu(hp);
|
||||
result:=false;
|
||||
if not ((assigned(hp)) and (hp.typ=ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These instructions do not write into a register at all }
|
||||
A_NOP,
|
||||
A_C_EQ_D,A_C_EQ_S,A_C_LE_D,A_C_LE_S,A_C_LT_D,A_C_LT_S,
|
||||
A_BA,A_BC,
|
||||
A_SB,A_SH,A_SW,A_SWL,A_SWR,A_SWC1,A_SDC1:
|
||||
exit;
|
||||
end;
|
||||
|
||||
result:=(p.ops>0) and (p.oper[0]^.typ=top_reg) and
|
||||
(p.oper[0]^.reg=reg);
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean;
|
||||
var
|
||||
i : Longint;
|
||||
|
@ -38,6 +38,8 @@ unit aoptcpu;
|
||||
function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
|
||||
function RegUsedAfterInstruction(reg: Tregister; p: tai;
|
||||
var AllUsedRegs: TAllUsedRegs): Boolean;
|
||||
function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
|
||||
function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
@ -69,30 +71,7 @@ unit aoptcpu;
|
||||
end;
|
||||
|
||||
|
||||
function regLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
p:=taicpu(hp);
|
||||
result:=false;
|
||||
if not ((assigned(hp)) and (hp.typ=ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These instructions do not write into a register at all }
|
||||
A_NOP,
|
||||
A_FCMPs,A_FCMPd,A_FCMPq,A_CMP,
|
||||
A_BA,A_Bxx,A_FBA,A_FBxx,
|
||||
A_STB,A_STH,A_ST,A_STF,A_STDF:
|
||||
exit;
|
||||
end;
|
||||
|
||||
result:=(p.ops>0) and (p.oper[p.ops-1]^.typ=top_reg) and
|
||||
(p.oper[p.ops-1]^.reg=reg);
|
||||
end;
|
||||
|
||||
|
||||
function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
i: longint;
|
||||
@ -119,6 +98,29 @@ unit aoptcpu;
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
|
||||
var
|
||||
p: taicpu;
|
||||
begin
|
||||
p:=taicpu(hp);
|
||||
result:=false;
|
||||
if not ((assigned(hp)) and (hp.typ=ait_instruction)) then
|
||||
exit;
|
||||
|
||||
case p.opcode of
|
||||
{ These instructions do not write into a register at all }
|
||||
A_NOP,
|
||||
A_FCMPs,A_FCMPd,A_FCMPq,A_CMP,
|
||||
A_BA,A_Bxx,A_FBA,A_FBxx,
|
||||
A_STB,A_STH,A_ST,A_STF,A_STDF:
|
||||
exit;
|
||||
end;
|
||||
|
||||
result:=(p.ops>0) and (p.oper[p.ops-1]^.typ=top_reg) and
|
||||
(p.oper[p.ops-1]^.reg=reg);
|
||||
end;
|
||||
|
||||
|
||||
function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
|
||||
var Next: tai; reg: TRegister): Boolean;
|
||||
begin
|
||||
|
Loading…
Reference in New Issue
Block a user