From 430b2fd7917e4689de57e75a67ad864f38b570aa Mon Sep 17 00:00:00 2001 From: florian Date: Tue, 18 May 2021 19:13:13 +0000 Subject: [PATCH] * AVR: second part of assembler optimizer rework git-svn-id: trunk@49378 - --- compiler/avr/aoptcpu.pas | 1342 ++++++++++++++++++++------------------ 1 file changed, 709 insertions(+), 633 deletions(-) diff --git a/compiler/avr/aoptcpu.pas b/compiler/avr/aoptcpu.pas index bd0f0f2a80..300a7ffdb4 100644 --- a/compiler/avr/aoptcpu.pas +++ b/compiler/avr/aoptcpu.pas @@ -48,11 +48,20 @@ Type function PeepHoleOptPass1Cpu(var p: tai): boolean; override; procedure PeepHoleOptPass2;override; private + function OptPass1ADD(var p : tai) : boolean; + function OptPass1ANDI(var p : tai) : boolean; + function OptPass1CALL(var p : tai) : boolean; + function OptPass1CLR(var p : tai) : boolean; function OptPass1IN(var p : tai) : boolean; function OptPass1LDI(var p : tai) : boolean; function OptPass1LDS(var p : tai) : boolean; + function OptPass1MOV(var p : tai) : boolean; + function OptPass1PUSH(var p : tai) : boolean; + function OptPass1RCALL(var p : tai) : boolean; + function OptPass1SBI(var p : tai) : boolean; function OptPass1SBR(var p : tai) : boolean; function OptPass1STS(var p : tai) : boolean; + function OptPass1SUB(var p : tai) : boolean; End; Implementation @@ -566,12 +575,699 @@ Implementation end; + function TCpuAsmOptimizer.OptPass1SBI(var p : tai) : boolean; + var + hp1, hp2, hp3, hp4, hp5: tai; + begin + Result:=false; + { + Turn + sbic/sbis X, y + jmp .L1 + op + .L1: + + into + sbis/sbic X,y + op + .L1: + } + if InvertSkipInstruction(p) then + result:=true + { + Turn + sbiX X, y + jmp .L1 + jmp .L2 + .L1: + op + .L2: + + into + sbiX X,y + .L1: + op + .L2: + } + else if GetNextInstruction(p, hp1) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and + (taicpu(hp1).ops>0) and + (taicpu(hp1).oper[0]^.typ = top_ref) and + (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and + + GetNextInstruction(hp1, hp2) and + (hp2.typ=ait_instruction) and + (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and + (taicpu(hp2).ops>0) and + (taicpu(hp2).oper[0]^.typ = top_ref) and + (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and + + GetNextInstruction(hp2, hp3) and + (hp3.typ=ait_label) and + (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and + + GetNextInstruction(hp3, hp4) and + (hp4.typ=ait_instruction) and + + GetNextInstruction(hp4, hp5) and + (hp3.typ=ait_label) and + (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then + begin + DebugMsg('Peephole SbiJmpJmp2Sbi performed',p); + + tai_label(hp3).labsym.decrefs; + tai_label(hp5).labsym.decrefs; + + AsmL.remove(hp1); + taicpu(hp1).Free; + + AsmL.remove(hp2); + taicpu(hp2).Free; + + result:=true; + end; + end; + + + function TCpuAsmOptimizer.OptPass1ANDI(var p : tai) : boolean; + var + hp1, hp2, hp3: tai; + i : longint; + begin + Result:=false; + { + Turn + andi rx, #pow2 + brne l + + l: + Into + sbrs rx, #(1 shl imm) + + l: + } + if (taicpu(p).ops=2) and + (taicpu(p).oper[1]^.typ=top_const) and + ispowerof2(taicpu(p).oper[1]^.val,i) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and + GetNextInstruction(p,hp1) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).opcode=A_BRxx) and + (taicpu(hp1).condition in [C_EQ,C_NE]) and + (taicpu(hp1).ops>0) and + (taicpu(hp1).oper[0]^.typ = top_ref) and + (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and + GetNextInstruction(hp1,hp2) and + (hp2.typ=ait_instruction) and + GetNextInstruction(hp2,hp3) and + (hp3.typ=ait_label) and + (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then + begin + DebugMsg('Peephole AndiBr2Sbr performed', p); + + taicpu(p).oper[1]^.val:=i; + + if taicpu(hp1).condition=C_NE then + taicpu(p).opcode:=A_SBRS + else + taicpu(p).opcode:=A_SBRC; + + asml.Remove(hp1); + hp1.free; + + result:=true; + end + { + Remove + andi rx, #y + dealloc rx + } + else if (taicpu(p).ops=2) and + (taicpu(p).oper[0]^.typ=top_reg) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and + (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or + (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then + begin + DebugMsg('Redundant Andi removed', p); + + result:=RemoveCurrentP(p); + end; + end; + + + function TCpuAsmOptimizer.OptPass1ADD(var p : tai) : boolean; + var + hp1: tai; + begin + Result:=false; + if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and + GetNextInstruction(p, hp1) and + MatchInstruction(hp1,A_ADC) then + begin + DebugMsg('Peephole AddAdc2Add performed', p); + + RemoveCurrentP(p, hp1); + Result := True; + end; + end; + + + function TCpuAsmOptimizer.OptPass1SUB(var p : tai) : boolean; + var + hp1: tai; + begin + Result:=false; + if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and + GetNextInstruction(p, hp1) and + MatchInstruction(hp1,A_SBC) then + begin + DebugMsg('Peephole SubSbc2Sub performed', p); + + taicpu(hp1).opcode:=A_SUB; + + RemoveCurrentP(p, hp1); + Result := True; + end; + end; + + + function TCpuAsmOptimizer.OptPass1CLR(var p : tai) : boolean; + var + hp1: tai; + alloc, dealloc: tai_regalloc; + begin + Result:=false; + { turn the common + clr rX + mov/ld rX, rY + into + mov/ld rX, rY + } + if (taicpu(p).ops=1) and + (taicpu(p).oper[0]^.typ=top_reg) and + GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and + (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).opcode in [A_MOV,A_LD]) and + (taicpu(hp1).ops>0) and + (taicpu(hp1).oper[0]^.typ=top_reg) and + (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then + begin + DebugMsg('Peephole ClrMov2Mov performed', p); + + result:=RemoveCurrentP(p); + end + { turn + clr rX + ... + adc rY, rX + into + ... + adc rY, r1 + } + else if (taicpu(p).ops=1) and + (taicpu(p).oper[0]^.typ=top_reg) and + GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and + (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).opcode in [A_ADC,A_SBC]) and + (taicpu(hp1).ops=2) and + (taicpu(hp1).oper[1]^.typ=top_reg) and + (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and + (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then + begin + DebugMsg('Peephole ClrAdc2Adc performed', p); + + taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg; + + alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); + dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); + + if assigned(alloc) and assigned(dealloc) then + begin + asml.Remove(alloc); + alloc.Free; + asml.Remove(dealloc); + dealloc.Free; + end; + + result:=RemoveCurrentP(p); + end; + end; + + + function TCpuAsmOptimizer.OptPass1PUSH(var p : tai) : boolean; + var + hp1, hp2, hp3: tai; + begin + Result:=false; + { turn + push reg0 + push reg1 + pop reg3 + pop reg2 + + into + + movw reg2,reg0 + + or + + mov reg3,reg1 + mov reg2,reg0 + + } + if GetNextInstruction(p,hp1) and + MatchInstruction(hp1,A_PUSH) and + + GetNextInstruction(hp1,hp2) and + MatchInstruction(hp2,A_POP) and + + GetNextInstruction(hp2,hp3) and + MatchInstruction(hp3,A_POP) then + begin + if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and + (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and + ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and + (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and + ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then + begin + DebugMsg('Peephole PushPushPopPop2Movw performed', p); + + taicpu(hp3).ops:=2; + taicpu(hp3).opcode:=A_MOVW; + + taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg); + + { We're removing 3 concurrent instructions. Remove hp1 + and hp2 manually instead of calling RemoveCurrentP + as this means we won't be calling UpdateUsedRegs 3 times } + asml.Remove(hp1); + hp1.Free; + + asml.Remove(hp2); + hp2.Free; + + { By removing p last, we've guaranteed that p.Next is + valid (storing it prior to removing the instructions + may result in a dangling pointer if hp1 immediately + follows p), and because hp1, hp2 and hp3 came from + sequential calls to GetNextInstruction, it is + guaranteed that UpdateUsedRegs will stop at hp3. [Kit] } + RemoveCurrentP(p, hp3); + Result := True; + end + else + begin + DebugMsg('Peephole PushPushPopPop2MovMov performed', p); + + taicpu(p).ops:=2; + taicpu(p).opcode:=A_MOV; + + taicpu(hp1).ops:=2; + taicpu(hp1).opcode:=A_MOV; + + taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg); + taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg); + + taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg); + taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg); + + { life range of reg2 and reg3 is increased, fix register allocation entries } + TransferUsedRegs(TmpUsedRegs); + UpdateUsedRegs(TmpUsedRegs,tai(p.Next)); + AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs); + + TransferUsedRegs(TmpUsedRegs); + AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs); + + IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs); + UpdateUsedRegs(tai(p.Next)); + + asml.Remove(hp2); + hp2.Free; + asml.Remove(hp3); + hp3.Free; + + result:=true; + end + + end; + end; + + + function TCpuAsmOptimizer.OptPass1CALL(var p : tai) : boolean; + var + hp1: tai; + begin + Result:=false; + if (cs_opt_level4 in current_settings.optimizerswitches) and + GetNextInstruction(p,hp1) and + MatchInstruction(hp1,A_RET) then + begin + DebugMsg('Peephole CallReg2Jmp performed', p); + + taicpu(p).opcode:=A_JMP; + + asml.Remove(hp1); + hp1.Free; + + result:=true; + end; + end; + + + function TCpuAsmOptimizer.OptPass1RCALL(var p : tai) : boolean; + var + hp1: tai; + begin + Result:=false; + if (cs_opt_level4 in current_settings.optimizerswitches) and + GetNextInstruction(p,hp1) and + MatchInstruction(hp1,A_RET) then + begin + DebugMsg('Peephole RCallReg2RJmp performed', p); + + taicpu(p).opcode:=A_RJMP; + + asml.Remove(hp1); + hp1.Free; + + result:=true; + end; + end; + + + function TCpuAsmOptimizer.OptPass1MOV(var p : tai) : boolean; + var + hp1, hp2: tai; + i : Integer; + alloc, dealloc: tai_regalloc; + begin + Result:=false; + { change + mov reg0, reg1 + dealloc reg0 + into + dealloc reg0 + } + if MatchOpType(taicpu(p),top_reg,top_reg) then + begin + TransferUsedRegs(TmpUsedRegs); + UpdateUsedRegs(TmpUsedRegs,tai(p.Next)); + if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and + { reg. allocation information before calls is not perfect, so don't do this before + calls/icalls } + GetNextInstruction(p,hp1) and + not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then + begin + DebugMsg('Peephole Mov2Nop performed', p); + RemoveCurrentP(p, hp1); + Result := True; + exit; + end; + end; + + { turn + mov reg0, reg1 + reg2,reg0 + dealloc reg0 + into + reg2,reg1 + } + if MatchOpType(taicpu(p),top_reg,top_reg) and + GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and + (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and + (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR, + A_OUT,A_IN]) or + { the reference register of ST/STD cannot be replaced } + (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and + (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and + {(taicpu(hp1).ops=1) and + (taicpu(hp1).oper[0]^.typ = top_reg) and + (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and } + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then + begin + DebugMsg('Peephole MovOp2Op 1 performed', p); + + for i := 0 to taicpu(hp1).ops-1 do + if taicpu(hp1).oper[i]^.typ=top_reg then + if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then + taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg; + + alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); + dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); + + if assigned(alloc) and assigned(dealloc) then + begin + asml.Remove(alloc); + alloc.Free; + asml.Remove(dealloc); + dealloc.Free; + end; + + { life range of reg1 is increased } + AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs); + { p will be removed, update used register as we continue + with the next instruction after p } + + result:=RemoveCurrentP(p); + end + { turn + mov reg1, reg0 + reg1,xxxx + dealloc reg1 + into + reg1,xxx + } + else if MatchOpType(taicpu(p),top_reg,top_reg) and + GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and + not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and + MatchInstruction(hp1,[A_CP,A_CPC,A_CPI,A_SBRS,A_SBRC]) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then + begin + DebugMsg('Peephole MovOp2Op 2 performed', p); + + for i := 0 to taicpu(hp1).ops-1 do + if taicpu(hp1).oper[i]^.typ=top_reg then + if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then + taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg; + + alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); + dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); + + if assigned(alloc) and assigned(dealloc) then + begin + asml.Remove(alloc); + alloc.Free; + asml.Remove(dealloc); + dealloc.Free; + end; + + { life range of reg1 is increased } + AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs); + { p will be removed, update used register as we continue + with the next instruction after p } + + result:=RemoveCurrentP(p); + end + { remove + mov reg0,reg0 + } + else if (taicpu(p).ops=2) and + (taicpu(p).oper[0]^.typ = top_reg) and + (taicpu(p).oper[1]^.typ = top_reg) and + (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then + begin + DebugMsg('Peephole RedundantMov performed', p); + + result:=RemoveCurrentP(p); + end + { + Turn + mov rx,ry + op rx,rz + mov ry, rx + Into + op ry,rz + } + else if (taicpu(p).ops=2) and + MatchOpType(taicpu(p),top_reg,top_reg) and + GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).ops >= 1) and + (taicpu(hp1).oper[0]^.typ = top_reg) and + GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and + MatchInstruction(hp2,A_MOV) and + MatchOpType(taicpu(hp2),top_reg,top_reg) and + (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and + (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and + (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and + (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and + (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR, + A_INC,A_DEC, + A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then + begin + DebugMsg('Peephole MovOpMov2Op performed', p); + + if (taicpu(hp1).ops=2) and + (taicpu(hp1).oper[1]^.typ=top_reg) and + (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then + taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg; + + taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg; + + alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); + dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next)); + + if assigned(alloc) and assigned(dealloc) then + begin + asml.Remove(alloc); + alloc.Free; + asml.Remove(dealloc); + dealloc.Free; + end; + + asml.remove(hp2); + hp2.free; + + result:=RemoveCurrentP(p); + end + { + Turn + mov rx,ry + op rx,rw + mov rw,rx + Into + op rw,ry + } + else if (taicpu(p).ops=2) and + MatchOpType(taicpu(p),top_reg,top_reg) and + GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and + (hp1.typ=ait_instruction) and + (taicpu(hp1).ops = 2) and + MatchOpType(taicpu(hp1),top_reg,top_reg) and + GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and + (hp2.typ=ait_instruction) and + (taicpu(hp2).opcode=A_MOV) and + MatchOpType(taicpu(hp2),top_reg,top_reg) and + (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and + (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and + (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and + (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and + (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and + assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then + begin + DebugMsg('Peephole MovOpMov2Op2 performed', p); + + taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg; + taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg; + + alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); + dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next)); + + if assigned(alloc) and assigned(dealloc) then + begin + asml.Remove(alloc); + alloc.Free; + asml.Remove(dealloc); + dealloc.Free; + end; + + result:=RemoveCurrentP(p); + + asml.remove(hp2); + hp2.free; + end + { fold + mov reg2,reg0 + mov reg3,reg1 + to + movw reg2,reg0 + } + else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and + (taicpu(p).ops=2) and + (taicpu(p).oper[0]^.typ = top_reg) and + (taicpu(p).oper[1]^.typ = top_reg) and + getnextinstruction(p,hp1) and + (hp1.typ = ait_instruction) and + (taicpu(hp1).opcode = A_MOV) and + (taicpu(hp1).ops=2) and + (taicpu(hp1).oper[0]^.typ = top_reg) and + (taicpu(hp1).oper[1]^.typ = top_reg) and + (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and + ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and + ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and + (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then + begin + DebugMsg('Peephole MovMov2Movw performed', p); + + alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous)); + if assigned(alloc) then + begin + asml.Remove(alloc); + asml.InsertBefore(alloc,p); + { proper book keeping of currently used registers } + IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs); + end; + + taicpu(p).opcode:=A_MOVW; + asml.remove(hp1); + hp1.free; + result:=true; + end + { + This removes the first mov from + mov rX,... + mov rX,... + } + else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and + { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight } + MatchInstruction(hp1,A_MOV) and + MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then + while MatchInstruction(hp1,A_MOV) and + MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and + { don't remove the first mov if the second is a mov rX,rX } + not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do + begin + DebugMsg('Peephole MovMov2Mov 1 performed', p); + + RemoveCurrentP(p,hp1); + Result := True; + + GetNextInstruction(hp1,hp1); + if not assigned(hp1) then + break; + end + { + This removes the second mov from + mov rX,rY + + ... + + mov rX,rY + + if rX and rY are not modified in-between + } + else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and + MatchInstruction(hp1,A_MOV) and + MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and + MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and + not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then + begin + DebugMsg('Peephole MovMov2Mov 2 performed', p); + AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs); + RemoveInstruction(hp1); + Result := True; + end; + end; + function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean; var - hp1,hp2,hp3,hp4,hp5: tai; - alloc, dealloc: tai_regalloc; - i: integer; - l: TAsmLabel; + hp1,hp2: tai; begin result := false; case p.typ of @@ -659,644 +1355,24 @@ Implementation A_SBRC: Result:=OptPass1SBR(p); A_ANDI: - begin - { - Turn - andi rx, #pow2 - brne l - - l: - Into - sbrs rx, #(1 shl imm) - - l: - } - if (taicpu(p).ops=2) and - (taicpu(p).oper[1]^.typ=top_const) and - ispowerof2(taicpu(p).oper[1]^.val,i) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and - GetNextInstruction(p,hp1) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).opcode=A_BRxx) and - (taicpu(hp1).condition in [C_EQ,C_NE]) and - (taicpu(hp1).ops>0) and - (taicpu(hp1).oper[0]^.typ = top_ref) and - (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and - GetNextInstruction(hp1,hp2) and - (hp2.typ=ait_instruction) and - GetNextInstruction(hp2,hp3) and - (hp3.typ=ait_label) and - (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then - begin - DebugMsg('Peephole AndiBr2Sbr performed', p); - - taicpu(p).oper[1]^.val:=i; - - if taicpu(hp1).condition=C_NE then - taicpu(p).opcode:=A_SBRS - else - taicpu(p).opcode:=A_SBRC; - - asml.Remove(hp1); - hp1.free; - - result:=true; - end - { - Remove - andi rx, #y - dealloc rx - } - else if (taicpu(p).ops=2) and - (taicpu(p).oper[0]^.typ=top_reg) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(p.next))) and - (assigned(FindRegDeAlloc(NR_DEFAULTFLAGS,tai(p.Next))) or - (not RegInUsedRegs(NR_DEFAULTFLAGS,UsedRegs))) then - begin - DebugMsg('Redundant Andi removed', p); - - result:=RemoveCurrentP(p); - end; - end; + Result:=OptPass1ANDI(p); A_ADD: - begin - if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and - GetNextInstruction(p, hp1) and - MatchInstruction(hp1,A_ADC) then - begin - DebugMsg('Peephole AddAdc2Add performed', p); - - RemoveCurrentP(p, hp1); - Result := True; - end; - end; + Result:=OptPass1ADD(p); A_SUB: - begin - if (taicpu(p).oper[1]^.reg=GetDefaultZeroReg) and - GetNextInstruction(p, hp1) and - MatchInstruction(hp1,A_SBC) then - begin - DebugMsg('Peephole SubSbc2Sub performed', p); - - taicpu(hp1).opcode:=A_SUB; - - RemoveCurrentP(p, hp1); - Result := True; - end; - end; + Result:=OptPass1SUB(p); A_CLR: - begin - { turn the common - clr rX - mov/ld rX, rY - into - mov/ld rX, rY - } - if (taicpu(p).ops=1) and - (taicpu(p).oper[0]^.typ=top_reg) and - GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and - (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).opcode in [A_MOV,A_LD]) and - (taicpu(hp1).ops>0) and - (taicpu(hp1).oper[0]^.typ=top_reg) and - (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) then - begin - DebugMsg('Peephole ClrMov2Mov performed', p); - - result:=RemoveCurrentP(p); - end - { turn - clr rX - ... - adc rY, rX - into - ... - adc rY, r1 - } - else if (taicpu(p).ops=1) and - (taicpu(p).oper[0]^.typ=top_reg) and - GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and - (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).opcode in [A_ADC,A_SBC]) and - (taicpu(hp1).ops=2) and - (taicpu(hp1).oper[1]^.typ=top_reg) and - (taicpu(hp1).oper[1]^.reg=taicpu(p).oper[0]^.reg) and - (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[0]^.reg) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then - begin - DebugMsg('Peephole ClrAdc2Adc performed', p); - - taicpu(hp1).oper[1]^.reg:=GetDefaultZeroReg; - - alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); - dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); - - if assigned(alloc) and assigned(dealloc) then - begin - asml.Remove(alloc); - alloc.Free; - asml.Remove(dealloc); - dealloc.Free; - end; - - result:=RemoveCurrentP(p); - end; - end; + Result:=OptPass1CLR(p); A_PUSH: - begin - { turn - push reg0 - push reg1 - pop reg3 - pop reg2 - - into - - movw reg2,reg0 - - or - - mov reg3,reg1 - mov reg2,reg0 - - } - if GetNextInstruction(p,hp1) and - MatchInstruction(hp1,A_PUSH) and - - GetNextInstruction(hp1,hp2) and - MatchInstruction(hp2,A_POP) and - - GetNextInstruction(hp2,hp3) and - MatchInstruction(hp3,A_POP) then - begin - if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and - (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and - ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and - (getsupreg(taicpu(hp2).oper[0]^.reg)=getsupreg(taicpu(hp3).oper[0]^.reg)+1) and - ((getsupreg(taicpu(hp3).oper[0]^.reg) mod 2)=0) then - begin - DebugMsg('Peephole PushPushPopPop2Movw performed', p); - - taicpu(hp3).ops:=2; - taicpu(hp3).opcode:=A_MOVW; - - taicpu(hp3).loadreg(1, taicpu(p).oper[0]^.reg); - - { We're removing 3 concurrent instructions. Remove hp1 - and hp2 manually instead of calling RemoveCurrentP - as this means we won't be calling UpdateUsedRegs 3 times } - asml.Remove(hp1); - hp1.Free; - - asml.Remove(hp2); - hp2.Free; - - { By removing p last, we've guaranteed that p.Next is - valid (storing it prior to removing the instructions - may result in a dangling pointer if hp1 immediately - follows p), and because hp1, hp2 and hp3 came from - sequential calls to GetNextInstruction, it is - guaranteed that UpdateUsedRegs will stop at hp3. [Kit] } - RemoveCurrentP(p, hp3); - Result := True; - end - else - begin - DebugMsg('Peephole PushPushPopPop2MovMov performed', p); - - taicpu(p).ops:=2; - taicpu(p).opcode:=A_MOV; - - taicpu(hp1).ops:=2; - taicpu(hp1).opcode:=A_MOV; - - taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg); - taicpu(p).loadreg(0, taicpu(hp3).oper[0]^.reg); - - taicpu(hp1).loadreg(1, taicpu(hp1).oper[0]^.reg); - taicpu(hp1).loadreg(0, taicpu(hp2).oper[0]^.reg); - - { life range of reg2 and reg3 is increased, fix register allocation entries } - TransferUsedRegs(TmpUsedRegs); - UpdateUsedRegs(TmpUsedRegs,tai(p.Next)); - AllocRegBetween(taicpu(hp2).oper[0]^.reg,hp1,hp2,TmpUsedRegs); - - TransferUsedRegs(TmpUsedRegs); - AllocRegBetween(taicpu(hp3).oper[0]^.reg,p,hp3,TmpUsedRegs); - - IncludeRegInUsedRegs(taicpu(hp3).oper[0]^.reg,UsedRegs); - UpdateUsedRegs(tai(p.Next)); - - asml.Remove(hp2); - hp2.Free; - asml.Remove(hp3); - hp3.Free; - - result:=true; - end - - end; - end; + Result:=OptPass1PUSH(p); A_CALL: - if (cs_opt_level4 in current_settings.optimizerswitches) and - GetNextInstruction(p,hp1) and - MatchInstruction(hp1,A_RET) then - begin - DebugMsg('Peephole CallReg2Jmp performed', p); - - taicpu(p).opcode:=A_JMP; - - asml.Remove(hp1); - hp1.Free; - - result:=true; - end; + Result:=OptPass1CALL(p); A_RCALL: - if (cs_opt_level4 in current_settings.optimizerswitches) and - GetNextInstruction(p,hp1) and - MatchInstruction(hp1,A_RET) then - begin - DebugMsg('Peephole RCallReg2RJmp performed', p); - - taicpu(p).opcode:=A_RJMP; - - asml.Remove(hp1); - hp1.Free; - - result:=true; - end; + Result:=OptPass1RCALL(p); A_MOV: - begin - { change - mov reg0, reg1 - dealloc reg0 - into - dealloc reg0 - } - if MatchOpType(taicpu(p),top_reg,top_reg) then - begin - TransferUsedRegs(TmpUsedRegs); - UpdateUsedRegs(TmpUsedRegs,tai(p.Next)); - if not(RegInUsedRegs(taicpu(p).oper[0]^.reg,TmpUsedRegs)) and - { reg. allocation information before calls is not perfect, so don't do this before - calls/icalls } - GetNextInstruction(p,hp1) and - not(MatchInstruction(hp1,[A_CALL,A_RCALL])) then - begin - DebugMsg('Peephole Mov2Nop performed', p); - RemoveCurrentP(p, hp1); - Result := True; - exit; - end; - end; - - { turn - mov reg0, reg1 - reg2,reg0 - dealloc reg0 - into - reg2,reg1 - } - if MatchOpType(taicpu(p),top_reg,top_reg) and - GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and - (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and - (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR, - A_OUT,A_IN]) or - { the reference register of ST/STD cannot be replaced } - (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and - (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and - {(taicpu(hp1).ops=1) and - (taicpu(hp1).oper[0]^.typ = top_reg) and - (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and } - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then - begin - DebugMsg('Peephole MovOp2Op 1 performed', p); - - for i := 0 to taicpu(hp1).ops-1 do - if taicpu(hp1).oper[i]^.typ=top_reg then - if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then - taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg; - - alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); - dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); - - if assigned(alloc) and assigned(dealloc) then - begin - asml.Remove(alloc); - alloc.Free; - asml.Remove(dealloc); - dealloc.Free; - end; - - { life range of reg1 is increased } - AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs); - { p will be removed, update used register as we continue - with the next instruction after p } - - result:=RemoveCurrentP(p); - end - { turn - mov reg1, reg0 - reg1,xxxx - dealloc reg1 - into - reg1,xxx - } - else if MatchOpType(taicpu(p),top_reg,top_reg) and - GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and - not(RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1)) and - MatchInstruction(hp1,[A_CP,A_CPC,A_CPI,A_SBRS,A_SBRC]) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then - begin - DebugMsg('Peephole MovOp2Op 2 performed', p); - - for i := 0 to taicpu(hp1).ops-1 do - if taicpu(hp1).oper[i]^.typ=top_reg then - if taicpu(hp1).oper[i]^.reg=taicpu(p).oper[0]^.reg then - taicpu(hp1).oper[i]^.reg:=taicpu(p).oper[1]^.reg; - - alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); - dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)); - - if assigned(alloc) and assigned(dealloc) then - begin - asml.Remove(alloc); - alloc.Free; - asml.Remove(dealloc); - dealloc.Free; - end; - - { life range of reg1 is increased } - AllocRegBetween(taicpu(p).oper[1]^.reg,p,hp1,usedregs); - { p will be removed, update used register as we continue - with the next instruction after p } - - result:=RemoveCurrentP(p); - end - { remove - mov reg0,reg0 - } - else if (taicpu(p).ops=2) and - (taicpu(p).oper[0]^.typ = top_reg) and - (taicpu(p).oper[1]^.typ = top_reg) and - (taicpu(p).oper[0]^.reg = taicpu(p).oper[1]^.reg) then - begin - DebugMsg('Peephole RedundantMov performed', p); - - result:=RemoveCurrentP(p); - end - { - Turn - mov rx,ry - op rx,rz - mov ry, rx - Into - op ry,rz - } - else if (taicpu(p).ops=2) and - MatchOpType(taicpu(p),top_reg,top_reg) and - GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).ops >= 1) and - (taicpu(hp1).oper[0]^.typ = top_reg) and - GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and - MatchInstruction(hp2,A_MOV) and - MatchOpType(taicpu(hp2),top_reg,top_reg) and - (taicpu(hp2).oper[0]^.reg = taicpu(p).oper[1]^.reg) and - (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and - (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and - (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp2)) and - (taicpu(hp1).opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_EOR, - A_INC,A_DEC, - A_LSL,A_LSR,A_ASR,A_ROR,A_ROL]) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then - begin - DebugMsg('Peephole MovOpMov2Op performed', p); - - if (taicpu(hp1).ops=2) and - (taicpu(hp1).oper[1]^.typ=top_reg) and - (taicpu(hp1).oper[1]^.reg = taicpu(p).oper[1]^.reg) then - taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg; - - taicpu(hp1).oper[0]^.reg:=taicpu(p).oper[1]^.reg; - - alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); - dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next)); - - if assigned(alloc) and assigned(dealloc) then - begin - asml.Remove(alloc); - alloc.Free; - asml.Remove(dealloc); - dealloc.Free; - end; - - asml.remove(hp2); - hp2.free; - - result:=RemoveCurrentP(p); - end - { - Turn - mov rx,ry - op rx,rw - mov rw,rx - Into - op rw,ry - } - else if (taicpu(p).ops=2) and - MatchOpType(taicpu(p),top_reg,top_reg) and - GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).ops = 2) and - MatchOpType(taicpu(hp1),top_reg,top_reg) and - GetNextInstructionUsingReg(hp1,hp2,taicpu(hp1).oper[0]^.reg) and - (hp2.typ=ait_instruction) and - (taicpu(hp2).opcode=A_MOV) and - MatchOpType(taicpu(hp2),top_reg,top_reg) and - (taicpu(hp2).oper[0]^.reg = taicpu(hp1).oper[1]^.reg) and - (taicpu(hp2).oper[1]^.reg = taicpu(hp1).oper[0]^.reg) and - (taicpu(hp2).oper[1]^.reg = taicpu(p).oper[0]^.reg) and - (not RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) and - (taicpu(hp1).opcode in [A_ADD,A_ADC,A_AND,A_OR,A_EOR]) and - assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg, tai(hp2.Next))) then - begin - DebugMsg('Peephole MovOpMov2Op2 performed', p); - - taicpu(hp1).oper[0]^.reg:=taicpu(hp2).oper[0]^.reg; - taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg; - - alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous)); - dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next)); - - if assigned(alloc) and assigned(dealloc) then - begin - asml.Remove(alloc); - alloc.Free; - asml.Remove(dealloc); - dealloc.Free; - end; - - result:=RemoveCurrentP(p); - - asml.remove(hp2); - hp2.free; - end - { fold - mov reg2,reg0 - mov reg3,reg1 - to - movw reg2,reg0 - } - else if (CPUAVR_HAS_MOVW in cpu_capabilities[current_settings.cputype]) and - (taicpu(p).ops=2) and - (taicpu(p).oper[0]^.typ = top_reg) and - (taicpu(p).oper[1]^.typ = top_reg) and - getnextinstruction(p,hp1) and - (hp1.typ = ait_instruction) and - (taicpu(hp1).opcode = A_MOV) and - (taicpu(hp1).ops=2) and - (taicpu(hp1).oper[0]^.typ = top_reg) and - (taicpu(hp1).oper[1]^.typ = top_reg) and - (getsupreg(taicpu(hp1).oper[0]^.reg)=getsupreg(taicpu(p).oper[0]^.reg)+1) and - ((getsupreg(taicpu(p).oper[0]^.reg) mod 2)=0) and - ((getsupreg(taicpu(p).oper[1]^.reg) mod 2)=0) and - (getsupreg(taicpu(hp1).oper[1]^.reg)=getsupreg(taicpu(p).oper[1]^.reg)+1) then - begin - DebugMsg('Peephole MovMov2Movw performed', p); - - alloc:=FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous)); - if assigned(alloc) then - begin - asml.Remove(alloc); - asml.InsertBefore(alloc,p); - { proper book keeping of currently used registers } - IncludeRegInUsedRegs(taicpu(hp1).oper[0]^.reg,UsedRegs); - end; - - taicpu(p).opcode:=A_MOVW; - asml.remove(hp1); - hp1.free; - result:=true; - end - { - This removes the first mov from - mov rX,... - mov rX,... - } - else if GetNextInstruction(p,hp1) and MatchInstruction(hp1,A_MOV) and - { test condition here already instead in the while loop only, else MovMov2Mov 2 might be oversight } - MatchInstruction(hp1,A_MOV) and - MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) then - while MatchInstruction(hp1,A_MOV) and - MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and - { don't remove the first mov if the second is a mov rX,rX } - not(MatchOperand(taicpu(hp1).oper[0]^,taicpu(hp1).oper[1]^)) do - begin - DebugMsg('Peephole MovMov2Mov 1 performed', p); - - RemoveCurrentP(p,hp1); - Result := True; - - GetNextInstruction(hp1,hp1); - if not assigned(hp1) then - break; - end - { - This removes the second mov from - mov rX,rY - - ... - - mov rX,rY - - if rX and rY are not modified in-between - } - else if GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[1]^.reg) and - MatchInstruction(hp1,A_MOV) and - MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and - MatchOperand(taicpu(p).oper[1]^, taicpu(hp1).oper[1]^) and - not(RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then - begin - DebugMsg('Peephole MovMov2Mov 2 performed', p); - AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,UsedRegs); - RemoveInstruction(hp1); - Result := True; - end; - end; + Result:=OptPass1MOV(p); A_SBIC, A_SBIS: - begin - { - Turn - sbic/sbis X, y - jmp .L1 - op - .L1: - - into - sbis/sbic X,y - op - .L1: - } - if InvertSkipInstruction(p) then - result:=true - { - Turn - sbiX X, y - jmp .L1 - jmp .L2 - .L1: - op - .L2: - - into - sbiX X,y - .L1: - op - .L2: - } - else if GetNextInstruction(p, hp1) and - (hp1.typ=ait_instruction) and - (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and - (taicpu(hp1).ops>0) and - (taicpu(hp1).oper[0]^.typ = top_ref) and - (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and - - GetNextInstruction(hp1, hp2) and - (hp2.typ=ait_instruction) and - (taicpu(hp2).opcode in [A_JMP,A_RJMP]) and - (taicpu(hp2).ops>0) and - (taicpu(hp2).oper[0]^.typ = top_ref) and - (taicpu(hp2).oper[0]^.ref^.symbol is TAsmLabel) and - - GetNextInstruction(hp2, hp3) and - (hp3.typ=ait_label) and - (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) and - - GetNextInstruction(hp3, hp4) and - (hp4.typ=ait_instruction) and - - GetNextInstruction(hp4, hp5) and - (hp3.typ=ait_label) and - (taicpu(hp2).oper[0]^.ref^.symbol=tai_label(hp5).labsym) then - begin - DebugMsg('Peephole SbiJmpJmp2Sbi performed',p); - - tai_label(hp3).labsym.decrefs; - tai_label(hp5).labsym.decrefs; - - AsmL.remove(hp1); - taicpu(hp1).Free; - - AsmL.remove(hp2); - taicpu(hp2).Free; - - result:=true; - end; - end; + Result:=OptPass1SBI(p); end; end; end;