aoptcpu.pas 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
  3. Development Team
  4. This unit implements the ARM optimizer object
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit aoptcpu;
  19. {$i fpcdefs.inc}
  20. {$define DEBUG_PREREGSCHEDULER}
  21. {$define DEBUG_AOPTCPU}
  22. Interface
  23. uses cgbase, cpubase, aasmtai, aasmcpu,aopt, aoptcpub, aoptobj;
  24. Type
  25. TCpuAsmOptimizer = class(TAsmOptimizer)
  26. { uses the same constructor as TAopObj }
  27. function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
  28. procedure PeepHoleOptPass2;override;
  29. Function RegInInstruction(Reg: TRegister; p1: tai): Boolean;override;
  30. procedure RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string);
  31. function RegUsedAfterInstruction(reg: Tregister; p: tai;
  32. var AllUsedRegs: TAllUsedRegs): Boolean;
  33. { gets the next tai object after current that contains info relevant
  34. to the optimizer in p1 which used the given register or does a
  35. change in program flow.
  36. If there is none, it returns false and
  37. sets p1 to nil }
  38. Function GetNextInstructionUsingReg(Current: tai; Var Next: tai;reg : TRegister): Boolean;
  39. { outputs a debug message into the assembler file }
  40. procedure DebugMsg(const s: string; p: tai);
  41. protected
  42. function LookForPostindexedPattern(p: taicpu): boolean;
  43. End;
  44. TCpuPreRegallocScheduler = class(TAsmScheduler)
  45. function SchedulerPass1Cpu(var p: tai): boolean;override;
  46. procedure SwapRegLive(p, hp1: taicpu);
  47. end;
  48. TCpuThumb2AsmOptimizer = class(TCpuAsmOptimizer)
  49. { uses the same constructor as TAopObj }
  50. procedure PeepHoleOptPass2;override;
  51. End;
  52. Implementation
  53. uses
  54. cutils,verbose,globals,
  55. systems,
  56. cpuinfo,
  57. cgobj,cgutils,procinfo,
  58. aasmbase,aasmdata;
  59. function CanBeCond(p : tai) : boolean;
  60. begin
  61. result:=
  62. (p.typ=ait_instruction) and
  63. (taicpu(p).condition=C_None) and
  64. (taicpu(p).opcode<>A_PLD) and
  65. ((taicpu(p).opcode<>A_BLX) or
  66. (taicpu(p).oper[0]^.typ=top_reg));
  67. end;
  68. function RefsEqual(const r1, r2: treference): boolean;
  69. begin
  70. refsequal :=
  71. (r1.offset = r2.offset) and
  72. (r1.base = r2.base) and
  73. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  74. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  75. (r1.relsymbol = r2.relsymbol) and
  76. (r1.signindex = r2.signindex) and
  77. (r1.shiftimm = r2.shiftimm) and
  78. (r1.addressmode = r2.addressmode) and
  79. (r1.shiftmode = r2.shiftmode);
  80. end;
  81. function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  82. begin
  83. result :=
  84. (instr.typ = ait_instruction) and
  85. ((op = []) or ((ord(taicpu(instr).opcode)<256) and (taicpu(instr).opcode in op))) and
  86. ((cond = []) or (taicpu(instr).condition in cond)) and
  87. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  88. end;
  89. function MatchInstruction(const instr: tai; const op: TAsmOp; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
  90. begin
  91. result :=
  92. (instr.typ = ait_instruction) and
  93. (taicpu(instr).opcode = op) and
  94. ((cond = []) or (taicpu(instr).condition in cond)) and
  95. ((postfix = []) or (taicpu(instr).oppostfix in postfix));
  96. end;
  97. function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
  98. begin
  99. result := oper1.typ = oper2.typ;
  100. if result then
  101. case oper1.typ of
  102. top_const:
  103. Result:=oper1.val = oper2.val;
  104. top_reg:
  105. Result:=oper1.reg = oper2.reg;
  106. top_conditioncode:
  107. Result:=oper1.cc = oper2.cc;
  108. top_ref:
  109. Result:=RefsEqual(oper1.ref^, oper2.ref^);
  110. else Result:=false;
  111. end
  112. end;
  113. function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
  114. begin
  115. result := (oper.typ = top_reg) and (oper.reg = reg);
  116. end;
  117. procedure RemoveRedundantMove(const cmpp: tai; movp: tai; asml: TAsmList);
  118. begin
  119. if (taicpu(movp).condition = C_EQ) and
  120. (taicpu(cmpp).oper[0]^.reg = taicpu(movp).oper[0]^.reg) and
  121. (taicpu(cmpp).oper[1]^.val = taicpu(movp).oper[1]^.val) then
  122. begin
  123. asml.insertafter(tai_comment.Create(strpnew('Peephole CmpMovMov - Removed redundant moveq')), movp);
  124. asml.remove(movp);
  125. movp.free;
  126. end;
  127. end;
  128. function regLoadedWithNewValue(reg: tregister; hp: tai): boolean;
  129. var
  130. p: taicpu;
  131. begin
  132. p := taicpu(hp);
  133. regLoadedWithNewValue := false;
  134. if not ((assigned(hp)) and (hp.typ = ait_instruction)) then
  135. exit;
  136. case p.opcode of
  137. { These operands do not write into a register at all }
  138. A_CMP, A_CMN, A_TST, A_TEQ, A_B, A_BL, A_BX, A_BLX, A_SWI, A_MSR, A_PLD:
  139. exit;
  140. {Take care of post/preincremented store and loads, they will change their base register}
  141. A_STR, A_LDR:
  142. regLoadedWithNewValue :=
  143. (taicpu(p).oper[1]^.typ=top_ref) and
  144. (taicpu(p).oper[1]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
  145. (taicpu(p).oper[1]^.ref^.base = reg);
  146. { These four are writing into the first 2 register, UMLAL and SMLAL will also read from them }
  147. A_UMLAL, A_UMULL, A_SMLAL, A_SMULL:
  148. regLoadedWithNewValue :=
  149. (p.oper[1]^.typ = top_reg) and
  150. (p.oper[1]^.reg = reg);
  151. {Loads to oper2 from coprocessor}
  152. {
  153. MCR/MRC is currently not supported in FPC
  154. A_MRC:
  155. regLoadedWithNewValue :=
  156. (p.oper[2]^.typ = top_reg) and
  157. (p.oper[2]^.reg = reg);
  158. }
  159. {Loads to all register in the registerset}
  160. A_LDM:
  161. regLoadedWithNewValue := (getsupreg(reg) in p.oper[1]^.regset^);
  162. end;
  163. if regLoadedWithNewValue then
  164. exit;
  165. case p.oper[0]^.typ of
  166. {This is the case}
  167. top_reg:
  168. regLoadedWithNewValue := (p.oper[0]^.reg = reg) or
  169. { LDRD }
  170. (p.opcode=A_LDR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg));
  171. {LDM/STM might write a new value to their index register}
  172. top_ref:
  173. regLoadedWithNewValue :=
  174. (taicpu(p).oper[0]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and
  175. (taicpu(p).oper[0]^.ref^.base = reg);
  176. end;
  177. end;
  178. function AlignedToQWord(const ref : treference) : boolean;
  179. begin
  180. { (safe) heuristics to ensure alignment }
  181. result:=(target_info.abi in [abi_eabi,abi_armeb,abi_eabihf]) and
  182. (((ref.offset>=0) and
  183. ((ref.offset mod 8)=0) and
  184. ((ref.base=NR_R13) or
  185. (ref.index=NR_R13))
  186. ) or
  187. ((ref.offset<=0) and
  188. { when using NR_R11, it has always a value of <qword align>+4 }
  189. ((abs(ref.offset+4) mod 8)=0) and
  190. (current_procinfo.framepointer=NR_R11) and
  191. ((ref.base=NR_R11) or
  192. (ref.index=NR_R11))
  193. )
  194. );
  195. end;
  196. function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
  197. var
  198. p: taicpu;
  199. i: longint;
  200. begin
  201. instructionLoadsFromReg := false;
  202. if not (assigned(hp) and (hp.typ = ait_instruction)) then
  203. exit;
  204. p:=taicpu(hp);
  205. i:=1;
  206. {For these instructions we have to start on oper[0]}
  207. if (p.opcode in [A_STR, A_LDM, A_STM, A_PLD,
  208. A_CMP, A_CMN, A_TST, A_TEQ,
  209. A_B, A_BL, A_BX, A_BLX,
  210. A_SMLAL, A_UMLAL]) then i:=0;
  211. while(i<p.ops) do
  212. begin
  213. case p.oper[I]^.typ of
  214. top_reg:
  215. instructionLoadsFromReg := (p.oper[I]^.reg = reg) or
  216. { STRD }
  217. ((i=0) and (p.opcode=A_STR) and (p.oppostfix=PF_D) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg)));
  218. top_regset:
  219. instructionLoadsFromReg := (getsupreg(reg) in p.oper[I]^.regset^);
  220. top_shifterop:
  221. instructionLoadsFromReg := p.oper[I]^.shifterop^.rs = reg;
  222. top_ref:
  223. instructionLoadsFromReg :=
  224. (p.oper[I]^.ref^.base = reg) or
  225. (p.oper[I]^.ref^.index = reg);
  226. end;
  227. if instructionLoadsFromReg then exit; {Bailout if we found something}
  228. Inc(I);
  229. end;
  230. end;
  231. function TCpuAsmOptimizer.RegUsedAfterInstruction(reg: Tregister; p: tai;
  232. var AllUsedRegs: TAllUsedRegs): Boolean;
  233. begin
  234. AllUsedRegs[getregtype(reg)].Update(tai(p.Next),true);
  235. RegUsedAfterInstruction :=
  236. AllUsedRegs[getregtype(reg)].IsUsed(reg) and
  237. not(regLoadedWithNewValue(reg,p)) and
  238. (
  239. not(GetNextInstruction(p,p)) or
  240. instructionLoadsFromReg(reg,p) or
  241. not(regLoadedWithNewValue(reg,p))
  242. );
  243. end;
  244. function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
  245. var Next: tai; reg: TRegister): Boolean;
  246. begin
  247. Next:=Current;
  248. repeat
  249. Result:=GetNextInstruction(Next,Next);
  250. until not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
  251. (is_calljmp(taicpu(Next).opcode)) or (RegInInstruction(NR_PC,Next));
  252. end;
  253. {$ifdef DEBUG_AOPTCPU}
  254. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
  255. begin
  256. asml.insertbefore(tai_comment.Create(strpnew(s)), p);
  257. end;
  258. {$else DEBUG_AOPTCPU}
  259. procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
  260. begin
  261. end;
  262. {$endif DEBUG_AOPTCPU}
  263. procedure TCpuAsmOptimizer.RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string);
  264. var
  265. alloc,
  266. dealloc : tai_regalloc;
  267. hp1 : tai;
  268. begin
  269. if MatchInstruction(movp, A_MOV, [taicpu(p).condition], [PF_None]) and
  270. (taicpu(movp).ops=2) and {We can't optimize if there is a shiftop}
  271. MatchOperand(taicpu(movp).oper[1]^, taicpu(p).oper[0]^.reg) and
  272. { don't mess with moves to pc }
  273. (taicpu(movp).oper[0]^.reg<>NR_PC) and
  274. { don't mess with moves to lr }
  275. (taicpu(movp).oper[0]^.reg<>NR_R14) and
  276. { the destination register of the mov might not be used beween p and movp }
  277. not(RegUsedBetween(taicpu(movp).oper[0]^.reg,p,movp)) and
  278. {There is a special requirement for MUL and MLA, oper[0] and oper[1] are not allowed to be the same}
  279. not (
  280. (taicpu(p).opcode in [A_MLA, A_MUL]) and
  281. (taicpu(p).oper[1]^.reg = taicpu(movp).oper[0]^.reg)
  282. ) and
  283. { Take care to only do this for instructions which REALLY load to the first register.
  284. Otherwise
  285. str reg0, [reg1]
  286. mov reg2, reg0
  287. will be optimized to
  288. str reg2, [reg1]
  289. }
  290. not (regLoadedWithNewValue(taicpu(p).oper[0]^.reg, p)) then
  291. begin
  292. dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
  293. if assigned(dealloc) then
  294. begin
  295. DebugMsg('Peephole '+optimizer+' removed superfluous mov', movp);
  296. { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
  297. and remove it if possible }
  298. GetLastInstruction(p,hp1);
  299. asml.Remove(dealloc);
  300. alloc:=FindRegAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
  301. if assigned(alloc) then
  302. begin
  303. asml.Remove(alloc);
  304. alloc.free;
  305. dealloc.free;
  306. end
  307. else
  308. asml.InsertAfter(dealloc,p);
  309. { try to move the allocation of the target register }
  310. GetLastInstruction(movp,hp1);
  311. alloc:=FindRegAlloc(taicpu(movp).oper[0]^.reg,tai(hp1.Next));
  312. if assigned(alloc) then
  313. begin
  314. asml.Remove(alloc);
  315. asml.InsertBefore(alloc,p);
  316. { adjust used regs }
  317. IncludeRegInUsedRegs(taicpu(movp).oper[0]^.reg,UsedRegs);
  318. end;
  319. { finally get rid of the mov }
  320. taicpu(p).loadreg(0,taicpu(movp).oper[0]^.reg);
  321. asml.remove(movp);
  322. movp.free;
  323. end;
  324. end;
  325. end;
  326. {
  327. optimize
  328. ldr/str regX,[reg1]
  329. ...
  330. add/sub reg1,reg1,regY/const
  331. into
  332. ldr/str regX,[reg1], regY/const
  333. }
  334. function TCpuAsmOptimizer.LookForPostindexedPattern(p: taicpu) : boolean;
  335. var
  336. hp1 : tai;
  337. begin
  338. Result:=false;
  339. if (p.oper[1]^.ref^.addressmode=AM_OFFSET) and
  340. (p.oper[1]^.ref^.index=NR_NO) and
  341. (p.oper[1]^.ref^.offset=0) and
  342. GetNextInstructionUsingReg(p, hp1, p.oper[1]^.ref^.base) and
  343. { we cannot check NR_DEFAULTFLAGS for modification yet so don't allow a condition }
  344. MatchInstruction(hp1, [A_ADD, A_SUB], [C_None], [PF_None]) and
  345. (taicpu(hp1).oper[0]^.reg=p.oper[1]^.ref^.base) and
  346. (taicpu(hp1).oper[1]^.reg=p.oper[1]^.ref^.base) and
  347. (
  348. (taicpu(hp1).oper[2]^.typ=top_reg) or
  349. { valid offset? }
  350. ((taicpu(hp1).oper[2]^.typ=top_const) and
  351. ((abs(taicpu(hp1).oper[2]^.val)<256) or
  352. ((abs(taicpu(hp1).oper[2]^.val)<4096) and (p.oppostfix in [PF_None,PF_B]))
  353. )
  354. )
  355. ) and
  356. { don't apply the optimization if the base register is loaded }
  357. (p.oper[0]^.reg<>p.oper[1]^.ref^.base) and
  358. not(RegModifiedBetween(taicpu(hp1).oper[0]^.reg,p,hp1)) and
  359. { don't apply the optimization if the (new) index register is loaded }
  360. (p.oper[0]^.reg<>taicpu(hp1).oper[2]^.reg) and
  361. not(RegModifiedBetween(taicpu(hp1).oper[2]^.reg,p,hp1)) then
  362. begin
  363. DebugMsg('Peephole Str/LdrAdd/Sub2Str/Ldr Postindex done', p);
  364. p.oper[1]^.ref^.addressmode:=AM_POSTINDEXED;
  365. if taicpu(hp1).oper[2]^.typ=top_const then
  366. begin
  367. if taicpu(hp1).opcode=A_ADD then
  368. p.oper[1]^.ref^.offset:=taicpu(hp1).oper[2]^.val
  369. else
  370. p.oper[1]^.ref^.offset:=-taicpu(hp1).oper[2]^.val;
  371. end
  372. else
  373. begin
  374. p.oper[1]^.ref^.index:=taicpu(hp1).oper[2]^.reg;
  375. if taicpu(hp1).opcode=A_ADD then
  376. p.oper[1]^.ref^.signindex:=1
  377. else
  378. p.oper[1]^.ref^.signindex:=-1;
  379. end;
  380. asml.Remove(hp1);
  381. hp1.Free;
  382. Result:=true;
  383. end;
  384. end;
  385. function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
  386. var
  387. hp1,hp2: tai;
  388. i, i2: longint;
  389. TmpUsedRegs: TAllUsedRegs;
  390. tempop: tasmop;
  391. function IsPowerOf2(const value: DWord): boolean; inline;
  392. begin
  393. Result:=(value and (value - 1)) = 0;
  394. end;
  395. begin
  396. result := false;
  397. case p.typ of
  398. ait_instruction:
  399. begin
  400. {
  401. change
  402. <op> reg,x,y
  403. cmp reg,#0
  404. into
  405. <op>s reg,x,y
  406. }
  407. { this optimization can applied only to the currently enabled operations because
  408. the other operations do not update all flags and FPC does not track flag usage }
  409. if MatchInstruction(p, [A_ADC,A_ADD,A_BIC,A_SUB,A_MUL,A_MVN,A_MOV,A_ORR,A_EOR,A_AND,
  410. A_RSB,A_RSC,A_SBC,A_MLA], [C_None], [PF_None]) and
  411. GetNextInstruction(p, hp1) and
  412. MatchInstruction(hp1, A_CMP, [C_None], [PF_None]) and
  413. (taicpu(hp1).oper[1]^.typ = top_const) and
  414. (taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg) and
  415. (taicpu(hp1).oper[1]^.val = 0) and
  416. GetNextInstruction(hp1, hp2) and
  417. { be careful here, following instructions could use other flags
  418. however after a jump fpc never depends on the value of flags }
  419. { All above instructions set Z and N according to the following
  420. Z := result = 0;
  421. N := result[31];
  422. EQ = Z=1; NE = Z=0;
  423. MI = N=1; PL = N=0; }
  424. MatchInstruction(hp2, A_B, [C_EQ,C_NE,C_MI,C_PL], []) and
  425. assigned(FindRegDealloc(NR_DEFAULTFLAGS,tai(hp2.Next))) then
  426. begin
  427. DebugMsg('Peephole OpCmp2OpS done', p);
  428. taicpu(p).oppostfix:=PF_S;
  429. { move flag allocation if possible }
  430. GetLastInstruction(hp1, hp2);
  431. hp2:=FindRegAlloc(NR_DEFAULTFLAGS,tai(hp2.Next));
  432. if assigned(hp2) then
  433. begin
  434. asml.Remove(hp2);
  435. asml.insertbefore(hp2, p);
  436. end;
  437. asml.remove(hp1);
  438. hp1.free;
  439. end
  440. else
  441. case taicpu(p).opcode of
  442. A_STR:
  443. begin
  444. { change
  445. str reg1,ref
  446. ldr reg2,ref
  447. into
  448. str reg1,ref
  449. mov reg2,reg1
  450. }
  451. if (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
  452. (taicpu(p).oppostfix=PF_None) and
  453. GetNextInstruction(p,hp1) and
  454. MatchInstruction(hp1, A_LDR, [taicpu(p).condition, C_None], [PF_None]) and
  455. RefsEqual(taicpu(p).oper[1]^.ref^,taicpu(hp1).oper[1]^.ref^) and
  456. (taicpu(hp1).oper[1]^.ref^.addressmode=AM_OFFSET) then
  457. begin
  458. if taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg then
  459. begin
  460. DebugMsg('Peephole StrLdr2StrMov 1 done', hp1);
  461. asml.remove(hp1);
  462. hp1.free;
  463. end
  464. else
  465. begin
  466. taicpu(hp1).opcode:=A_MOV;
  467. taicpu(hp1).oppostfix:=PF_None;
  468. taicpu(hp1).loadreg(1,taicpu(p).oper[0]^.reg);
  469. DebugMsg('Peephole StrLdr2StrMov 2 done', hp1);
  470. end;
  471. result := true;
  472. end
  473. { change
  474. str reg1,ref
  475. str reg2,ref
  476. into
  477. strd reg1,ref
  478. }
  479. else if (CPUARM_HAS_EDSP in cpu_capabilities[current_settings.cputype]) and
  480. (taicpu(p).oppostfix=PF_None) and
  481. (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
  482. GetNextInstruction(p,hp1) and
  483. MatchInstruction(hp1, A_STR, [taicpu(p).condition, C_None], [PF_None]) and
  484. not(odd(getsupreg(taicpu(p).oper[0]^.reg))) and
  485. (getsupreg(taicpu(p).oper[0]^.reg)+1=getsupreg(taicpu(hp1).oper[0]^.reg)) and
  486. { str ensures that either base or index contain no register, else ldr wouldn't
  487. use an offset either
  488. }
  489. (taicpu(p).oper[1]^.ref^.base=taicpu(hp1).oper[1]^.ref^.base) and
  490. (taicpu(p).oper[1]^.ref^.index=taicpu(hp1).oper[1]^.ref^.index) and
  491. (taicpu(p).oper[1]^.ref^.offset+4=taicpu(hp1).oper[1]^.ref^.offset) and
  492. (abs(taicpu(p).oper[1]^.ref^.offset)<256) and
  493. AlignedToQWord(taicpu(p).oper[1]^.ref^) then
  494. begin
  495. DebugMsg('Peephole StrStr2Strd done', p);
  496. taicpu(p).oppostfix:=PF_D;
  497. asml.remove(hp1);
  498. hp1.free;
  499. end;
  500. LookForPostindexedPattern(taicpu(p));
  501. end;
  502. A_LDR:
  503. begin
  504. { change
  505. ldr reg1,ref
  506. ldr reg2,ref
  507. into ...
  508. }
  509. if (taicpu(p).oper[1]^.ref^.addressmode=AM_OFFSET) and
  510. GetNextInstruction(p,hp1) and
  511. { ldrd is not allowed here }
  512. MatchInstruction(hp1, A_LDR, [taicpu(p).condition, C_None], [taicpu(p).oppostfix,PF_None]-[PF_D]) then
  513. begin
  514. {
  515. ...
  516. ldr reg1,ref
  517. mov reg2,reg1
  518. }
  519. if RefsEqual(taicpu(p).oper[1]^.ref^,taicpu(hp1).oper[1]^.ref^) and
  520. (taicpu(p).oper[0]^.reg<>taicpu(hp1).oper[1]^.ref^.index) and
  521. (taicpu(p).oper[0]^.reg<>taicpu(hp1).oper[1]^.ref^.base) and
  522. (taicpu(hp1).oper[1]^.ref^.addressmode=AM_OFFSET) then
  523. begin
  524. if taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg then
  525. begin
  526. DebugMsg('Peephole LdrLdr2Ldr done', hp1);
  527. asml.remove(hp1);
  528. hp1.free;
  529. end
  530. else
  531. begin
  532. DebugMsg('Peephole LdrLdr2LdrMov done', hp1);
  533. taicpu(hp1).opcode:=A_MOV;
  534. taicpu(hp1).oppostfix:=PF_None;
  535. taicpu(hp1).loadreg(1,taicpu(p).oper[0]^.reg);
  536. end;
  537. result := true;
  538. end
  539. {
  540. ...
  541. ldrd reg1,ref
  542. }
  543. else if (CPUARM_HAS_EDSP in cpu_capabilities[current_settings.cputype]) and
  544. { ldrd does not allow any postfixes ... }
  545. (taicpu(p).oppostfix=PF_None) and
  546. not(odd(getsupreg(taicpu(p).oper[0]^.reg))) and
  547. (getsupreg(taicpu(p).oper[0]^.reg)+1=getsupreg(taicpu(hp1).oper[0]^.reg)) and
  548. { ldr ensures that either base or index contain no register, else ldr wouldn't
  549. use an offset either
  550. }
  551. (taicpu(p).oper[1]^.ref^.base=taicpu(hp1).oper[1]^.ref^.base) and
  552. (taicpu(p).oper[1]^.ref^.index=taicpu(hp1).oper[1]^.ref^.index) and
  553. (taicpu(p).oper[1]^.ref^.offset+4=taicpu(hp1).oper[1]^.ref^.offset) and
  554. (abs(taicpu(p).oper[1]^.ref^.offset)<256) and
  555. AlignedToQWord(taicpu(p).oper[1]^.ref^) then
  556. begin
  557. DebugMsg('Peephole LdrLdr2Ldrd done', p);
  558. taicpu(p).oppostfix:=PF_D;
  559. asml.remove(hp1);
  560. hp1.free;
  561. end;
  562. end;
  563. LookForPostindexedPattern(taicpu(p));
  564. { Remove superfluous mov after ldr
  565. changes
  566. ldr reg1, ref
  567. mov reg2, reg1
  568. to
  569. ldr reg2, ref
  570. conditions are:
  571. * no ldrd usage
  572. * reg1 must be released after mov
  573. * mov can not contain shifterops
  574. * ldr+mov have the same conditions
  575. * mov does not set flags
  576. }
  577. if (taicpu(p).oppostfix<>PF_D) and GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) then
  578. RemoveSuperfluousMove(p, hp1, 'LdrMov2Ldr');
  579. end;
  580. A_MOV:
  581. begin
  582. { fold
  583. mov reg1,reg0, shift imm1
  584. mov reg1,reg1, shift imm2
  585. }
  586. if (taicpu(p).ops=3) and
  587. (taicpu(p).oper[2]^.typ = top_shifterop) and
  588. (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
  589. getnextinstruction(p,hp1) and
  590. MatchInstruction(hp1, A_MOV, [taicpu(p).condition], [PF_None]) and
  591. (taicpu(hp1).ops=3) and
  592. MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[0]^.reg) and
  593. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  594. (taicpu(hp1).oper[2]^.typ = top_shifterop) and
  595. (taicpu(hp1).oper[2]^.shifterop^.rs = NR_NO) then
  596. begin
  597. { fold
  598. mov reg1,reg0, lsl 16
  599. mov reg1,reg1, lsr 16
  600. strh reg1, ...
  601. dealloc reg1
  602. to
  603. strh reg1, ...
  604. dealloc reg1
  605. }
  606. if (taicpu(p).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  607. (taicpu(p).oper[2]^.shifterop^.shiftimm=16) and
  608. (taicpu(hp1).oper[2]^.shifterop^.shiftmode in [SM_LSR,SM_ASR]) and
  609. (taicpu(hp1).oper[2]^.shifterop^.shiftimm=16) and
  610. getnextinstruction(hp1,hp2) and
  611. MatchInstruction(hp2, A_STR, [taicpu(p).condition], [PF_H]) and
  612. MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^.reg) then
  613. begin
  614. CopyUsedRegs(TmpUsedRegs);
  615. UpdateUsedRegs(TmpUsedRegs, tai(p.next));
  616. UpdateUsedRegs(TmpUsedRegs, tai(hp1.next));
  617. if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hp2,TmpUsedRegs)) then
  618. begin
  619. DebugMsg('Peephole optimizer removed superfluous 16 Bit zero extension', hp1);
  620. taicpu(hp2).loadreg(0,taicpu(p).oper[1]^.reg);
  621. asml.remove(p);
  622. asml.remove(hp1);
  623. p.free;
  624. hp1.free;
  625. p:=hp2;
  626. end;
  627. ReleaseUsedRegs(TmpUsedRegs);
  628. end
  629. { fold
  630. mov reg1,reg0, shift imm1
  631. mov reg1,reg1, shift imm2
  632. to
  633. mov reg1,reg0, shift imm1+imm2
  634. }
  635. else if (taicpu(p).oper[2]^.shifterop^.shiftmode=taicpu(hp1).oper[2]^.shifterop^.shiftmode) or
  636. { asr makes no use after a lsr, the asr can be foled into the lsr }
  637. ((taicpu(p).oper[2]^.shifterop^.shiftmode=SM_LSR) and (taicpu(hp1).oper[2]^.shifterop^.shiftmode=SM_ASR) ) then
  638. begin
  639. inc(taicpu(p).oper[2]^.shifterop^.shiftimm,taicpu(hp1).oper[2]^.shifterop^.shiftimm);
  640. { avoid overflows }
  641. if taicpu(p).oper[2]^.shifterop^.shiftimm>31 then
  642. case taicpu(p).oper[2]^.shifterop^.shiftmode of
  643. SM_ROR:
  644. taicpu(p).oper[2]^.shifterop^.shiftimm:=taicpu(p).oper[2]^.shifterop^.shiftimm and 31;
  645. SM_ASR:
  646. taicpu(p).oper[2]^.shifterop^.shiftimm:=31;
  647. SM_LSR,
  648. SM_LSL:
  649. begin
  650. hp1:=taicpu.op_reg_const(A_MOV,taicpu(p).oper[0]^.reg,0);
  651. InsertLLItem(p.previous, p.next, hp1);
  652. p.free;
  653. p:=hp1;
  654. end;
  655. else
  656. internalerror(2008072803);
  657. end;
  658. DebugMsg('Peephole ShiftShift2Shift 1 done', p);
  659. asml.remove(hp1);
  660. hp1.free;
  661. result := true;
  662. end
  663. { fold
  664. mov reg1,reg0, shift imm1
  665. mov reg1,reg1, shift imm2
  666. mov reg1,reg1, shift imm3 ...
  667. }
  668. else if getnextinstruction(hp1,hp2) and
  669. MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
  670. (taicpu(hp2).ops=3) and
  671. MatchOperand(taicpu(hp2).oper[0]^, taicpu(hp1).oper[0]^.reg) and
  672. MatchOperand(taicpu(hp2).oper[1]^, taicpu(hp1).oper[0]^.reg) and
  673. (taicpu(hp2).oper[2]^.typ = top_shifterop) and
  674. (taicpu(hp2).oper[2]^.shifterop^.rs = NR_NO) then
  675. begin
  676. { mov reg1,reg0, lsl imm1
  677. mov reg1,reg1, lsr/asr imm2
  678. mov reg1,reg1, lsl imm3 ...
  679. if imm3<=imm1 and imm2>=imm3
  680. to
  681. mov reg1,reg0, lsl imm1
  682. mov reg1,reg1, lsr/asr imm2-imm3
  683. }
  684. if (taicpu(p).oper[2]^.shifterop^.shiftmode=SM_LSL) and (taicpu(hp2).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  685. (taicpu(hp1).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and
  686. (taicpu(hp2).oper[2]^.shifterop^.shiftimm<=taicpu(p).oper[2]^.shifterop^.shiftimm) and
  687. (taicpu(hp1).oper[2]^.shifterop^.shiftimm>=taicpu(hp2).oper[2]^.shifterop^.shiftimm) then
  688. begin
  689. dec(taicpu(hp1).oper[2]^.shifterop^.shiftimm,taicpu(hp2).oper[2]^.shifterop^.shiftimm);
  690. DebugMsg('Peephole ShiftShiftShift2ShiftShift 1 done', p);
  691. asml.remove(hp2);
  692. hp2.free;
  693. result := true;
  694. if taicpu(hp1).oper[2]^.shifterop^.shiftimm=0 then
  695. begin
  696. asml.remove(hp1);
  697. hp1.free;
  698. end;
  699. end
  700. { mov reg1,reg0, lsr/asr imm1
  701. mov reg1,reg1, lsl imm2
  702. mov reg1,reg1, lsr/asr imm3 ...
  703. if imm3>=imm1 and imm2>=imm1
  704. to
  705. mov reg1,reg0, lsl imm2-imm1
  706. mov reg1,reg1, lsr/asr imm3 ...
  707. }
  708. else if (taicpu(p).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and (taicpu(hp2).oper[2]^.shifterop^.shiftmode in [SM_ASR,SM_LSR]) and
  709. (taicpu(hp1).oper[2]^.shifterop^.shiftmode=SM_LSL) and
  710. (taicpu(hp2).oper[2]^.shifterop^.shiftimm>=taicpu(p).oper[2]^.shifterop^.shiftimm) and
  711. (taicpu(hp1).oper[2]^.shifterop^.shiftimm>=taicpu(p).oper[2]^.shifterop^.shiftimm) then
  712. begin
  713. dec(taicpu(hp1).oper[2]^.shifterop^.shiftimm,taicpu(p).oper[2]^.shifterop^.shiftimm);
  714. taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
  715. DebugMsg('Peephole ShiftShiftShift2ShiftShift 2 done', p);
  716. asml.remove(p);
  717. p.free;
  718. p:=hp2;
  719. if taicpu(hp1).oper[2]^.shifterop^.shiftimm=0 then
  720. begin
  721. taicpu(hp2).oper[1]^.reg:=taicpu(hp1).oper[1]^.reg;
  722. asml.remove(hp1);
  723. hp1.free;
  724. p:=hp2;
  725. end;
  726. result := true;
  727. end;
  728. end;
  729. end;
  730. { Change the common
  731. mov r0, r0, lsr #24
  732. and r0, r0, #255
  733. and remove the superfluous and
  734. This could be extended to handle more cases.
  735. }
  736. if (taicpu(p).ops=3) and
  737. (taicpu(p).oper[2]^.typ = top_shifterop) and
  738. (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
  739. (taicpu(p).oper[2]^.shifterop^.shiftmode = SM_LSR) and
  740. (taicpu(p).oper[2]^.shifterop^.shiftimm >= 24 ) and
  741. getnextinstruction(p,hp1) and
  742. MatchInstruction(hp1, A_AND, [taicpu(p).condition], [taicpu(p).oppostfix]) and
  743. (taicpu(hp1).ops=3) and
  744. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  745. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[1]^) and
  746. (taicpu(hp1).oper[2]^.typ = top_const) and
  747. { Check if the AND actually would only mask out bits beeing already zero because of the shift
  748. For LSR #25 and an AndConst of 255 that whould go like this:
  749. 255 and ((2 shl (32-25))-1)
  750. which results in 127, which is one less a power-of-2, meaning all lower bits are set.
  751. LSR #25 and AndConst of 254:
  752. 254 and ((2 shl (32-25))-1) = 126 -> lowest bit is clear, so we can't remove it.
  753. }
  754. ispowerof2((taicpu(hp1).oper[2]^.val and ((2 shl (32-taicpu(p).oper[2]^.shifterop^.shiftimm))-1))+1) then
  755. begin
  756. DebugMsg('Peephole LsrAnd2Lsr done', hp1);
  757. asml.remove(hp1);
  758. hp1.free;
  759. end;
  760. {
  761. optimize
  762. mov rX, yyyy
  763. ....
  764. }
  765. if (taicpu(p).ops = 2) and
  766. GetNextInstruction(p,hp1) and
  767. (tai(hp1).typ = ait_instruction) then
  768. begin
  769. {
  770. This changes the very common
  771. mov r0, #0
  772. str r0, [...]
  773. mov r0, #0
  774. str r0, [...]
  775. and removes all superfluous mov instructions
  776. }
  777. if (taicpu(p).oper[1]^.typ = top_const) and
  778. (taicpu(hp1).opcode=A_STR) then
  779. while MatchInstruction(hp1, A_STR, [taicpu(p).condition], []) and
  780. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  781. GetNextInstruction(hp1, hp2) and
  782. MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
  783. (taicpu(hp2).ops = 2) and
  784. MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^) and
  785. MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[1]^) do
  786. begin
  787. DebugMsg('Peephole MovStrMov done', hp2);
  788. GetNextInstruction(hp2,hp1);
  789. asml.remove(hp2);
  790. hp2.free;
  791. if not assigned(hp1) then break;
  792. end
  793. {
  794. This removes the first mov from
  795. mov rX,...
  796. mov rX,...
  797. }
  798. else if taicpu(hp1).opcode=A_MOV then
  799. while MatchInstruction(hp1, A_MOV, [taicpu(p).condition], [taicpu(p).oppostfix]) and
  800. (taicpu(hp1).ops = 2) and
  801. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^) and
  802. { don't remove the first mov if the second is a mov rX,rX }
  803. not(MatchOperand(taicpu(hp1).oper[0]^, taicpu(hp1).oper[1]^)) do
  804. begin
  805. DebugMsg('Peephole MovMov done', p);
  806. asml.remove(p);
  807. p.free;
  808. p:=hp1;
  809. GetNextInstruction(hp1,hp1);
  810. if not assigned(hp1) then
  811. break;
  812. end;
  813. end;
  814. {
  815. change
  816. mov r1, r0
  817. add r1, r1, #1
  818. to
  819. add r1, r0, #1
  820. Todo: Make it work for mov+cmp too
  821. CAUTION! If this one is successful p might not be a mov instruction anymore!
  822. }
  823. if (taicpu(p).ops = 2) and
  824. (taicpu(p).oper[1]^.typ = top_reg) and
  825. (taicpu(p).oppostfix = PF_NONE) and
  826. GetNextInstruction(p, hp1) and
  827. MatchInstruction(hp1, [A_ADD, A_ADC, A_RSB, A_RSC, A_SUB, A_SBC,
  828. A_AND, A_BIC, A_EOR, A_ORR, A_MOV, A_MVN],
  829. [taicpu(p).condition], []) and
  830. {MOV and MVN might only have 2 ops}
  831. (taicpu(hp1).ops = 3) and
  832. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[0]^.reg) and
  833. (taicpu(hp1).oper[1]^.typ = top_reg) and
  834. (taicpu(hp1).oper[2]^.typ in [top_reg, top_const, top_shifterop]) then
  835. begin
  836. { When we get here we still don't know if the registers match}
  837. for I:=1 to 2 do
  838. {
  839. If the first loop was successful p will be replaced with hp1.
  840. The checks will still be ok, because all required information
  841. will also be in hp1 then.
  842. }
  843. if MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg) then
  844. begin
  845. DebugMsg('Peephole RedundantMovProcess done', hp1);
  846. taicpu(hp1).oper[I]^.reg := taicpu(p).oper[1]^.reg;
  847. if p<>hp1 then
  848. begin
  849. asml.remove(p);
  850. p.free;
  851. p:=hp1;
  852. end;
  853. end;
  854. end;
  855. { This folds shifterops into following instructions
  856. mov r0, r1, lsl #8
  857. add r2, r3, r0
  858. to
  859. add r2, r3, r1, lsl #8
  860. CAUTION! If this one is successful p might not be a mov instruction anymore!
  861. }
  862. if (taicpu(p).opcode = A_MOV) and
  863. (taicpu(p).ops = 3) and
  864. (taicpu(p).oper[1]^.typ = top_reg) and
  865. (taicpu(p).oper[2]^.typ = top_shifterop) and
  866. (taicpu(p).oppostfix = PF_NONE) and
  867. GetNextInstruction(p, hp1) and
  868. MatchInstruction(hp1, [A_ADD, A_ADC, A_RSB, A_RSC, A_SUB, A_SBC,
  869. A_AND, A_BIC, A_EOR, A_ORR, A_TEQ, A_TST,
  870. A_CMP, A_CMN],
  871. [taicpu(p).condition], [PF_None]) and
  872. (taicpu(hp1).ops >= 2) and {Currently we can't fold into another shifterop}
  873. (taicpu(hp1).oper[taicpu(hp1).ops-1]^.typ = top_reg) and
  874. (
  875. {Only ONE of the two src operands is allowed to match}
  876. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[taicpu(hp1).ops-2]^) xor
  877. MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[taicpu(hp1).ops-1]^)
  878. ) then
  879. begin
  880. CopyUsedRegs(TmpUsedRegs);
  881. UpdateUsedRegs(TmpUsedRegs, tai(p.next));
  882. if taicpu(hp1).opcode in [A_TST, A_TEQ, A_CMN] then
  883. I2:=0
  884. else
  885. I2:=1;
  886. if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hp1,TmpUsedRegs)) then
  887. for I:=I2 to taicpu(hp1).ops-1 do
  888. if MatchOperand(taicpu(p).oper[0]^, taicpu(hp1).oper[I]^.reg) then
  889. begin
  890. { If the parameter matched on the second op from the RIGHT
  891. we have to switch the parameters, this will not happen for CMP
  892. were we're only evaluating the most right parameter
  893. }
  894. if I <> taicpu(hp1).ops-1 then
  895. begin
  896. {The SUB operators need to be changed when we swap parameters}
  897. case taicpu(hp1).opcode of
  898. A_SUB: tempop:=A_RSB;
  899. A_SBC: tempop:=A_RSC;
  900. A_RSB: tempop:=A_SUB;
  901. A_RSC: tempop:=A_SBC;
  902. else tempop:=taicpu(hp1).opcode;
  903. end;
  904. if taicpu(hp1).ops = 3 then
  905. hp2:=taicpu.op_reg_reg_reg_shifterop(tempop,
  906. taicpu(hp1).oper[0]^.reg, taicpu(hp1).oper[2]^.reg,
  907. taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
  908. else
  909. hp2:=taicpu.op_reg_reg_shifterop(tempop,
  910. taicpu(hp1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
  911. taicpu(p).oper[2]^.shifterop^);
  912. end
  913. else
  914. if taicpu(hp1).ops = 3 then
  915. hp2:=taicpu.op_reg_reg_reg_shifterop(taicpu(hp1).opcode,
  916. taicpu(hp1).oper[0]^.reg, taicpu(hp1).oper[1]^.reg,
  917. taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
  918. else
  919. hp2:=taicpu.op_reg_reg_shifterop(taicpu(hp1).opcode,
  920. taicpu(hp1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
  921. taicpu(p).oper[2]^.shifterop^);
  922. asml.insertbefore(hp2, p);
  923. asml.remove(p);
  924. asml.remove(hp1);
  925. p.free;
  926. hp1.free;
  927. p:=hp2;
  928. GetNextInstruction(p,hp1);
  929. DebugMsg('Peephole FoldShiftProcess done', p);
  930. break;
  931. end;
  932. ReleaseUsedRegs(TmpUsedRegs);
  933. end;
  934. {
  935. Often we see shifts and then a superfluous mov to another register
  936. In the future this might be handled in RedundantMovProcess when it uses RegisterTracking
  937. }
  938. if (taicpu(p).opcode = A_MOV) and
  939. GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) then
  940. RemoveSuperfluousMove(p, hp1, 'MovMov2Mov');
  941. end;
  942. A_ADD,
  943. A_ADC,
  944. A_RSB,
  945. A_RSC,
  946. A_SUB,
  947. A_SBC,
  948. A_AND,
  949. A_BIC,
  950. A_EOR,
  951. A_ORR,
  952. A_MLA,
  953. A_MUL:
  954. begin
  955. {
  956. optimize
  957. and reg2,reg1,const1
  958. ...
  959. }
  960. if (taicpu(p).opcode = A_AND) and
  961. (taicpu(p).oper[1]^.typ = top_reg) and
  962. (taicpu(p).oper[2]^.typ = top_const) then
  963. begin
  964. {
  965. change
  966. and reg2,reg1,const1
  967. and reg3,reg2,const2
  968. to
  969. and reg3,reg1,(const1 and const2)
  970. }
  971. if GetNextInstruction(p, hp1) and
  972. MatchInstruction(hp1, A_AND, [taicpu(p).condition], [PF_None]) and
  973. { either reg3 and reg2 are equal or reg2 is deallocated after the and }
  974. (MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[0]^.reg) or
  975. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next)))) and
  976. MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) and
  977. (taicpu(hp1).oper[2]^.typ = top_const) then
  978. begin
  979. DebugMsg('Peephole AndAnd2And done', p);
  980. taicpu(p).loadConst(2,taicpu(p).oper[2]^.val and taicpu(hp1).oper[2]^.val);
  981. taicpu(p).oppostfix:=taicpu(hp1).oppostfix;
  982. taicpu(p).loadReg(0,taicpu(hp1).oper[0]^.reg);
  983. asml.remove(hp1);
  984. hp1.free;
  985. end
  986. {
  987. change
  988. and reg2,reg1,255
  989. strb reg2,[...]
  990. dealloc reg2
  991. to
  992. strb reg1,[...]
  993. }
  994. else if (taicpu(p).oper[2]^.val = 255) and
  995. MatchInstruction(p, A_AND, [C_None], [PF_None]) and
  996. GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
  997. MatchInstruction(hp1, A_STR, [C_None], [PF_B]) and
  998. assigned(FindRegDealloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) and
  999. { the reference in strb might not use reg2 }
  1000. not(RegInRef(taicpu(p).oper[0]^.reg,taicpu(hp1).oper[1]^.ref^)) and
  1001. { reg1 might not be modified inbetween }
  1002. not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then
  1003. begin
  1004. DebugMsg('Peephole AndStrb2Strb done', p);
  1005. taicpu(hp1).loadReg(0,taicpu(p).oper[1]^.reg);
  1006. asml.remove(p);
  1007. p.free;
  1008. p:=hp1;
  1009. end;
  1010. end;
  1011. {
  1012. change
  1013. add/sub reg2,reg1,const1
  1014. str/ldr reg3,[reg2,const2]
  1015. dealloc reg2
  1016. to
  1017. str/ldr reg3,[reg1,const2+/-const1]
  1018. }
  1019. if (taicpu(p).opcode in [A_ADD,A_SUB]) and
  1020. (taicpu(p).oper[1]^.typ = top_reg) and
  1021. (taicpu(p).oper[2]^.typ = top_const) then
  1022. begin
  1023. hp1:=p;
  1024. while GetNextInstructionUsingReg(hp1, hp1, taicpu(p).oper[0]^.reg) and
  1025. { we cannot check NR_DEFAULTFLAGS for modification yet so don't allow a condition }
  1026. MatchInstruction(hp1, [A_LDR, A_STR], [C_None], []) and
  1027. (taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
  1028. { don't optimize if the register is stored/overwritten }
  1029. (taicpu(hp1).oper[0]^.reg<>taicpu(p).oper[1]^.reg) and
  1030. (taicpu(hp1).oper[1]^.ref^.index=NR_NO) and
  1031. (taicpu(hp1).oper[1]^.ref^.addressmode=AM_OFFSET) and
  1032. { new offset must be valid: either in the range of 8 or 12 bit, depend on the
  1033. ldr postfix }
  1034. (((taicpu(p).opcode=A_ADD) and
  1035. (((taicpu(hp1).oppostfix in [PF_None,PF_B]) and
  1036. (abs(taicpu(hp1).oper[1]^.ref^.offset+taicpu(p).oper[2]^.val)<4096)) or
  1037. (abs(taicpu(hp1).oper[1]^.ref^.offset+taicpu(p).oper[2]^.val)<256)
  1038. )
  1039. ) or
  1040. ((taicpu(p).opcode=A_SUB) and
  1041. (((taicpu(hp1).oppostfix in [PF_None,PF_B]) and
  1042. (abs(taicpu(hp1).oper[1]^.ref^.offset-taicpu(p).oper[2]^.val)<4096)) or
  1043. (abs(taicpu(hp1).oper[1]^.ref^.offset-taicpu(p).oper[2]^.val)<256)
  1044. )
  1045. )
  1046. ) do
  1047. begin
  1048. { neither reg1 nor reg2 might be changed inbetween }
  1049. if RegModifiedBetween(taicpu(p).oper[0]^.reg,p,hp1) or
  1050. RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1) then
  1051. break;
  1052. { reg2 must be either overwritten by the ldr or it is deallocated afterwards }
  1053. if ((taicpu(hp1).opcode=A_LDR) and (taicpu(p).oper[0]^.reg=taicpu(hp1).oper[0]^.reg)) or
  1054. assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next))) then
  1055. begin
  1056. { remember last instruction }
  1057. hp2:=hp1;
  1058. DebugMsg('Peephole Add/SubLdr2Ldr done', p);
  1059. hp1:=p;
  1060. { fix all ldr/str }
  1061. while GetNextInstructionUsingReg(hp1, hp1, taicpu(p).oper[0]^.reg) do
  1062. begin
  1063. taicpu(hp1).oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
  1064. if taicpu(p).opcode=A_ADD then
  1065. inc(taicpu(hp1).oper[1]^.ref^.offset,taicpu(p).oper[2]^.val)
  1066. else
  1067. dec(taicpu(hp1).oper[1]^.ref^.offset,taicpu(p).oper[2]^.val);
  1068. if hp1=hp2 then
  1069. break;
  1070. end;
  1071. GetNextInstruction(p,hp1);
  1072. asml.remove(p);
  1073. p.free;
  1074. p:=hp1;
  1075. break;
  1076. end;
  1077. end;
  1078. end;
  1079. {
  1080. change
  1081. add reg1, ...
  1082. mov reg2, reg1
  1083. to
  1084. add reg2, ...
  1085. }
  1086. if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) then
  1087. RemoveSuperfluousMove(p, hp1, 'DataMov2Data');
  1088. end;
  1089. A_CMP:
  1090. begin
  1091. {
  1092. change
  1093. cmp reg,const1
  1094. moveq reg,const1
  1095. movne reg,const2
  1096. to
  1097. cmp reg,const1
  1098. movne reg,const2
  1099. }
  1100. if (taicpu(p).oper[1]^.typ = top_const) and
  1101. GetNextInstruction(p, hp1) and
  1102. MatchInstruction(hp1, A_MOV, [C_EQ, C_NE], [PF_NONE]) and
  1103. (taicpu(hp1).oper[1]^.typ = top_const) and
  1104. GetNextInstruction(hp1, hp2) and
  1105. MatchInstruction(hp2, A_MOV, [C_EQ, C_NE], [PF_NONE]) and
  1106. (taicpu(hp1).oper[1]^.typ = top_const) then
  1107. begin
  1108. RemoveRedundantMove(p, hp1, asml);
  1109. RemoveRedundantMove(p, hp2, asml);
  1110. end;
  1111. end;
  1112. end;
  1113. end;
  1114. end;
  1115. end;
  1116. { instructions modifying the CPSR can be only the last instruction }
  1117. function MustBeLast(p : tai) : boolean;
  1118. begin
  1119. Result:=(p.typ=ait_instruction) and
  1120. ((taicpu(p).opcode in [A_BL,A_BLX,A_CMP,A_CMN,A_SWI,A_TEQ,A_TST,A_CMF,A_CMFE {,A_MSR}]) or
  1121. ((taicpu(p).ops>=1) and (taicpu(p).oper[0]^.typ=top_reg) and (taicpu(p).oper[0]^.reg=NR_PC)) or
  1122. (taicpu(p).oppostfix=PF_S));
  1123. end;
  1124. procedure TCpuAsmOptimizer.PeepHoleOptPass2;
  1125. var
  1126. p,hp1,hp2: tai;
  1127. l : longint;
  1128. condition : tasmcond;
  1129. hp3: tai;
  1130. WasLast: boolean;
  1131. { UsedRegs, TmpUsedRegs: TRegSet; }
  1132. begin
  1133. p := BlockStart;
  1134. { UsedRegs := []; }
  1135. while (p <> BlockEnd) Do
  1136. begin
  1137. { UpdateUsedRegs(UsedRegs, tai(p.next)); }
  1138. case p.Typ Of
  1139. Ait_Instruction:
  1140. begin
  1141. case taicpu(p).opcode Of
  1142. A_B:
  1143. if taicpu(p).condition<>C_None then
  1144. begin
  1145. { check for
  1146. Bxx xxx
  1147. <several instructions>
  1148. xxx:
  1149. }
  1150. l:=0;
  1151. WasLast:=False;
  1152. GetNextInstruction(p, hp1);
  1153. while assigned(hp1) and
  1154. (l<=4) and
  1155. CanBeCond(hp1) and
  1156. { stop on labels }
  1157. not(hp1.typ=ait_label) do
  1158. begin
  1159. inc(l);
  1160. if MustBeLast(hp1) then
  1161. begin
  1162. WasLast:=True;
  1163. GetNextInstruction(hp1,hp1);
  1164. break;
  1165. end
  1166. else
  1167. GetNextInstruction(hp1,hp1);
  1168. end;
  1169. if assigned(hp1) then
  1170. begin
  1171. if FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then
  1172. begin
  1173. if (l<=4) and (l>0) then
  1174. begin
  1175. condition:=inverse_cond(taicpu(p).condition);
  1176. hp2:=p;
  1177. GetNextInstruction(p,hp1);
  1178. p:=hp1;
  1179. repeat
  1180. if hp1.typ=ait_instruction then
  1181. taicpu(hp1).condition:=condition;
  1182. if MustBeLast(hp1) then
  1183. begin
  1184. GetNextInstruction(hp1,hp1);
  1185. break;
  1186. end
  1187. else
  1188. GetNextInstruction(hp1,hp1);
  1189. until not(assigned(hp1)) or
  1190. not(CanBeCond(hp1)) or
  1191. (hp1.typ=ait_label);
  1192. { wait with removing else GetNextInstruction could
  1193. ignore the label if it was the only usage in the
  1194. jump moved away }
  1195. tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs;
  1196. asml.remove(hp2);
  1197. hp2.free;
  1198. continue;
  1199. end;
  1200. end
  1201. else
  1202. { do not perform further optimizations if there is inctructon
  1203. in block #1 which can not be optimized.
  1204. }
  1205. if not WasLast then
  1206. begin
  1207. { check further for
  1208. Bcc xxx
  1209. <several instructions 1>
  1210. B yyy
  1211. xxx:
  1212. <several instructions 2>
  1213. yyy:
  1214. }
  1215. { hp2 points to jmp yyy }
  1216. hp2:=hp1;
  1217. { skip hp1 to xxx }
  1218. GetNextInstruction(hp1, hp1);
  1219. if assigned(hp2) and
  1220. assigned(hp1) and
  1221. (l<=3) and
  1222. (hp2.typ=ait_instruction) and
  1223. (taicpu(hp2).is_jmp) and
  1224. (taicpu(hp2).condition=C_None) and
  1225. { real label and jump, no further references to the
  1226. label are allowed }
  1227. (tasmlabel(taicpu(p).oper[0]^.ref^.symbol).getrefs=2) and
  1228. FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then
  1229. begin
  1230. l:=0;
  1231. { skip hp1 to <several moves 2> }
  1232. GetNextInstruction(hp1, hp1);
  1233. while assigned(hp1) and
  1234. CanBeCond(hp1) do
  1235. begin
  1236. inc(l);
  1237. GetNextInstruction(hp1, hp1);
  1238. end;
  1239. { hp1 points to yyy: }
  1240. if assigned(hp1) and
  1241. FindLabel(tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol),hp1) then
  1242. begin
  1243. condition:=inverse_cond(taicpu(p).condition);
  1244. GetNextInstruction(p,hp1);
  1245. hp3:=p;
  1246. p:=hp1;
  1247. repeat
  1248. if hp1.typ=ait_instruction then
  1249. taicpu(hp1).condition:=condition;
  1250. GetNextInstruction(hp1,hp1);
  1251. until not(assigned(hp1)) or
  1252. not(CanBeCond(hp1));
  1253. { hp2 is still at jmp yyy }
  1254. GetNextInstruction(hp2,hp1);
  1255. { hp2 is now at xxx: }
  1256. condition:=inverse_cond(condition);
  1257. GetNextInstruction(hp1,hp1);
  1258. { hp1 is now at <several movs 2> }
  1259. repeat
  1260. taicpu(hp1).condition:=condition;
  1261. GetNextInstruction(hp1,hp1);
  1262. until not(assigned(hp1)) or
  1263. not(CanBeCond(hp1)) or
  1264. (hp1.typ=ait_label);
  1265. {
  1266. asml.remove(hp1.next)
  1267. hp1.next.free;
  1268. asml.remove(hp1);
  1269. hp1.free;
  1270. }
  1271. { remove Bcc }
  1272. tasmlabel(taicpu(hp3).oper[0]^.ref^.symbol).decrefs;
  1273. asml.remove(hp3);
  1274. hp3.free;
  1275. { remove jmp }
  1276. tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs;
  1277. asml.remove(hp2);
  1278. hp2.free;
  1279. continue;
  1280. end;
  1281. end;
  1282. end;
  1283. end;
  1284. end;
  1285. end;
  1286. end;
  1287. end;
  1288. p := tai(p.next)
  1289. end;
  1290. end;
  1291. function TCpuAsmOptimizer.RegInInstruction(Reg: TRegister; p1: tai): Boolean;
  1292. begin
  1293. If (p1.typ = ait_instruction) and (taicpu(p1).opcode=A_BL) then
  1294. Result:=true
  1295. else
  1296. Result:=inherited RegInInstruction(Reg, p1);
  1297. end;
  1298. const
  1299. { set of opcode which might or do write to memory }
  1300. { TODO : extend armins.dat to contain r/w info }
  1301. opcode_could_mem_write = [A_B,A_BL,A_BLX,A_BKPT,A_BX,A_STR,A_STRB,A_STRBT,
  1302. A_STRH,A_STRT,A_STF,A_SFM,A_STM,A_FSTS,A_FSTD];
  1303. { adjust the register live information when swapping the two instructions p and hp1,
  1304. they must follow one after the other }
  1305. procedure TCpuPreRegallocScheduler.SwapRegLive(p,hp1 : taicpu);
  1306. procedure CheckLiveEnd(reg : tregister);
  1307. var
  1308. supreg : TSuperRegister;
  1309. regtype : TRegisterType;
  1310. begin
  1311. if reg=NR_NO then
  1312. exit;
  1313. regtype:=getregtype(reg);
  1314. supreg:=getsupreg(reg);
  1315. if (cg.rg[regtype].live_end[supreg]=hp1) and
  1316. RegInInstruction(reg,p) then
  1317. cg.rg[regtype].live_end[supreg]:=p;
  1318. end;
  1319. procedure CheckLiveStart(reg : TRegister);
  1320. var
  1321. supreg : TSuperRegister;
  1322. regtype : TRegisterType;
  1323. begin
  1324. if reg=NR_NO then
  1325. exit;
  1326. regtype:=getregtype(reg);
  1327. supreg:=getsupreg(reg);
  1328. if (cg.rg[regtype].live_start[supreg]=p) and
  1329. RegInInstruction(reg,hp1) then
  1330. cg.rg[regtype].live_start[supreg]:=hp1;
  1331. end;
  1332. var
  1333. i : longint;
  1334. r : TSuperRegister;
  1335. begin
  1336. { assumption: p is directly followed by hp1 }
  1337. { if live of any reg used by p starts at p and hp1 uses this register then
  1338. set live start to hp1 }
  1339. for i:=0 to p.ops-1 do
  1340. case p.oper[i]^.typ of
  1341. Top_Reg:
  1342. CheckLiveStart(p.oper[i]^.reg);
  1343. Top_Ref:
  1344. begin
  1345. CheckLiveStart(p.oper[i]^.ref^.base);
  1346. CheckLiveStart(p.oper[i]^.ref^.index);
  1347. end;
  1348. Top_Shifterop:
  1349. CheckLiveStart(p.oper[i]^.shifterop^.rs);
  1350. Top_RegSet:
  1351. for r:=RS_R0 to RS_R15 do
  1352. if r in p.oper[i]^.regset^ then
  1353. CheckLiveStart(newreg(R_INTREGISTER,r,R_SUBWHOLE));
  1354. end;
  1355. { if live of any reg used by hp1 ends at hp1 and p uses this register then
  1356. set live end to p }
  1357. for i:=0 to hp1.ops-1 do
  1358. case hp1.oper[i]^.typ of
  1359. Top_Reg:
  1360. CheckLiveEnd(hp1.oper[i]^.reg);
  1361. Top_Ref:
  1362. begin
  1363. CheckLiveEnd(hp1.oper[i]^.ref^.base);
  1364. CheckLiveEnd(hp1.oper[i]^.ref^.index);
  1365. end;
  1366. Top_Shifterop:
  1367. CheckLiveStart(hp1.oper[i]^.shifterop^.rs);
  1368. Top_RegSet:
  1369. for r:=RS_R0 to RS_R15 do
  1370. if r in hp1.oper[i]^.regset^ then
  1371. CheckLiveEnd(newreg(R_INTREGISTER,r,R_SUBWHOLE));
  1372. end;
  1373. end;
  1374. function TCpuPreRegallocScheduler.SchedulerPass1Cpu(var p: tai): boolean;
  1375. { TODO : schedule also forward }
  1376. { TODO : schedule distance > 1 }
  1377. var
  1378. hp1,hp2,hp3,hp4,hp5 : tai;
  1379. list : TAsmList;
  1380. begin
  1381. result:=true;
  1382. list:=TAsmList.Create;
  1383. p:=BlockStart;
  1384. while p<>BlockEnd Do
  1385. begin
  1386. if (p.typ=ait_instruction) and
  1387. GetNextInstruction(p,hp1) and
  1388. (hp1.typ=ait_instruction) and
  1389. (taicpu(hp1).opcode in [A_LDR,A_LDRB,A_LDRH,A_LDRSB,A_LDRSH]) and
  1390. { for now we don't reschedule if the previous instruction changes potentially a memory location }
  1391. ( (not(taicpu(p).opcode in opcode_could_mem_write) and
  1392. not(RegModifiedByInstruction(NR_PC,p))
  1393. ) or
  1394. ((taicpu(p).opcode in [A_STM,A_STRB,A_STRH,A_STR]) and
  1395. ((taicpu(hp1).oper[1]^.ref^.base=NR_PC) or
  1396. (assigned(taicpu(hp1).oper[1]^.ref^.symboldata) and
  1397. (taicpu(hp1).oper[1]^.ref^.offset=0)
  1398. )
  1399. ) or
  1400. { try to prove that the memory accesses don't overlapp }
  1401. ((taicpu(p).opcode in [A_STRB,A_STRH,A_STR]) and
  1402. (taicpu(p).oper[1]^.ref^.base=taicpu(hp1).oper[1]^.ref^.base) and
  1403. (taicpu(p).oppostfix=PF_None) and
  1404. (taicpu(hp1).oppostfix=PF_None) and
  1405. (taicpu(p).oper[1]^.ref^.index=NR_NO) and
  1406. (taicpu(hp1).oper[1]^.ref^.index=NR_NO) and
  1407. { get operand sizes and check if the offset distance is large enough to ensure no overlapp }
  1408. (abs(taicpu(p).oper[1]^.ref^.offset-taicpu(hp1).oper[1]^.ref^.offset)>=max(tcgsize2size[reg_cgsize(taicpu(p).oper[0]^.reg)],tcgsize2size[reg_cgsize(taicpu(hp1).oper[0]^.reg)]))
  1409. )
  1410. )
  1411. ) and
  1412. GetNextInstruction(hp1,hp2) and
  1413. (hp2.typ=ait_instruction) and
  1414. { loaded register used by next instruction? }
  1415. (RegInInstruction(taicpu(hp1).oper[0]^.reg,hp2)) and
  1416. { loaded register not used by previous instruction? }
  1417. not(RegInInstruction(taicpu(hp1).oper[0]^.reg,p)) and
  1418. { same condition? }
  1419. (taicpu(p).condition=taicpu(hp1).condition) and
  1420. { first instruction might not change the register used as base }
  1421. ((taicpu(hp1).oper[1]^.ref^.base=NR_NO) or
  1422. not(RegModifiedByInstruction(taicpu(hp1).oper[1]^.ref^.base,p))
  1423. ) and
  1424. { first instruction might not change the register used as index }
  1425. ((taicpu(hp1).oper[1]^.ref^.index=NR_NO) or
  1426. not(RegModifiedByInstruction(taicpu(hp1).oper[1]^.ref^.index,p))
  1427. ) then
  1428. begin
  1429. hp3:=tai(p.Previous);
  1430. hp5:=tai(p.next);
  1431. asml.Remove(p);
  1432. { if there is a reg. dealloc instruction associated with p, move it together with p }
  1433. { before the instruction? }
  1434. while assigned(hp3) and (hp3.typ<>ait_instruction) do
  1435. begin
  1436. if (hp3.typ=ait_regalloc) and (tai_regalloc(hp3).ratype in [ra_dealloc]) and
  1437. RegInInstruction(tai_regalloc(hp3).reg,p) then
  1438. begin
  1439. hp4:=hp3;
  1440. hp3:=tai(hp3.Previous);
  1441. asml.Remove(hp4);
  1442. list.Concat(hp4);
  1443. end
  1444. else
  1445. hp3:=tai(hp3.Previous);
  1446. end;
  1447. list.Concat(p);
  1448. SwapRegLive(taicpu(p),taicpu(hp1));
  1449. { after the instruction? }
  1450. while assigned(hp5) and (hp5.typ<>ait_instruction) do
  1451. begin
  1452. if (hp5.typ=ait_regalloc) and (tai_regalloc(hp5).ratype in [ra_dealloc]) and
  1453. RegInInstruction(tai_regalloc(hp5).reg,p) then
  1454. begin
  1455. hp4:=hp5;
  1456. hp5:=tai(hp5.next);
  1457. asml.Remove(hp4);
  1458. list.Concat(hp4);
  1459. end
  1460. else
  1461. hp5:=tai(hp5.Next);
  1462. end;
  1463. asml.Remove(hp1);
  1464. {$ifdef DEBUG_PREREGSCHEDULER}
  1465. asml.insertbefore(tai_comment.Create(strpnew('Rescheduled')),hp2);
  1466. {$endif DEBUG_PREREGSCHEDULER}
  1467. asml.InsertBefore(hp1,hp2);
  1468. asml.InsertListBefore(hp2,list);
  1469. p:=tai(p.next)
  1470. end
  1471. else if p.typ=ait_instruction then
  1472. p:=hp1
  1473. else
  1474. p:=tai(p.next);
  1475. end;
  1476. list.Free;
  1477. end;
  1478. procedure TCpuThumb2AsmOptimizer.PeepHoleOptPass2;
  1479. begin
  1480. { TODO: Add optimizer code }
  1481. end;
  1482. begin
  1483. casmoptimizer:=TCpuAsmOptimizer;
  1484. cpreregallocscheduler:=TCpuPreRegallocScheduler;
  1485. End.