fpc/compiler/xtensa/aoptcpu.pas

302 lines
8.5 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
Development Team
This unit implements the ARM64 optimizer object
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
Unit aoptcpu;
{$i fpcdefs.inc}
{$ifdef EXTDEBUG}
{$define DEBUG_AOPTCPU}
{$endif EXTDEBUG}
Interface
uses
globtype, globals,
cutils,
cgbase, cpubase, aasmtai, aasmcpu, aopt, aoptcpub;
Type
TCpuAsmOptimizer = class(TAsmOptimizer)
function CanDoJumpOpts: Boolean; override;
{ uses the same constructor as TAopObj }
function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;override;
function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;override;
function GetNextInstructionUsingReg(Current : tai; out Next : tai; reg : TRegister) : Boolean;
procedure DebugMsg(const s : string; p : tai);
function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
private
function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
End;
Implementation
uses
aasmbase,
aoptutils,
cgutils,
verbose;
{$ifdef DEBUG_AOPTCPU}
procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
begin
asml.insertbefore(tai_comment.Create(strpnew(s)), p);
end;
{$else DEBUG_AOPTCPU}
procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
begin
end;
{$endif DEBUG_AOPTCPU}
function CanBeCond(p : tai) : boolean;
begin
result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
end;
function TCpuAsmOptimizer.CanDoJumpOpts: Boolean;
begin
Result := true;
end;
function RefsEqual(const r1, r2: treference): boolean;
begin
refsequal :=
(r1.offset = r2.offset) and
(r1.base = r2.base) and
(r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
(r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
(r1.relsymbol = r2.relsymbol) and
(r1.volatility=[]) and
(r2.volatility=[]);
end;
function MatchInstruction(const instr: tai; const op: TAsmOp; const postfix: TOpPostfixes): boolean;
begin
result :=
(instr.typ = ait_instruction) and
(taicpu(instr).opcode = op) and
((postfix = []) or (taicpu(instr).oppostfix in postfix));
end;
function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
begin
result := (oper.typ = top_reg) and (oper.reg = reg);
end;
function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
begin
result := oper1.typ = oper2.typ;
if result then
case oper1.typ of
top_const:
Result:=oper1.val = oper2.val;
top_reg:
Result:=oper1.reg = oper2.reg;
top_ref:
Result:=RefsEqual(oper1.ref^, oper2.ref^);
else Result:=false;
end
end;
function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
Out Next: tai; reg: TRegister): Boolean;
begin
Next:=Current;
repeat
Result:=GetNextInstruction(Next,Next);
until not (Result) or
not(cs_opt_level3 in current_settings.optimizerswitches) or
(Next.typ<>ait_instruction) or
RegInInstruction(reg,Next) or
is_calljmp(taicpu(Next).opcode);
end;
function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
var
p: taicpu;
begin
Result := false;
if not(assigned(hp) and (hp.typ = ait_instruction)) then
exit;
p := taicpu(hp);
if not (p.ops >0) then
exit;
case p.opcode of
A_B,
A_SSI,A_SSIU,A_SSX,A_SSXU,
A_S16I,A_S32C1I,A_S32E,A_S32I,A_S32RI,A_S8I:
exit;
else
;
end;
case p.oper[0]^.typ of
top_reg:
Result := (p.oper[0]^.reg = reg) ;
else
;
end;
end;
function TCpuAsmOptimizer.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;
{ Start on oper[0]? }
if taicpu(hp).spilling_get_operation_type(0) in [operand_read, operand_readwrite] then
i:=0;
while(i<p.ops) do
begin
case p.oper[I]^.typ of
top_reg:
Result := (p.oper[I]^.reg = reg);
top_ref:
Result :=
(p.oper[I]^.ref^.base = reg) or
(p.oper[I]^.ref^.index = reg);
else
;
end;
{ Bailout if we found something }
if Result then
exit;
Inc(I);
end;
end;
function TCpuAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string):boolean;
var
alloc,
dealloc : tai_regalloc;
hp1 : tai;
begin
Result:=false;
if MatchInstruction(movp, A_MOV, [PF_None,PF_N]) and
{ We can't optimize if there is a shiftop }
(taicpu(movp).ops=2) and
MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
{ the destination register of the mov might not be used beween p and movp }
not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
{ Take care to only do this for instructions which REALLY load to the first register.
Otherwise
s* reg0, [reg1]
mov reg2, reg0
will be optimized to
s* reg2, [reg1]
}
RegLoadedWithNewValue(taicpu(p).oper[0]^.reg, p) then
begin
dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
if assigned(dealloc) then
begin
DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
result:=true;
{ taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
and remove it if possible }
asml.Remove(dealloc);
alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.previous));
if assigned(alloc) then
begin
asml.Remove(alloc);
alloc.free;
dealloc.free;
end
else
asml.InsertAfter(dealloc,p);
{ try to move the allocation of the target register }
GetLastInstruction(movp,hp1);
alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
if assigned(alloc) then
begin
asml.Remove(alloc);
asml.InsertBefore(alloc,p);
{ adjust used regs }
IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
end;
{ finally get rid of the mov }
taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
asml.remove(movp);
movp.free;
end;
end;
end;
function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
var
hp1: tai;
begin
result := false;
case p.typ of
ait_instruction:
begin
case taicpu(p).opcode of
A_ADD,
A_ADDI,
A_L32I,
A_SRLI,
A_SUB:
begin
if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
RemoveSuperfluousMove(p, hp1, 'DataMov2Data') then
Result:=true;
end;
else
;
end;
end
else
;
end
end;
begin
casmoptimizer:=TCpuAsmOptimizer;
End.