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:
florian 2016-01-24 15:25:16 +00:00
parent 273f88a54c
commit 1266491085
5 changed files with 198 additions and 175 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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