daopt386.pas 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Jonas Maebe, member of the Freepascal
  4. development team
  5. This unit contains the data flow analyzer and several helper procedures
  6. and functions.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. unit daopt386;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. globtype,
  25. cclasses,aasmbase,aasmtai,aasmcpu,cgbase,
  26. cpubase,optbase;
  27. {******************************* Constants *******************************}
  28. const
  29. { Possible register content types }
  30. con_Unknown = 0;
  31. con_ref = 1;
  32. con_const = 2;
  33. { The contents aren't usable anymore for CSE, but they may still be }
  34. { usefull for detecting whether the result of a load is actually used }
  35. con_invalid = 3;
  36. { the reverse of the above (in case a (conditional) jump is encountered): }
  37. { CSE is still possible, but the original instruction can't be removed }
  38. con_noRemoveRef = 4;
  39. { same, but for constants }
  40. con_noRemoveConst = 5;
  41. {********************************* Types *********************************}
  42. type
  43. TRegArray = Array[RS_EAX..RS_ESP] of tsuperregister;
  44. TRegSet = Set of RS_EAX..RS_ESP;
  45. toptreginfo = Record
  46. NewRegsEncountered, OldRegsEncountered: TRegSet;
  47. RegsLoadedForRef: TRegSet;
  48. regsStillUsedAfterSeq: TRegSet;
  49. lastReload: array[RS_EAX..RS_ESP] of tai;
  50. New2OldReg: TRegArray;
  51. end;
  52. {possible actions on an operand: read, write or modify (= read & write)}
  53. TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
  54. {the possible states of a flag}
  55. TFlagContents = (F_Unknown, F_notSet, F_Set);
  56. TContent = Packed Record
  57. {start and end of block instructions that defines the
  58. content of this register.}
  59. StartMod: tai;
  60. MemWrite: taicpu;
  61. {how many instructions starting with StarMod does the block consist of}
  62. NrOfMods: Word;
  63. {the type of the content of the register: unknown, memory, constant}
  64. Typ: Byte;
  65. case byte of
  66. {starts at 0, gets increased everytime the register is written to}
  67. 1: (WState: Byte;
  68. {starts at 0, gets increased everytime the register is read from}
  69. RState: Byte);
  70. { to compare both states in one operation }
  71. 2: (state: word);
  72. end;
  73. {Contents of the integer registers}
  74. TRegContent = Array[RS_EAX..RS_ESP] Of TContent;
  75. {contents of the FPU registers}
  76. // TRegFPUContent = Array[RS_ST..RS_ST7] Of TContent;
  77. {$ifdef tempOpts}
  78. { linked list which allows searching/deleting based on value, no extra frills}
  79. PSearchLinkedListItem = ^TSearchLinkedListItem;
  80. TSearchLinkedListItem = object(TLinkedList_Item)
  81. constructor init;
  82. function equals(p: PSearchLinkedListItem): boolean; virtual;
  83. end;
  84. PSearchDoubleIntItem = ^TSearchDoubleInttem;
  85. TSearchDoubleIntItem = object(TLinkedList_Item)
  86. constructor init(_int1,_int2: longint);
  87. function equals(p: PSearchLinkedListItem): boolean; virtual;
  88. private
  89. int1, int2: longint;
  90. end;
  91. PSearchLinkedList = ^TSearchLinkedList;
  92. TSearchLinkedList = object(TLinkedList)
  93. function searchByValue(p: PSearchLinkedListItem): boolean;
  94. procedure removeByValue(p: PSearchLinkedListItem);
  95. end;
  96. {$endif tempOpts}
  97. {information record with the contents of every register. Every tai object
  98. gets one of these assigned: a pointer to it is stored in the OptInfo field}
  99. TtaiProp = Record
  100. Regs: TRegContent;
  101. { FPURegs: TRegFPUContent;} {currently not yet used}
  102. { allocated Registers }
  103. UsedRegs: TRegSet;
  104. { status of the direction flag }
  105. DirFlag: TFlagContents;
  106. {$ifdef tempOpts}
  107. { currently used temps }
  108. tempAllocs: PSearchLinkedList;
  109. {$endif tempOpts}
  110. { can this instruction be removed? }
  111. CanBeRemoved: Boolean;
  112. { are the resultflags set by this instruction used? }
  113. FlagsUsed: Boolean;
  114. end;
  115. ptaiprop = ^TtaiProp;
  116. TtaiPropBlock = Array[1..250000] Of TtaiProp;
  117. PtaiPropBlock = ^TtaiPropBlock;
  118. TInstrSinceLastMod = Array[RS_EAX..RS_ESP] Of Word;
  119. TLabelTableItem = Record
  120. taiObj: tai;
  121. {$ifDef JumpAnal}
  122. InstrNr: Longint;
  123. RefsFound: Word;
  124. JmpsProcessed: Word
  125. {$endif JumpAnal}
  126. end;
  127. TLabelTable = Array[0..2500000] Of TLabelTableItem;
  128. PLabelTable = ^TLabelTable;
  129. {*********************** procedures and functions ************************}
  130. procedure InsertLLItem(AsmL: TAAsmOutput; prev, foll, new_one: TLinkedListItem);
  131. function RefsEquivalent(const R1, R2: TReference; var RegInfo: toptreginfo; OpAct: TOpAction): Boolean;
  132. function RefsEqual(const R1, R2: TReference): Boolean;
  133. function isgp32reg(supreg: tsuperregister): Boolean;
  134. function reginref(supreg: tsuperregister; const ref: treference): boolean;
  135. function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
  136. function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
  137. function RegInInstruction(supreg: tsuperregister; p1: tai): boolean;
  138. function reginop(supreg: tsuperregister; const o:toper): boolean;
  139. function instrWritesFlags(p: tai): boolean;
  140. function instrReadsFlags(p: tai): boolean;
  141. function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
  142. supreg: tsuperregister; const c: tcontent; var invalsmemwrite: boolean): boolean;
  143. function writeToRegDestroysContents(destReg, supreg: tsuperregister;
  144. const c: tcontent): boolean;
  145. function writeDestroysContents(const op: toper; supreg: tsuperregister;
  146. const c: tcontent; var memwritedestroyed: boolean): boolean;
  147. function GetNextInstruction(Current: tai; var Next: tai): Boolean;
  148. function GetLastInstruction(Current: tai; var Last: tai): Boolean;
  149. procedure SkipHead(var p: tai);
  150. function labelCanBeSkipped(p: tai_label): boolean;
  151. procedure RemoveLastDeallocForFuncRes(asmL: TAAsmOutput; p: tai);
  152. function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
  153. hp: tai): boolean;
  154. procedure UpdateUsedRegs(var UsedRegs: TRegSet; p: tai);
  155. procedure AllocRegBetween(asml: taasmoutput; reg: tregister; p1, p2: tai);
  156. function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
  157. //function RegsEquivalent(OldReg, NewReg: tregister; var RegInfo: toptreginfo; OpAct: TopAction): Boolean;
  158. function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
  159. function sizescompatible(loadsize,newsize: topsize): boolean;
  160. function OpsEqual(const o1,o2:toper): Boolean;
  161. type
  162. tdfaobj = class
  163. constructor create(_list: taasmoutput); virtual;
  164. function pass_1(_blockstart: tai): tai;
  165. function pass_2: boolean;
  166. procedure clear;
  167. function getlabelwithsym(sym: tasmlabel): tai;
  168. private
  169. { Walks through the list to find the lowest and highest label number, inits the }
  170. { labeltable and fixes/optimizes some regallocs }
  171. procedure initlabeltable;
  172. function initdfapass2: boolean;
  173. procedure dodfapass2;
  174. { asm list we're working on }
  175. list: taasmoutput;
  176. { current part of the asm list }
  177. blockstart, blockend: tai;
  178. { the amount of taiObjects in the current part of the assembler list }
  179. nroftaiobjs: longint;
  180. { Array which holds all TtaiProps }
  181. taipropblock: ptaipropblock;
  182. { all labels in the current block: their value mapped to their location }
  183. lolab, hilab, labdif: longint;
  184. labeltable: plabeltable;
  185. end;
  186. function FindLabel(L: tasmlabel; var hp: tai): Boolean;
  187. procedure incState(var S: Byte; amount: longint);
  188. {******************************* Variables *******************************}
  189. var
  190. dfa: tdfaobj;
  191. {*********************** end of Interface section ************************}
  192. Implementation
  193. Uses
  194. {$ifdef csdebug}
  195. cutils,
  196. {$else}
  197. {$ifdef statedebug}
  198. cutils,
  199. {$endif}
  200. {$endif}
  201. globals, systems, verbose, symconst, symsym, cgobj,
  202. rgobj, procinfo;
  203. Type
  204. TRefCompare = function(const r1, r2: TReference): Boolean;
  205. var
  206. {How many instructions are between the current instruction and the last one
  207. that modified the register}
  208. NrOfInstrSinceLastMod: TInstrSinceLastMod;
  209. {$ifdef tempOpts}
  210. constructor TSearchLinkedListItem.init;
  211. begin
  212. end;
  213. function TSearchLinkedListItem.equals(p: PSearchLinkedListItem): boolean;
  214. begin
  215. equals := false;
  216. end;
  217. constructor TSearchDoubleIntItem.init(_int1,_int2: longint);
  218. begin
  219. int1 := _int1;
  220. int2 := _int2;
  221. end;
  222. function TSearchDoubleIntItem.equals(p: PSearchLinkedListItem): boolean;
  223. begin
  224. equals := (TSearchDoubleIntItem(p).int1 = int1) and
  225. (TSearchDoubleIntItem(p).int2 = int2);
  226. end;
  227. function TSearchLinkedList.searchByValue(p: PSearchLinkedListItem): boolean;
  228. var temp: PSearchLinkedListItem;
  229. begin
  230. temp := first;
  231. while (temp <> last.next) and
  232. not(temp.equals(p)) do
  233. temp := temp.next;
  234. searchByValue := temp <> last.next;
  235. end;
  236. procedure TSearchLinkedList.removeByValue(p: PSearchLinkedListItem);
  237. begin
  238. temp := first;
  239. while (temp <> last.next) and
  240. not(temp.equals(p)) do
  241. temp := temp.next;
  242. if temp <> last.next then
  243. begin
  244. remove(temp);
  245. dispose(temp,done);
  246. end;
  247. end;
  248. procedure updateTempAllocs(var UsedRegs: TRegSet; p: tai);
  249. {updates UsedRegs with the RegAlloc Information coming after p}
  250. begin
  251. repeat
  252. while assigned(p) and
  253. ((p.typ in (SkipInstr - [ait_RegAlloc])) or
  254. ((p.typ = ait_label) and
  255. labelCanBeSkipped(tai_label(current)))) Do
  256. p := tai(p.next);
  257. while assigned(p) and
  258. (p.typ=ait_RegAlloc) Do
  259. begin
  260. case tai_regalloc(p).ratype of
  261. ra_alloc :
  262. UsedRegs := UsedRegs + [tai_regalloc(p).reg];
  263. ra_dealloc :
  264. UsedRegs := UsedRegs - [tai_regalloc(p).reg];
  265. end;
  266. p := tai(p.next);
  267. end;
  268. until not(assigned(p)) or
  269. (not(p.typ in SkipInstr) and
  270. not((p.typ = ait_label) and
  271. labelCanBeSkipped(tai_label(current))));
  272. end;
  273. {$endif tempOpts}
  274. {************************ Create the Label table ************************}
  275. function findregalloc(reg: tregister; starttai: tai; ratyp: tregalloctype): boolean;
  276. { Returns true if a ait_alloc object for reg is found in the block of tai's }
  277. { starting with Starttai and ending with the next "real" instruction }
  278. var
  279. supreg: tsuperregister;
  280. begin
  281. findregalloc := false;
  282. supreg := getsupreg(reg);
  283. repeat
  284. while assigned(starttai) and
  285. ((starttai.typ in (skipinstr - [ait_regalloc])) or
  286. ((starttai.typ = ait_label) and
  287. labelcanbeskipped(tai_label(starttai)))) do
  288. starttai := tai(starttai.next);
  289. if assigned(starttai) and
  290. (starttai.typ = ait_regalloc) then
  291. begin
  292. if (tai_regalloc(Starttai).ratype = ratyp) and
  293. (getsupreg(tai_regalloc(Starttai).reg) = supreg) then
  294. begin
  295. findregalloc:=true;
  296. break;
  297. end;
  298. starttai := tai(starttai.next);
  299. end
  300. else
  301. break;
  302. until false;
  303. end;
  304. procedure RemoveLastDeallocForFuncRes(asml: taasmoutput; p: tai);
  305. procedure DoRemoveLastDeallocForFuncRes(asml: taasmoutput; supreg: tsuperregister);
  306. var
  307. hp2: tai;
  308. begin
  309. hp2 := p;
  310. repeat
  311. hp2 := tai(hp2.previous);
  312. if assigned(hp2) and
  313. (hp2.typ = ait_regalloc) and
  314. (tai_regalloc(hp2).ratype=ra_dealloc) and
  315. (getregtype(tai_regalloc(hp2).reg) = R_INTREGISTER) and
  316. (getsupreg(tai_regalloc(hp2).reg) = supreg) then
  317. begin
  318. asml.remove(hp2);
  319. hp2.free;
  320. break;
  321. end;
  322. until not(assigned(hp2)) or regInInstruction(supreg,hp2);
  323. end;
  324. begin
  325. case current_procinfo.procdef.rettype.def.deftype of
  326. arraydef,recorddef,pointerdef,
  327. stringdef,enumdef,procdef,objectdef,errordef,
  328. filedef,setdef,procvardef,
  329. classrefdef,forwarddef:
  330. DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
  331. orddef:
  332. if current_procinfo.procdef.rettype.def.size <> 0 then
  333. begin
  334. DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
  335. { for int64/qword }
  336. if current_procinfo.procdef.rettype.def.size = 8 then
  337. DoRemoveLastDeallocForFuncRes(asml,RS_EDX);
  338. end;
  339. end;
  340. end;
  341. procedure getNoDeallocRegs(var regs: tregset);
  342. var
  343. regCounter: TSuperRegister;
  344. begin
  345. regs := [];
  346. case current_procinfo.procdef.rettype.def.deftype of
  347. arraydef,recorddef,pointerdef,
  348. stringdef,enumdef,procdef,objectdef,errordef,
  349. filedef,setdef,procvardef,
  350. classrefdef,forwarddef:
  351. regs := [RS_EAX];
  352. orddef:
  353. if current_procinfo.procdef.rettype.def.size <> 0 then
  354. begin
  355. regs := [RS_EAX];
  356. { for int64/qword }
  357. if current_procinfo.procdef.rettype.def.size = 8 then
  358. regs := regs + [RS_EDX];
  359. end;
  360. end;
  361. for regCounter := RS_EAX to RS_EBX do
  362. { if not(regCounter in rg.usableregsint) then}
  363. include(regs,regcounter);
  364. end;
  365. procedure AddRegDeallocFor(asml: taasmoutput; reg: tregister; p: tai);
  366. var
  367. hp1: tai;
  368. funcResRegs: tregset;
  369. funcResReg: boolean;
  370. begin
  371. { if not(supreg in rg.usableregsint) then
  372. exit;}
  373. { if not(supreg in [RS_EDI]) then
  374. exit;}
  375. getNoDeallocRegs(funcresregs);
  376. { funcResRegs := funcResRegs - rg.usableregsint;}
  377. { funcResRegs := funcResRegs - [RS_EDI];}
  378. { funcResRegs := funcResRegs - [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI]; }
  379. funcResReg := getsupreg(reg) in funcresregs;
  380. hp1 := p;
  381. {
  382. while not(funcResReg and
  383. (p.typ = ait_instruction) and
  384. (taicpu(p).opcode = A_JMP) and
  385. (tasmlabel(taicpu(p).oper[0]^.sym) = aktexit2label)) and
  386. getLastInstruction(p, p) and
  387. not(regInInstruction(supreg, p)) do
  388. hp1 := p;
  389. }
  390. { don't insert a dealloc for registers which contain the function result }
  391. { if they are followed by a jump to the exit label (for exit(...)) }
  392. { if not(funcResReg) or
  393. not((hp1.typ = ait_instruction) and
  394. (taicpu(hp1).opcode = A_JMP) and
  395. (tasmlabel(taicpu(hp1).oper[0]^.sym) = aktexit2label)) then }
  396. begin
  397. p := tai_regalloc.deAlloc(reg,nil);
  398. insertLLItem(AsmL, hp1.previous, hp1, p);
  399. end;
  400. end;
  401. {************************ Search the Label table ************************}
  402. function findlabel(l: tasmlabel; var hp: tai): boolean;
  403. {searches for the specified label starting from hp as long as the
  404. encountered instructions are labels, to be able to optimize constructs like
  405. jne l2 jmp l2
  406. jmp l3 and l1:
  407. l1: l2:
  408. l2:}
  409. var
  410. p: tai;
  411. begin
  412. p := hp;
  413. while assigned(p) and
  414. (p.typ in SkipInstr + [ait_label,ait_align]) Do
  415. if (p.typ <> ait_Label) or
  416. (tai_label(p).l <> l) then
  417. GetNextInstruction(p, p)
  418. else
  419. begin
  420. hp := p;
  421. findlabel := true;
  422. exit
  423. end;
  424. findlabel := false;
  425. end;
  426. {************************ Some general functions ************************}
  427. function tch2reg(ch: tinschange): tsuperregister;
  428. {converts a TChange variable to a TRegister}
  429. const
  430. ch2reg: array[CH_REAX..CH_REDI] of tsuperregister = (RS_EAX,RS_ECX,RS_EDX,RS_EBX,RS_ESP,RS_EBP,RS_ESI,RS_EDI);
  431. begin
  432. if (ch <= CH_REDI) then
  433. tch2reg := ch2reg[ch]
  434. else if (ch <= CH_WEDI) then
  435. tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_REDI))]
  436. else if (ch <= CH_RWEDI) then
  437. tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_WEDI))]
  438. else if (ch <= CH_MEDI) then
  439. tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_RWEDI))]
  440. else
  441. InternalError($db)
  442. end;
  443. { inserts new_one between prev and foll }
  444. procedure InsertLLItem(AsmL: TAAsmOutput; prev, foll, new_one: TLinkedListItem);
  445. begin
  446. if assigned(prev) then
  447. if assigned(foll) then
  448. begin
  449. if assigned(new_one) then
  450. begin
  451. new_one.previous := prev;
  452. new_one.next := foll;
  453. prev.next := new_one;
  454. foll.previous := new_one;
  455. { shgould we update line information }
  456. if (not (tai(new_one).typ in SkipLineInfo)) and
  457. (not (tai(foll).typ in SkipLineInfo)) then
  458. tailineinfo(new_one).fileinfo := tailineinfo(foll).fileinfo;
  459. end;
  460. end
  461. else
  462. asml.Concat(new_one)
  463. else
  464. if assigned(foll) then
  465. asml.Insert(new_one)
  466. end;
  467. {********************* Compare parts of tai objects *********************}
  468. function regssamesize(reg1, reg2: tregister): boolean;
  469. {returns true if Reg1 and Reg2 are of the same size (so if they're both
  470. 8bit, 16bit or 32bit)}
  471. begin
  472. if (reg1 = NR_NO) or (reg2 = NR_NO) then
  473. internalerror(2003111602);
  474. regssamesize := getsubreg(reg1) = getsubreg(reg2);
  475. end;
  476. procedure AddReg2RegInfo(OldReg, NewReg: TRegister; var RegInfo: toptreginfo);
  477. {updates the ???RegsEncountered and ???2???reg fields of RegInfo. Assumes that
  478. OldReg and NewReg have the same size (has to be chcked in advance with
  479. RegsSameSize) and that neither equals RS_INVALID}
  480. var
  481. newsupreg, oldsupreg: tsuperregister;
  482. begin
  483. if (newreg = NR_NO) or (oldreg = NR_NO) then
  484. internalerror(2003111601);
  485. newsupreg := getsupreg(newreg);
  486. oldsupreg := getsupreg(oldreg);
  487. with RegInfo Do
  488. begin
  489. NewRegsEncountered := NewRegsEncountered + [newsupreg];
  490. OldRegsEncountered := OldRegsEncountered + [oldsupreg];
  491. New2OldReg[newsupreg] := oldsupreg;
  492. end;
  493. end;
  494. procedure AddOp2RegInfo(const o:toper; var reginfo: toptreginfo);
  495. begin
  496. case o.typ Of
  497. top_reg:
  498. if (o.reg <> NR_NO) then
  499. AddReg2RegInfo(o.reg, o.reg, RegInfo);
  500. top_ref:
  501. begin
  502. if o.ref^.base <> NR_NO then
  503. AddReg2RegInfo(o.ref^.base, o.ref^.base, RegInfo);
  504. if o.ref^.index <> NR_NO then
  505. AddReg2RegInfo(o.ref^.index, o.ref^.index, RegInfo);
  506. end;
  507. end;
  508. end;
  509. function RegsEquivalent(oldreg, newreg: tregister; var reginfo: toptreginfo; opact: topaction): Boolean;
  510. begin
  511. if not((oldreg = NR_NO) or (newreg = NR_NO)) then
  512. if RegsSameSize(oldreg, newreg) then
  513. with reginfo do
  514. {here we always check for the 32 bit component, because it is possible that
  515. the 8 bit component has not been set, event though NewReg already has been
  516. processed. This happens if it has been compared with a register that doesn't
  517. have an 8 bit component (such as EDI). in that case the 8 bit component is
  518. still set to RS_NO and the comparison in the else-part will fail}
  519. if (getsupreg(oldReg) in OldRegsEncountered) then
  520. if (getsupreg(NewReg) in NewRegsEncountered) then
  521. RegsEquivalent := (getsupreg(oldreg) = New2OldReg[getsupreg(newreg)])
  522. { if we haven't encountered the new register yet, but we have encountered the
  523. old one already, the new one can only be correct if it's being written to
  524. (and consequently the old one is also being written to), otherwise
  525. movl -8(%ebp), %eax and movl -8(%ebp), %eax
  526. movl (%eax), %eax movl (%edx), %edx
  527. are considered equivalent}
  528. else
  529. if (opact = opact_write) then
  530. begin
  531. AddReg2RegInfo(oldreg, newreg, reginfo);
  532. RegsEquivalent := true
  533. end
  534. else
  535. Regsequivalent := false
  536. else
  537. if not(getsupreg(newreg) in NewRegsEncountered) and
  538. ((opact = opact_write) or
  539. (newreg = oldreg)) then
  540. begin
  541. AddReg2RegInfo(oldreg, newreg, reginfo);
  542. RegsEquivalent := true
  543. end
  544. else
  545. RegsEquivalent := false
  546. else
  547. RegsEquivalent := false
  548. else
  549. RegsEquivalent := oldreg = newreg
  550. end;
  551. function RefsEquivalent(const r1, r2: treference; var regInfo: toptreginfo; opact: topaction): boolean;
  552. begin
  553. RefsEquivalent :=
  554. (r1.offset = r2.offset) and
  555. RegsEquivalent(r1.base, r2.base, reginfo, opact) and
  556. RegsEquivalent(r1.index, r2.index, reginfo, opact) and
  557. (r1.segment = r2.segment) and (r1.scalefactor = r2.scalefactor) and
  558. (r1.symbol = r2.symbol) and (r1.refaddr = r2.refaddr) and
  559. (r1.relsymbol = r2.relsymbol);
  560. end;
  561. function refsequal(const r1, r2: treference): boolean;
  562. begin
  563. refsequal :=
  564. (r1.offset = r2.offset) and
  565. (r1.segment = r2.segment) and (r1.base = r2.base) and
  566. (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
  567. (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
  568. (r1.relsymbol = r2.relsymbol);
  569. end;
  570. function isgp32reg(supreg: tsuperregister): boolean;
  571. {Checks if the register is a 32 bit general purpose register}
  572. begin
  573. isgp32reg := false;
  574. if (supreg >= RS_EAX) and (supreg <= RS_EBX) then
  575. isgp32reg := true
  576. end;
  577. function reginref(supreg: tsuperregister; const ref: treference): boolean;
  578. begin {checks whether ref contains a reference to reg}
  579. reginref :=
  580. ((ref.base <> NR_NO) and
  581. (getsupreg(ref.base) = supreg)) or
  582. ((ref.index <> NR_NO) and
  583. (getsupreg(ref.index) = supreg))
  584. end;
  585. function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
  586. var
  587. p: taicpu;
  588. opcount: longint;
  589. begin
  590. RegReadByInstruction := false;
  591. if hp.typ <> ait_instruction then
  592. exit;
  593. p := taicpu(hp);
  594. case p.opcode of
  595. A_IMUL:
  596. case p.ops of
  597. 1:
  598. regReadByInstruction :=
  599. (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
  600. 2,3:
  601. regReadByInstruction :=
  602. reginop(supreg,p.oper[0]^) or
  603. reginop(supreg,p.oper[1]^);
  604. end;
  605. A_IDIV,A_DIV,A_MUL:
  606. begin
  607. regReadByInstruction :=
  608. reginop(supreg,p.oper[0]^) or (supreg in [RS_EAX,RS_EDX]);
  609. end;
  610. else
  611. begin
  612. for opcount := 0 to p.ops-1 do
  613. if (p.oper[opCount]^.typ = top_ref) and
  614. reginref(supreg,p.oper[opcount]^.ref^) then
  615. begin
  616. RegReadByInstruction := true;
  617. exit
  618. end;
  619. for opcount := 1 to maxinschanges do
  620. case insprop[p.opcode].ch[opcount] of
  621. CH_REAX..CH_REDI,CH_RWEAX..CH_MEDI:
  622. if supreg = tch2reg(insprop[p.opcode].ch[opcount]) then
  623. begin
  624. RegReadByInstruction := true;
  625. exit
  626. end;
  627. CH_RWOP1,CH_ROP1,CH_MOP1:
  628. if //(p.oper[0]^.typ = top_reg) and
  629. reginop(supreg,p.oper[0]^) then
  630. begin
  631. RegReadByInstruction := true;
  632. exit
  633. end;
  634. Ch_RWOP2,Ch_ROP2,Ch_MOP2:
  635. if //(p.oper[1]^.typ = top_reg) and
  636. reginop(supreg,p.oper[1]^) then
  637. begin
  638. RegReadByInstruction := true;
  639. exit
  640. end;
  641. Ch_RWOP3,Ch_ROP3,Ch_MOP3:
  642. if //(p.oper[2]^.typ = top_reg) and
  643. reginop(supreg,p.oper[2]^) then
  644. begin
  645. RegReadByInstruction := true;
  646. exit
  647. end;
  648. end;
  649. end;
  650. end;
  651. end;
  652. function regInInstruction(supreg: tsuperregister; p1: tai): boolean;
  653. { Checks if reg is used by the instruction p1 }
  654. { Difference with "regReadBysinstruction() or regModifiedByInstruction()": }
  655. { this one ignores CH_ALL opcodes, while regModifiedByInstruction doesn't }
  656. var
  657. p: taicpu;
  658. opcount: Word;
  659. begin
  660. regInInstruction := false;
  661. if p1.typ <> ait_instruction then
  662. exit;
  663. p := taicpu(p1);
  664. case p.opcode of
  665. A_IMUL:
  666. case p.ops of
  667. 1:
  668. regInInstruction :=
  669. (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
  670. 2,3:
  671. regInInstruction :=
  672. reginop(supreg,p.oper[0]^) or
  673. reginop(supreg,p.oper[1]^) or
  674. (assigned(p.oper[2]) and
  675. reginop(supreg,p.oper[2]^));
  676. end;
  677. A_IDIV,A_DIV,A_MUL:
  678. regInInstruction :=
  679. reginop(supreg,p.oper[0]^) or
  680. (supreg in [RS_EAX,RS_EDX])
  681. else
  682. begin
  683. for opcount := 1 to maxinschanges do
  684. case insprop[p.opcode].Ch[opCount] of
  685. CH_REAX..CH_MEDI:
  686. if tch2reg(InsProp[p.opcode].Ch[opCount]) = supreg then
  687. begin
  688. regInInstruction := true;
  689. exit;
  690. end;
  691. CH_ROp1..CH_MOp1:
  692. if reginop(supreg,p.oper[0]^) then
  693. begin
  694. regInInstruction := true;
  695. exit
  696. end;
  697. Ch_ROp2..Ch_MOp2:
  698. if reginop(supreg,p.oper[1]^) then
  699. begin
  700. regInInstruction := true;
  701. exit
  702. end;
  703. Ch_ROp3..Ch_MOp3:
  704. if reginop(supreg,p.oper[2]^) then
  705. begin
  706. regInInstruction := true;
  707. exit
  708. end;
  709. end;
  710. end;
  711. end;
  712. end;
  713. function reginop(supreg: tsuperregister; const o:toper): boolean;
  714. begin
  715. reginop := false;
  716. case o.typ Of
  717. top_reg:
  718. reginop :=
  719. (getregtype(o.reg) = R_INTREGISTER) and
  720. (supreg = getsupreg(o.reg));
  721. top_ref:
  722. reginop :=
  723. ((o.ref^.base <> NR_NO) and
  724. (supreg = getsupreg(o.ref^.base))) or
  725. ((o.ref^.index <> NR_NO) and
  726. (supreg = getsupreg(o.ref^.index)));
  727. end;
  728. end;
  729. function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
  730. var
  731. InstrProp: TInsProp;
  732. TmpResult: Boolean;
  733. Cnt: Word;
  734. begin
  735. TmpResult := False;
  736. if supreg = RS_INVALID then
  737. exit;
  738. if (p1.typ = ait_instruction) then
  739. case taicpu(p1).opcode of
  740. A_IMUL:
  741. With taicpu(p1) Do
  742. TmpResult :=
  743. ((ops = 1) and (supreg in [RS_EAX,RS_EDX])) or
  744. ((ops = 2) and (getsupreg(oper[1]^.reg) = supreg)) or
  745. ((ops = 3) and (getsupreg(oper[2]^.reg) = supreg));
  746. A_DIV, A_IDIV, A_MUL:
  747. With taicpu(p1) Do
  748. TmpResult :=
  749. (supreg in [RS_EAX,RS_EDX]);
  750. else
  751. begin
  752. Cnt := 1;
  753. InstrProp := InsProp[taicpu(p1).OpCode];
  754. while (Cnt <= maxinschanges) and
  755. (InstrProp.Ch[Cnt] <> Ch_None) and
  756. not(TmpResult) Do
  757. begin
  758. case InstrProp.Ch[Cnt] Of
  759. Ch_WEAX..Ch_MEDI:
  760. TmpResult := supreg = tch2reg(InstrProp.Ch[Cnt]);
  761. Ch_RWOp1,Ch_WOp1,Ch_Mop1:
  762. TmpResult := (taicpu(p1).oper[0]^.typ = top_reg) and
  763. reginop(supreg,taicpu(p1).oper[0]^);
  764. Ch_RWOp2,Ch_WOp2,Ch_Mop2:
  765. TmpResult := (taicpu(p1).oper[1]^.typ = top_reg) and
  766. reginop(supreg,taicpu(p1).oper[1]^);
  767. Ch_RWOp3,Ch_WOp3,Ch_Mop3:
  768. TmpResult := (taicpu(p1).oper[2]^.typ = top_reg) and
  769. reginop(supreg,taicpu(p1).oper[2]^);
  770. Ch_FPU: TmpResult := false; // supreg is supposed to be an intreg!! supreg in [RS_ST..RS_ST7,RS_MM0..RS_MM7];
  771. Ch_ALL: TmpResult := true;
  772. end;
  773. inc(Cnt)
  774. end
  775. end
  776. end;
  777. RegModifiedByInstruction := TmpResult
  778. end;
  779. function instrWritesFlags(p: tai): boolean;
  780. var
  781. l: longint;
  782. begin
  783. instrWritesFlags := true;
  784. case p.typ of
  785. ait_instruction:
  786. begin
  787. for l := 1 to maxinschanges do
  788. if InsProp[taicpu(p).opcode].Ch[l] in [Ch_WFlags,Ch_RWFlags,Ch_All] then
  789. exit;
  790. end;
  791. ait_label:
  792. exit;
  793. end;
  794. instrWritesFlags := false;
  795. end;
  796. function instrReadsFlags(p: tai): boolean;
  797. var
  798. l: longint;
  799. begin
  800. instrReadsFlags := true;
  801. case p.typ of
  802. ait_instruction:
  803. begin
  804. for l := 1 to maxinschanges do
  805. if InsProp[taicpu(p).opcode].Ch[l] in [Ch_RFlags,Ch_RWFlags,Ch_All] then
  806. exit;
  807. end;
  808. ait_label:
  809. exit;
  810. end;
  811. instrReadsFlags := false;
  812. end;
  813. {********************* GetNext and GetLastInstruction *********************}
  814. function GetNextInstruction(Current: tai; var Next: tai): Boolean;
  815. { skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
  816. { next tai object in Next. Returns false if there isn't any }
  817. begin
  818. repeat
  819. if (Current.typ = ait_marker) and
  820. (tai_Marker(current).Kind = AsmBlockStart) then
  821. begin
  822. GetNextInstruction := False;
  823. Next := Nil;
  824. Exit
  825. end;
  826. Current := tai(current.Next);
  827. while assigned(Current) and
  828. ((current.typ in skipInstr) or
  829. ((current.typ = ait_label) and
  830. labelCanBeSkipped(tai_label(current)))) do
  831. Current := tai(current.Next);
  832. { if assigned(Current) and
  833. (current.typ = ait_Marker) and
  834. (tai_Marker(current).Kind = NoPropInfoStart) then
  835. begin
  836. while assigned(Current) and
  837. ((current.typ <> ait_Marker) or
  838. (tai_Marker(current).Kind <> NoPropInfoend)) Do
  839. Current := tai(current.Next);
  840. end;}
  841. until not(assigned(Current)) or
  842. (current.typ <> ait_Marker) or
  843. not(tai_Marker(current).Kind in [NoPropInfoStart,NoPropInfoend]);
  844. Next := Current;
  845. if assigned(Current) and
  846. not((current.typ in SkipInstr) or
  847. ((current.typ = ait_label) and
  848. labelCanBeSkipped(tai_label(current))))
  849. then
  850. GetNextInstruction :=
  851. not((current.typ = ait_marker) and
  852. (tai_marker(current).kind = asmBlockStart))
  853. else
  854. begin
  855. GetNextInstruction := False;
  856. Next := nil;
  857. end;
  858. end;
  859. function GetLastInstruction(Current: tai; var Last: tai): boolean;
  860. {skips the ait-types in SkipInstr puts the previous tai object in
  861. Last. Returns false if there isn't any}
  862. begin
  863. repeat
  864. Current := tai(current.previous);
  865. while assigned(Current) and
  866. (((current.typ = ait_Marker) and
  867. not(tai_Marker(current).Kind in [AsmBlockend{,NoPropInfoend}])) or
  868. (current.typ in SkipInstr) or
  869. ((current.typ = ait_label) and
  870. labelCanBeSkipped(tai_label(current)))) Do
  871. Current := tai(current.previous);
  872. { if assigned(Current) and
  873. (current.typ = ait_Marker) and
  874. (tai_Marker(current).Kind = NoPropInfoend) then
  875. begin
  876. while assigned(Current) and
  877. ((current.typ <> ait_Marker) or
  878. (tai_Marker(current).Kind <> NoPropInfoStart)) Do
  879. Current := tai(current.previous);
  880. end;}
  881. until not(assigned(Current)) or
  882. (current.typ <> ait_Marker) or
  883. not(tai_Marker(current).Kind in [NoPropInfoStart,NoPropInfoend]);
  884. if not(assigned(Current)) or
  885. (current.typ in SkipInstr) or
  886. ((current.typ = ait_label) and
  887. labelCanBeSkipped(tai_label(current))) or
  888. ((current.typ = ait_Marker) and
  889. (tai_Marker(current).Kind = AsmBlockend))
  890. then
  891. begin
  892. Last := nil;
  893. GetLastInstruction := False
  894. end
  895. else
  896. begin
  897. Last := Current;
  898. GetLastInstruction := True;
  899. end;
  900. end;
  901. procedure SkipHead(var p: tai);
  902. var
  903. oldp: tai;
  904. begin
  905. repeat
  906. oldp := p;
  907. if (p.typ in SkipInstr) or
  908. ((p.typ = ait_marker) and
  909. (tai_Marker(p).Kind in [AsmBlockend,inlinestart,inlineend])) then
  910. GetNextInstruction(p,p)
  911. else if ((p.Typ = Ait_Marker) and
  912. (tai_Marker(p).Kind = nopropinfostart)) then
  913. {a marker of the NoPropInfoStart can't be the first instruction of a
  914. TAAsmoutput list}
  915. GetNextInstruction(tai(p.previous),p);
  916. until p = oldp
  917. end;
  918. function labelCanBeSkipped(p: tai_label): boolean;
  919. begin
  920. labelCanBeSkipped := not(p.l.is_used) or p.l.is_addr;
  921. end;
  922. {******************* The Data Flow Analyzer functions ********************}
  923. function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
  924. hp: tai): boolean;
  925. { assumes reg is a 32bit register }
  926. var
  927. p: taicpu;
  928. begin
  929. if not assigned(hp) or
  930. (hp.typ <> ait_instruction) then
  931. begin
  932. regLoadedWithNewValue := false;
  933. exit;
  934. end;
  935. p := taicpu(hp);
  936. regLoadedWithNewValue :=
  937. (((p.opcode = A_MOV) or
  938. (p.opcode = A_MOVZX) or
  939. (p.opcode = A_MOVSX) or
  940. (p.opcode = A_LEA)) and
  941. (p.oper[1]^.typ = top_reg) and
  942. (getsupreg(p.oper[1]^.reg) = supreg) and
  943. (canDependOnPrevValue or
  944. (p.oper[0]^.typ <> top_ref) or
  945. not regInRef(supreg,p.oper[0]^.ref^)) or
  946. ((p.opcode = A_POP) and
  947. (getsupreg(p.oper[0]^.reg) = supreg)));
  948. end;
  949. procedure UpdateUsedRegs(var UsedRegs: TRegSet; p: tai);
  950. {updates UsedRegs with the RegAlloc Information coming after p}
  951. begin
  952. repeat
  953. while assigned(p) and
  954. ((p.typ in (SkipInstr - [ait_RegAlloc])) or
  955. ((p.typ = ait_label) and
  956. labelCanBeSkipped(tai_label(p)))) Do
  957. p := tai(p.next);
  958. while assigned(p) and
  959. (p.typ=ait_RegAlloc) Do
  960. begin
  961. if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
  962. begin
  963. case tai_regalloc(p).ratype of
  964. ra_alloc :
  965. UsedRegs := UsedRegs + [getsupreg(tai_regalloc(p).reg)];
  966. ra_dealloc :
  967. UsedRegs := UsedRegs - [getsupreg(tai_regalloc(p).reg)];
  968. end;
  969. end;
  970. p := tai(p.next);
  971. end;
  972. until not(assigned(p)) or
  973. (not(p.typ in SkipInstr) and
  974. not((p.typ = ait_label) and
  975. labelCanBeSkipped(tai_label(p))));
  976. end;
  977. procedure AllocRegBetween(asml: taasmoutput; reg: tregister; p1, p2: tai);
  978. { allocates register reg between (and including) instructions p1 and p2 }
  979. { the type of p1 and p2 must not be in SkipInstr }
  980. var
  981. hp, start: tai;
  982. lastRemovedWasDealloc, firstRemovedWasAlloc, first: boolean;
  983. supreg: tsuperregister;
  984. begin
  985. supreg := getsupreg(reg);
  986. { if not(supreg in rg.usableregsint+[RS_EDI,RS_ESI]) or
  987. not(assigned(p1)) then}
  988. if not(supreg in [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_EDI,RS_ESI]) or
  989. not(assigned(p1)) then
  990. { this happens with registers which are loaded implicitely, outside the }
  991. { current block (e.g. esi with self) }
  992. exit;
  993. { make sure we allocate it for this instruction }
  994. if p1 = p2 then
  995. getnextinstruction(p2,p2);
  996. lastRemovedWasDealloc := false;
  997. firstRemovedWasAlloc := false;
  998. first := true;
  999. {$ifdef allocregdebug}
  1000. hp := tai_comment.Create(strpnew('allocating '+std_reg2str[supreg]+
  1001. ' from here...')));
  1002. insertllitem(asml,p1.previous,p1,hp);
  1003. hp := tai_comment.Create(strpnew('allocated '+std_reg2str[supreg]+
  1004. ' till here...')));
  1005. insertllitem(asml,p2,p1.next,hp);
  1006. {$endif allocregdebug}
  1007. start := p1;
  1008. repeat
  1009. if assigned(p1.OptInfo) then
  1010. include(ptaiprop(p1.OptInfo)^.UsedRegs,supreg);
  1011. p1 := tai(p1.next);
  1012. repeat
  1013. while assigned(p1) and
  1014. (p1.typ in (SkipInstr-[ait_regalloc])) Do
  1015. p1 := tai(p1.next);
  1016. { remove all allocation/deallocation info about the register in between }
  1017. if assigned(p1) and
  1018. (p1.typ = ait_regalloc) then
  1019. if (getsupreg(tai_regalloc(p1).reg) = supreg) then
  1020. begin
  1021. if first then
  1022. begin
  1023. firstRemovedWasAlloc := (tai_regalloc(p1).ratype=ra_alloc);
  1024. first := false;
  1025. end;
  1026. lastRemovedWasDealloc := (tai_regalloc(p1).ratype=ra_dealloc);
  1027. hp := tai(p1.Next);
  1028. asml.Remove(p1);
  1029. p1.free;
  1030. p1 := hp;
  1031. end
  1032. else p1 := tai(p1.next);
  1033. until not(assigned(p1)) or
  1034. not(p1.typ in SkipInstr);
  1035. until not(assigned(p1)) or
  1036. (p1 = p2);
  1037. if assigned(p1) then
  1038. begin
  1039. if assigned(p1.optinfo) then
  1040. include(ptaiprop(p1.OptInfo)^.UsedRegs,supreg);
  1041. if lastRemovedWasDealloc then
  1042. begin
  1043. hp := tai_regalloc.DeAlloc(reg,nil);
  1044. insertLLItem(asmL,p1,p1.next,hp);
  1045. end;
  1046. end;
  1047. if firstRemovedWasAlloc then
  1048. begin
  1049. hp := tai_regalloc.Alloc(reg,nil);
  1050. insertLLItem(asmL,start.previous,start,hp);
  1051. end;
  1052. end;
  1053. function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
  1054. var
  1055. hp: tai;
  1056. first: boolean;
  1057. begin
  1058. findregdealloc := false;
  1059. first := true;
  1060. while assigned(p.previous) and
  1061. ((tai(p.previous).typ in (skipinstr+[ait_align])) or
  1062. ((tai(p.previous).typ = ait_label) and
  1063. labelCanBeSkipped(tai_label(p.previous)))) do
  1064. begin
  1065. p := tai(p.previous);
  1066. if (p.typ = ait_regalloc) and
  1067. (getsupreg(tai_regalloc(p).reg) = supreg) then
  1068. if (tai_regalloc(p).ratype=ra_dealloc) then
  1069. if first then
  1070. begin
  1071. findregdealloc := true;
  1072. break;
  1073. end
  1074. else
  1075. begin
  1076. findRegDealloc :=
  1077. getNextInstruction(p,hp) and
  1078. regLoadedWithNewValue(supreg,false,hp);
  1079. break
  1080. end
  1081. else
  1082. first := false;
  1083. end
  1084. end;
  1085. procedure incState(var S: Byte; amount: longint);
  1086. {increases S by 1, wraps around at $ffff to 0 (so we won't get overflow
  1087. errors}
  1088. begin
  1089. if (s <= $ff - amount) then
  1090. inc(s, amount)
  1091. else s := longint(s) + amount - $ff;
  1092. end;
  1093. function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
  1094. { Content is the sequence of instructions that describes the contents of }
  1095. { seqReg. reg is being overwritten by the current instruction. if the }
  1096. { content of seqReg depends on reg (ie. because of a }
  1097. { "movl (seqreg,reg), seqReg" instruction), this function returns true }
  1098. var
  1099. p: tai;
  1100. Counter: Word;
  1101. TmpResult: Boolean;
  1102. RegsChecked: TRegSet;
  1103. begin
  1104. RegsChecked := [];
  1105. p := Content.StartMod;
  1106. TmpResult := False;
  1107. Counter := 1;
  1108. while not(TmpResult) and
  1109. (Counter <= Content.NrOfMods) Do
  1110. begin
  1111. if (p.typ = ait_instruction) and
  1112. ((taicpu(p).opcode = A_MOV) or
  1113. (taicpu(p).opcode = A_MOVZX) or
  1114. (taicpu(p).opcode = A_MOVSX) or
  1115. (taicpu(p).opcode = A_LEA)) and
  1116. (taicpu(p).oper[0]^.typ = top_ref) then
  1117. With taicpu(p).oper[0]^.ref^ Do
  1118. if ((base = current_procinfo.FramePointer) or
  1119. (assigned(symbol) and (base = NR_NO))) and
  1120. (index = NR_NO) then
  1121. begin
  1122. RegsChecked := RegsChecked + [getsupreg(taicpu(p).oper[1]^.reg)];
  1123. if supreg = getsupreg(taicpu(p).oper[1]^.reg) then
  1124. break;
  1125. end
  1126. else
  1127. tmpResult :=
  1128. regReadByInstruction(supreg,p) and
  1129. regModifiedByInstruction(seqReg,p)
  1130. else
  1131. tmpResult :=
  1132. regReadByInstruction(supreg,p) and
  1133. regModifiedByInstruction(seqReg,p);
  1134. inc(Counter);
  1135. GetNextInstruction(p,p)
  1136. end;
  1137. sequenceDependsonReg := TmpResult
  1138. end;
  1139. procedure invalidateDependingRegs(p1: ptaiprop; supreg: tsuperregister);
  1140. var
  1141. counter: tsuperregister;
  1142. begin
  1143. for counter := RS_EAX to RS_EDI do
  1144. if counter <> supreg then
  1145. with p1^.regs[counter] Do
  1146. begin
  1147. if (typ in [con_ref,con_noRemoveRef]) and
  1148. sequenceDependsOnReg(p1^.Regs[counter],counter,supreg) then
  1149. if typ in [con_ref, con_invalid] then
  1150. typ := con_invalid
  1151. { con_noRemoveRef = con_unknown }
  1152. else
  1153. typ := con_unknown;
  1154. if assigned(memwrite) and
  1155. regInRef(counter,memwrite.oper[1]^.ref^) then
  1156. memwrite := nil;
  1157. end;
  1158. end;
  1159. procedure DestroyReg(p1: ptaiprop; supreg: tsuperregister; doincState:Boolean);
  1160. {Destroys the contents of the register reg in the ptaiprop p1, as well as the
  1161. contents of registers are loaded with a memory location based on reg.
  1162. doincState is false when this register has to be destroyed not because
  1163. it's contents are directly modified/overwritten, but because of an indirect
  1164. action (e.g. this register holds the contents of a variable and the value
  1165. of the variable in memory is changed) }
  1166. begin
  1167. { the following happens for fpu registers }
  1168. if (supreg < low(NrOfInstrSinceLastMod)) or
  1169. (supreg > high(NrOfInstrSinceLastMod)) then
  1170. exit;
  1171. NrOfInstrSinceLastMod[supreg] := 0;
  1172. with p1^.regs[supreg] do
  1173. begin
  1174. if doincState then
  1175. begin
  1176. incState(wstate,1);
  1177. typ := con_unknown;
  1178. startmod := nil;
  1179. end
  1180. else
  1181. if typ in [con_ref,con_const,con_invalid] then
  1182. typ := con_invalid
  1183. { con_noRemoveRef = con_unknown }
  1184. else
  1185. typ := con_unknown;
  1186. memwrite := nil;
  1187. end;
  1188. invalidateDependingRegs(p1,supreg);
  1189. end;
  1190. {procedure AddRegsToSet(p: tai; var RegSet: TRegSet);
  1191. begin
  1192. if (p.typ = ait_instruction) then
  1193. begin
  1194. case taicpu(p).oper[0]^.typ Of
  1195. top_reg:
  1196. if not(taicpu(p).oper[0]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
  1197. RegSet := RegSet + [taicpu(p).oper[0]^.reg];
  1198. top_ref:
  1199. With TReference(taicpu(p).oper[0]^) Do
  1200. begin
  1201. if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
  1202. then RegSet := RegSet + [base];
  1203. if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
  1204. then RegSet := RegSet + [index];
  1205. end;
  1206. end;
  1207. case taicpu(p).oper[1]^.typ Of
  1208. top_reg:
  1209. if not(taicpu(p).oper[1]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
  1210. if RegSet := RegSet + [TRegister(TwoWords(taicpu(p).oper[1]^).Word1];
  1211. top_ref:
  1212. With TReference(taicpu(p).oper[1]^) Do
  1213. begin
  1214. if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
  1215. then RegSet := RegSet + [base];
  1216. if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
  1217. then RegSet := RegSet + [index];
  1218. end;
  1219. end;
  1220. end;
  1221. end;}
  1222. function OpsEquivalent(const o1, o2: toper; var RegInfo: toptreginfo; OpAct: TopAction): Boolean;
  1223. begin {checks whether the two ops are equivalent}
  1224. OpsEquivalent := False;
  1225. if o1.typ=o2.typ then
  1226. case o1.typ Of
  1227. top_reg:
  1228. OpsEquivalent :=RegsEquivalent(o1.reg,o2.reg, RegInfo, OpAct);
  1229. top_ref:
  1230. OpsEquivalent := RefsEquivalent(o1.ref^, o2.ref^, RegInfo, OpAct);
  1231. Top_Const:
  1232. OpsEquivalent := o1.val = o2.val;
  1233. Top_None:
  1234. OpsEquivalent := True
  1235. end;
  1236. end;
  1237. function OpsEqual(const o1,o2:toper): Boolean;
  1238. begin {checks whether the two ops are equal}
  1239. OpsEqual := False;
  1240. if o1.typ=o2.typ then
  1241. case o1.typ Of
  1242. top_reg :
  1243. OpsEqual:=o1.reg=o2.reg;
  1244. top_ref :
  1245. OpsEqual := RefsEqual(o1.ref^, o2.ref^);
  1246. Top_Const :
  1247. OpsEqual:=o1.val=o2.val;
  1248. Top_None :
  1249. OpsEqual := True
  1250. end;
  1251. end;
  1252. function sizescompatible(loadsize,newsize: topsize): boolean;
  1253. begin
  1254. case loadsize of
  1255. S_B,S_BW,S_BL:
  1256. sizescompatible := (newsize = loadsize) or (newsize = S_B);
  1257. S_W,S_WL:
  1258. sizescompatible := (newsize = loadsize) or (newsize = S_W);
  1259. else
  1260. sizescompatible := newsize = S_L;
  1261. end;
  1262. end;
  1263. function opscompatible(p1,p2: taicpu): boolean;
  1264. begin
  1265. case p1.opcode of
  1266. A_MOVZX,A_MOVSX:
  1267. opscompatible :=
  1268. ((p2.opcode = p1.opcode) or (p2.opcode = A_MOV)) and
  1269. sizescompatible(p1.opsize,p2.opsize);
  1270. else
  1271. opscompatible :=
  1272. (p1.opcode = p2.opcode) and
  1273. (p1.ops = p2.ops) and
  1274. (p1.opsize = p2.opsize);
  1275. end;
  1276. end;
  1277. function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
  1278. {$ifdef csdebug}
  1279. var
  1280. hp: tai;
  1281. {$endif csdebug}
  1282. begin {checks whether two taicpu instructions are equal}
  1283. if assigned(p1) and assigned(p2) and
  1284. (tai(p1).typ = ait_instruction) and
  1285. (tai(p2).typ = ait_instruction) and
  1286. opscompatible(taicpu(p1),taicpu(p2)) and
  1287. (not(assigned(taicpu(p1).oper[0])) or
  1288. (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ)) and
  1289. (not(assigned(taicpu(p1).oper[1])) or
  1290. (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ)) and
  1291. (not(assigned(taicpu(p1).oper[2])) or
  1292. (taicpu(p1).oper[2]^.typ = taicpu(p2).oper[2]^.typ)) then
  1293. {both instructions have the same structure:
  1294. "<operator> <operand of type1>, <operand of type 2>"}
  1295. if ((taicpu(p1).opcode = A_MOV) or
  1296. (taicpu(p1).opcode = A_MOVZX) or
  1297. (taicpu(p1).opcode = A_MOVSX) or
  1298. (taicpu(p1).opcode = A_LEA)) and
  1299. (taicpu(p1).oper[0]^.typ = top_ref) {then .oper[1]^t = top_reg} then
  1300. if not(RegInRef(getsupreg(taicpu(p1).oper[1]^.reg), taicpu(p1).oper[0]^.ref^)) then
  1301. {the "old" instruction is a load of a register with a new value, not with
  1302. a value based on the contents of this register (so no "mov (reg), reg")}
  1303. if not(RegInRef(getsupreg(taicpu(p2).oper[1]^.reg), taicpu(p2).oper[0]^.ref^)) and
  1304. RefsEqual(taicpu(p1).oper[0]^.ref^, taicpu(p2).oper[0]^.ref^) then
  1305. {the "new" instruction is also a load of a register with a new value, and
  1306. this value is fetched from the same memory location}
  1307. begin
  1308. With taicpu(p2).oper[0]^.ref^ Do
  1309. begin
  1310. if (base <> NR_NO) and
  1311. (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
  1312. include(RegInfo.RegsLoadedForRef, getsupreg(base));
  1313. if (index <> NR_NO) and
  1314. (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
  1315. include(RegInfo.RegsLoadedForRef, getsupreg(index));
  1316. end;
  1317. {add the registers from the reference (.oper[0]^) to the RegInfo, all registers
  1318. from the reference are the same in the old and in the new instruction
  1319. sequence}
  1320. AddOp2RegInfo(taicpu(p1).oper[0]^, RegInfo);
  1321. {the registers from .oper[1]^ have to be equivalent, but not necessarily equal}
  1322. InstructionsEquivalent :=
  1323. RegsEquivalent(taicpu(p1).oper[1]^.reg,
  1324. taicpu(p2).oper[1]^.reg, RegInfo, OpAct_Write);
  1325. end
  1326. {the registers are loaded with values from different memory locations. if
  1327. this was allowed, the instructions "mov -4(esi),eax" and "mov -4(ebp),eax"
  1328. would be considered equivalent}
  1329. else
  1330. InstructionsEquivalent := False
  1331. else
  1332. {load register with a value based on the current value of this register}
  1333. begin
  1334. With taicpu(p2).oper[0]^.ref^ Do
  1335. begin
  1336. if (base <> NR_NO) and
  1337. (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer),
  1338. getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
  1339. {it won't do any harm if the register is already in RegsLoadedForRef}
  1340. begin
  1341. include(RegInfo.RegsLoadedForRef, getsupreg(base));
  1342. {$ifdef csdebug}
  1343. Writeln(std_regname(base), ' added');
  1344. {$endif csdebug}
  1345. end;
  1346. if (index <> NR_NO) and
  1347. (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer),
  1348. getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
  1349. begin
  1350. include(RegInfo.RegsLoadedForRef, getsupreg(index));
  1351. {$ifdef csdebug}
  1352. Writeln(std_regname(index), ' added');
  1353. {$endif csdebug}
  1354. end;
  1355. end;
  1356. if (taicpu(p2).oper[1]^.reg <> NR_NO) and
  1357. (not(getsupreg(taicpu(p2).oper[1]^.reg) in [getsupreg(current_procinfo.FramePointer),RS_ESP])) then
  1358. begin
  1359. RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef -
  1360. [getsupreg(taicpu(p2).oper[1]^.reg)];
  1361. {$ifdef csdebug}
  1362. Writeln(std_regname(newreg(R_INTREGISTER,getsupreg(taicpu(p2).oper[1]^.reg),R_SUBWHOLE)), ' removed');
  1363. {$endif csdebug}
  1364. end;
  1365. InstructionsEquivalent :=
  1366. OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, RegInfo, OpAct_Read) and
  1367. OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, RegInfo, OpAct_Write)
  1368. end
  1369. else
  1370. {an instruction <> mov, movzx, movsx}
  1371. begin
  1372. {$ifdef csdebug}
  1373. hp := tai_comment.Create(strpnew('checking if equivalent'));
  1374. hp.previous := p2;
  1375. hp.next := p2.next;
  1376. p2.next.previous := hp;
  1377. p2.next := hp;
  1378. {$endif csdebug}
  1379. InstructionsEquivalent :=
  1380. (not(assigned(taicpu(p1).oper[0])) or
  1381. OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, RegInfo, OpAct_Unknown)) and
  1382. (not(assigned(taicpu(p1).oper[1])) or
  1383. OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, RegInfo, OpAct_Unknown)) and
  1384. (not(assigned(taicpu(p1).oper[2])) or
  1385. OpsEquivalent(taicpu(p1).oper[2]^, taicpu(p2).oper[2]^, RegInfo, OpAct_Unknown))
  1386. end
  1387. {the instructions haven't even got the same structure, so they're certainly
  1388. not equivalent}
  1389. else
  1390. begin
  1391. {$ifdef csdebug}
  1392. hp := tai_comment.Create(strpnew('different opcodes/format'));
  1393. hp.previous := p2;
  1394. hp.next := p2.next;
  1395. p2.next.previous := hp;
  1396. p2.next := hp;
  1397. {$endif csdebug}
  1398. InstructionsEquivalent := False;
  1399. end;
  1400. {$ifdef csdebug}
  1401. hp := tai_comment.Create(strpnew('instreq: '+tostr(byte(instructionsequivalent))));
  1402. hp.previous := p2;
  1403. hp.next := p2.next;
  1404. p2.next.previous := hp;
  1405. p2.next := hp;
  1406. {$endif csdebug}
  1407. end;
  1408. (*
  1409. function InstructionsEqual(p1, p2: tai): Boolean;
  1410. begin {checks whether two taicpu instructions are equal}
  1411. InstructionsEqual :=
  1412. assigned(p1) and assigned(p2) and
  1413. ((tai(p1).typ = ait_instruction) and
  1414. (tai(p1).typ = ait_instruction) and
  1415. (taicpu(p1).opcode = taicpu(p2).opcode) and
  1416. (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ) and
  1417. (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ) and
  1418. OpsEqual(taicpu(p1).oper[0]^.typ, taicpu(p1).oper[0]^, taicpu(p2).oper[0]^) and
  1419. OpsEqual(taicpu(p1).oper[1]^.typ, taicpu(p1).oper[1]^, taicpu(p2).oper[1]^))
  1420. end;
  1421. *)
  1422. procedure readreg(p: ptaiprop; supreg: tsuperregister);
  1423. begin
  1424. if supreg in [RS_EAX..RS_EDI] then
  1425. incState(p^.regs[supreg].rstate,1)
  1426. end;
  1427. procedure readref(p: ptaiprop; const ref: preference);
  1428. begin
  1429. if ref^.base <> NR_NO then
  1430. readreg(p, getsupreg(ref^.base));
  1431. if ref^.index <> NR_NO then
  1432. readreg(p, getsupreg(ref^.index));
  1433. end;
  1434. procedure ReadOp(p: ptaiprop;const o:toper);
  1435. begin
  1436. case o.typ Of
  1437. top_reg: readreg(p, getsupreg(o.reg));
  1438. top_ref: readref(p, o.ref);
  1439. end;
  1440. end;
  1441. function RefInInstruction(const ref: TReference; p: tai;
  1442. RefsEq: TRefCompare): Boolean;
  1443. {checks whehter ref is used in p}
  1444. var TmpResult: Boolean;
  1445. begin
  1446. TmpResult := False;
  1447. if (p.typ = ait_instruction) then
  1448. begin
  1449. if (taicpu(p).ops >= 1) and
  1450. (taicpu(p).oper[0]^.typ = top_ref) then
  1451. TmpResult := RefsEq(ref, taicpu(p).oper[0]^.ref^);
  1452. if not(TmpResult) and
  1453. (taicpu(p).ops >= 2) and
  1454. (taicpu(p).oper[1]^.typ = top_ref) then
  1455. TmpResult := RefsEq(ref, taicpu(p).oper[1]^.ref^);
  1456. if not(TmpResult) and
  1457. (taicpu(p).ops >= 3) and
  1458. (taicpu(p).oper[2]^.typ = top_ref) then
  1459. TmpResult := RefsEq(ref, taicpu(p).oper[2]^.ref^);
  1460. end;
  1461. RefInInstruction := TmpResult;
  1462. end;
  1463. function RefInSequence(const ref: TReference; Content: TContent;
  1464. RefsEq: TRefCompare): Boolean;
  1465. {checks the whole sequence of Content (so StartMod and and the next NrOfMods
  1466. tai objects) to see whether ref is used somewhere}
  1467. var p: tai;
  1468. Counter: Word;
  1469. TmpResult: Boolean;
  1470. begin
  1471. p := Content.StartMod;
  1472. TmpResult := False;
  1473. Counter := 1;
  1474. while not(TmpResult) and
  1475. (Counter <= Content.NrOfMods) Do
  1476. begin
  1477. if (p.typ = ait_instruction) and
  1478. RefInInstruction(ref, p, RefsEq)
  1479. then TmpResult := True;
  1480. inc(Counter);
  1481. GetNextInstruction(p,p)
  1482. end;
  1483. RefInSequence := TmpResult
  1484. end;
  1485. function ArrayRefsEq(const r1, r2: TReference): Boolean;
  1486. begin
  1487. ArrayRefsEq := (R1.Offset = R2.Offset) and
  1488. (R1.Segment = R2.Segment) and
  1489. (R1.Symbol=R2.Symbol) and
  1490. (R1.base = R2.base)
  1491. end;
  1492. function isSimpleRef(const ref: treference): boolean;
  1493. { returns true if ref is reference to a local or global variable, to a }
  1494. { parameter or to an object field (this includes arrays). Returns false }
  1495. { otherwise. }
  1496. begin
  1497. isSimpleRef :=
  1498. assigned(ref.symbol) or
  1499. (ref.base = current_procinfo.framepointer);
  1500. end;
  1501. function containsPointerRef(p: tai): boolean;
  1502. { checks if an instruction contains a reference which is a pointer location }
  1503. var
  1504. hp: taicpu;
  1505. count: longint;
  1506. begin
  1507. containsPointerRef := false;
  1508. if p.typ <> ait_instruction then
  1509. exit;
  1510. hp := taicpu(p);
  1511. for count := 0 to hp.ops-1 do
  1512. begin
  1513. case hp.oper[count]^.typ of
  1514. top_ref:
  1515. if not isSimpleRef(hp.oper[count]^.ref^) then
  1516. begin
  1517. containsPointerRef := true;
  1518. exit;
  1519. end;
  1520. top_none:
  1521. exit;
  1522. end;
  1523. end;
  1524. end;
  1525. function containsPointerLoad(c: tcontent): boolean;
  1526. { checks whether the contents of a register contain a pointer reference }
  1527. var
  1528. p: tai;
  1529. count: longint;
  1530. begin
  1531. containsPointerLoad := false;
  1532. p := c.startmod;
  1533. for count := c.nrOfMods downto 1 do
  1534. begin
  1535. if containsPointerRef(p) then
  1536. begin
  1537. containsPointerLoad := true;
  1538. exit;
  1539. end;
  1540. getnextinstruction(p,p);
  1541. end;
  1542. end;
  1543. function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
  1544. supreg: tsuperregister; const c: tcontent; var invalsmemwrite: boolean): boolean;
  1545. { returns whether the contents c of reg are invalid after regWritten is }
  1546. { is written to ref }
  1547. var
  1548. refsEq: trefCompare;
  1549. begin
  1550. if isSimpleRef(ref) then
  1551. begin
  1552. if (ref.index <> NR_NO) or
  1553. (assigned(ref.symbol) and
  1554. (ref.base <> NR_NO)) then
  1555. { local/global variable or parameter which is an array }
  1556. refsEq := {$ifdef fpc}@{$endif}arrayRefsEq
  1557. else
  1558. { local/global variable or parameter which is not an array }
  1559. refsEq := {$ifdef fpc}@{$endif}refsEqual;
  1560. invalsmemwrite :=
  1561. assigned(c.memwrite) and
  1562. ((not(cs_uncertainOpts in aktglobalswitches) and
  1563. containsPointerRef(c.memwrite)) or
  1564. refsEq(c.memwrite.oper[1]^.ref^,ref));
  1565. if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
  1566. begin
  1567. writeToMemDestroysContents := false;
  1568. exit;
  1569. end;
  1570. { write something to a parameter, a local or global variable, so }
  1571. { * with uncertain optimizations on: }
  1572. { - destroy the contents of registers whose contents have somewhere a }
  1573. { "mov?? (ref), %reg". WhichReg (this is the register whose contents }
  1574. { are being written to memory) is not destroyed if it's StartMod is }
  1575. { of that form and NrOfMods = 1 (so if it holds ref, but is not a }
  1576. { expression based on ref) }
  1577. { * with uncertain optimizations off: }
  1578. { - also destroy registers that contain any pointer }
  1579. with c do
  1580. writeToMemDestroysContents :=
  1581. (typ in [con_ref,con_noRemoveRef]) and
  1582. ((not(cs_uncertainOpts in aktglobalswitches) and
  1583. containsPointerLoad(c)
  1584. ) or
  1585. (refInSequence(ref,c,refsEq) and
  1586. ((supreg <> regWritten) or
  1587. not((nrOfMods = 1) and
  1588. {StarMod is always of the type ait_instruction}
  1589. (taicpu(StartMod).oper[0]^.typ = top_ref) and
  1590. refsEq(taicpu(StartMod).oper[0]^.ref^, ref)
  1591. )
  1592. )
  1593. )
  1594. );
  1595. end
  1596. else
  1597. { write something to a pointer location, so }
  1598. { * with uncertain optimzations on: }
  1599. { - do not destroy registers which contain a local/global variable or }
  1600. { a parameter, except if DestroyRefs is called because of a "movsl" }
  1601. { * with uncertain optimzations off: }
  1602. { - destroy every register which contains a memory location }
  1603. begin
  1604. invalsmemwrite :=
  1605. assigned(c.memwrite) and
  1606. (not(cs_UncertainOpts in aktglobalswitches) or
  1607. containsPointerRef(c.memwrite));
  1608. if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
  1609. begin
  1610. writeToMemDestroysContents := false;
  1611. exit;
  1612. end;
  1613. with c do
  1614. writeToMemDestroysContents :=
  1615. (typ in [con_ref,con_noRemoveRef]) and
  1616. (not(cs_UncertainOpts in aktglobalswitches) or
  1617. { for movsl }
  1618. ((ref.base = NR_EDI) and (ref.index = NR_EDI)) or
  1619. { don't destroy if reg contains a parameter, local or global variable }
  1620. containsPointerLoad(c)
  1621. );
  1622. end;
  1623. end;
  1624. function writeToRegDestroysContents(destReg, supreg: tsuperregister;
  1625. const c: tcontent): boolean;
  1626. { returns whether the contents c of reg are invalid after destReg is }
  1627. { modified }
  1628. begin
  1629. writeToRegDestroysContents :=
  1630. (c.typ in [con_ref,con_noRemoveRef,con_invalid]) and
  1631. sequenceDependsOnReg(c,supreg,destReg);
  1632. end;
  1633. function writeDestroysContents(const op: toper; supreg: tsuperregister;
  1634. const c: tcontent; var memwritedestroyed: boolean): boolean;
  1635. { returns whether the contents c of reg are invalid after regWritten is }
  1636. { is written to op }
  1637. begin
  1638. memwritedestroyed := false;
  1639. case op.typ of
  1640. top_reg:
  1641. writeDestroysContents :=
  1642. writeToRegDestroysContents(getsupreg(op.reg),supreg,c);
  1643. top_ref:
  1644. writeDestroysContents :=
  1645. writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,c,memwritedestroyed);
  1646. else
  1647. writeDestroysContents := false;
  1648. end;
  1649. end;
  1650. procedure destroyRefs(p: tai; const ref: treference; regwritten: tsuperregister);
  1651. { destroys all registers which possibly contain a reference to ref, regWritten }
  1652. { is the register whose contents are being written to memory (if this proc }
  1653. { is called because of a "mov?? %reg, (mem)" instruction) }
  1654. var
  1655. counter: tsuperregister;
  1656. destroymemwrite: boolean;
  1657. begin
  1658. for counter := RS_EAX to RS_EDI Do
  1659. begin
  1660. if writeToMemDestroysContents(regwritten,ref,counter,
  1661. ptaiprop(p.optInfo)^.regs[counter],destroymemwrite) then
  1662. destroyReg(ptaiprop(p.optInfo), counter, false)
  1663. else if destroymemwrite then
  1664. ptaiprop(p.optinfo)^.regs[counter].MemWrite := nil;
  1665. end;
  1666. end;
  1667. procedure DestroyAllRegs(p: ptaiprop; read, written: boolean);
  1668. var Counter: tsuperregister;
  1669. begin {initializes/desrtoys all registers}
  1670. For Counter := RS_EAX To RS_EDI Do
  1671. begin
  1672. if read then
  1673. readreg(p, Counter);
  1674. DestroyReg(p, Counter, written);
  1675. p^.regs[counter].MemWrite := nil;
  1676. end;
  1677. p^.DirFlag := F_Unknown;
  1678. end;
  1679. procedure DestroyOp(taiObj: tai; const o:Toper);
  1680. {$ifdef statedebug}
  1681. var
  1682. hp: tai;
  1683. {$endif statedebug}
  1684. begin
  1685. case o.typ Of
  1686. top_reg:
  1687. begin
  1688. {$ifdef statedebug}
  1689. hp := tai_comment.Create(strpnew('destroying '+std_regname(o.reg)));
  1690. hp.next := taiobj.next;
  1691. hp.previous := taiobj;
  1692. taiobj.next := hp;
  1693. if assigned(hp.next) then
  1694. hp.next.previous := hp;
  1695. {$endif statedebug}
  1696. DestroyReg(ptaiprop(taiObj.OptInfo), getsupreg(o.reg), true);
  1697. end;
  1698. top_ref:
  1699. begin
  1700. readref(ptaiprop(taiObj.OptInfo), o.ref);
  1701. DestroyRefs(taiObj, o.ref^, RS_INVALID);
  1702. end;
  1703. end;
  1704. end;
  1705. procedure AddInstr2RegContents({$ifdef statedebug} asml: taasmoutput; {$endif}
  1706. p: taicpu; supreg: tsuperregister);
  1707. {$ifdef statedebug}
  1708. var
  1709. hp: tai;
  1710. {$endif statedebug}
  1711. begin
  1712. With ptaiprop(p.optinfo)^.regs[supreg] Do
  1713. if (typ in [con_ref,con_noRemoveRef]) then
  1714. begin
  1715. incState(wstate,1);
  1716. { also store how many instructions are part of the sequence in the first }
  1717. { instructions ptaiprop, so it can be easily accessed from within }
  1718. { CheckSequence}
  1719. inc(NrOfMods, NrOfInstrSinceLastMod[supreg]);
  1720. ptaiprop(tai(StartMod).OptInfo)^.Regs[supreg].NrOfMods := NrOfMods;
  1721. NrOfInstrSinceLastMod[supreg] := 0;
  1722. invalidateDependingRegs(p.optinfo,supreg);
  1723. ptaiprop(p.optinfo)^.regs[supreg].memwrite := nil;
  1724. {$ifdef StateDebug}
  1725. hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)
  1726. + ' -- ' + tostr(ptaiprop(p.optinfo)^.Regs[supreg].nrofmods)));
  1727. InsertLLItem(AsmL, p, p.next, hp);
  1728. {$endif StateDebug}
  1729. end
  1730. else
  1731. begin
  1732. {$ifdef statedebug}
  1733. hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))));
  1734. insertllitem(asml,p,p.next,hp);
  1735. {$endif statedebug}
  1736. DestroyReg(ptaiprop(p.optinfo), supreg, true);
  1737. {$ifdef StateDebug}
  1738. hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)));
  1739. InsertLLItem(AsmL, p, p.next, hp);
  1740. {$endif StateDebug}
  1741. end
  1742. end;
  1743. procedure AddInstr2OpContents({$ifdef statedebug} asml: TAAsmoutput; {$endif}
  1744. p: taicpu; const oper: TOper);
  1745. begin
  1746. if oper.typ = top_reg then
  1747. AddInstr2RegContents({$ifdef statedebug} asml, {$endif}p, getsupreg(oper.reg))
  1748. else
  1749. begin
  1750. ReadOp(ptaiprop(p.optinfo), oper);
  1751. DestroyOp(p, oper);
  1752. end
  1753. end;
  1754. {*************************************************************************************}
  1755. {************************************** TDFAOBJ **************************************}
  1756. {*************************************************************************************}
  1757. constructor tdfaobj.create(_list: taasmoutput);
  1758. begin
  1759. list := _list;
  1760. blockstart := nil;
  1761. blockend := nil;
  1762. nroftaiobjs := 0;
  1763. taipropblock := nil;
  1764. lolab := 0;
  1765. hilab := 0;
  1766. labdif := 0;
  1767. labeltable := nil;
  1768. end;
  1769. procedure tdfaobj.initlabeltable;
  1770. var
  1771. labelfound: boolean;
  1772. p, prev: tai;
  1773. hp1, hp2: tai;
  1774. {$ifdef i386}
  1775. regcounter,
  1776. supreg : tsuperregister;
  1777. {$endif i386}
  1778. usedregs, nodeallocregs: tregset;
  1779. begin
  1780. labelfound := false;
  1781. lolab := maxlongint;
  1782. hilab := 0;
  1783. p := blockstart;
  1784. prev := p;
  1785. while assigned(p) do
  1786. begin
  1787. if (tai(p).typ = ait_label) then
  1788. if not labelcanbeskipped(tai_label(p)) then
  1789. begin
  1790. labelfound := true;
  1791. if (tai_Label(p).l.labelnr < lolab) then
  1792. lolab := tai_label(p).l.labelnr;
  1793. if (tai_Label(p).l.labelnr > hilab) then
  1794. hilab := tai_label(p).l.labelnr;
  1795. end;
  1796. prev := p;
  1797. getnextinstruction(p, p);
  1798. end;
  1799. if (prev.typ = ait_marker) and
  1800. (tai_marker(prev).kind = asmblockstart) then
  1801. blockend := prev
  1802. else blockend := nil;
  1803. if labelfound then
  1804. labdif := hilab+1-lolab
  1805. else labdif := 0;
  1806. usedregs := [];
  1807. if (labdif <> 0) then
  1808. begin
  1809. getmem(labeltable, labdif*sizeof(tlabeltableitem));
  1810. fillchar(labeltable^, labdif*sizeof(tlabeltableitem), 0);
  1811. end;
  1812. p := blockstart;
  1813. prev := p;
  1814. while (p <> blockend) do
  1815. begin
  1816. case p.typ of
  1817. ait_label:
  1818. if not labelcanbeskipped(tai_label(p)) then
  1819. labeltable^[tai_label(p).l.labelnr-lolab].taiobj := p;
  1820. {$ifdef i386}
  1821. ait_regalloc:
  1822. begin
  1823. supreg:=getsupreg(tai_regalloc(p).reg);
  1824. case tai_regalloc(p).ratype of
  1825. ra_alloc :
  1826. begin
  1827. if not(supreg in usedregs) then
  1828. include(usedregs, supreg)
  1829. else
  1830. addregdeallocfor(list, tai_regalloc(p).reg, p);
  1831. end;
  1832. ra_dealloc :
  1833. begin
  1834. exclude(usedregs, supreg);
  1835. hp1 := p;
  1836. hp2 := nil;
  1837. while not(findregalloc(tai_regalloc(p).reg, tai(hp1.next),ra_alloc)) and
  1838. getnextinstruction(hp1, hp1) and
  1839. regininstruction(getsupreg(tai_regalloc(p).reg), hp1) Do
  1840. hp2 := hp1;
  1841. if hp2 <> nil then
  1842. begin
  1843. hp1 := tai(p.previous);
  1844. list.remove(p);
  1845. insertllitem(list, hp2, tai(hp2.next), p);
  1846. p := hp1;
  1847. end;
  1848. end;
  1849. end;
  1850. end;
  1851. {$endif i386}
  1852. end;
  1853. repeat
  1854. prev := p;
  1855. p := tai(p.next);
  1856. until not(assigned(p)) or
  1857. not(p.typ in (skipinstr - [ait_regalloc]));
  1858. end;
  1859. {$ifdef i386}
  1860. { don't add deallocation for function result variable or for regvars}
  1861. getNoDeallocRegs(noDeallocRegs);
  1862. usedRegs := usedRegs - noDeallocRegs;
  1863. for regCounter := RS_EAX to RS_EDI do
  1864. if regCounter in usedRegs then
  1865. addRegDeallocFor(list,newreg(R_INTREGISTER,regCounter,R_SUBWHOLE),prev);
  1866. {$endif i386}
  1867. end;
  1868. function tdfaobj.pass_1(_blockstart: tai): tai;
  1869. begin
  1870. blockstart := _blockstart;
  1871. initlabeltable;
  1872. pass_1 := blockend;
  1873. end;
  1874. function tdfaobj.initdfapass2: boolean;
  1875. {reserves memory for the PtaiProps in one big memory block when not using
  1876. TP, returns False if not enough memory is available for the optimizer in all
  1877. cases}
  1878. var
  1879. p: tai;
  1880. count: Longint;
  1881. { TmpStr: String; }
  1882. begin
  1883. p := blockstart;
  1884. skiphead(p);
  1885. nroftaiobjs := 0;
  1886. while (p <> blockend) do
  1887. begin
  1888. {$ifDef JumpAnal}
  1889. case p.typ of
  1890. ait_label:
  1891. begin
  1892. if not labelcanbeskipped(tai_label(p)) then
  1893. labeltable^[tai_label(p).l.labelnr-lolab].instrnr := nroftaiobjs
  1894. end;
  1895. ait_instruction:
  1896. begin
  1897. if taicpu(p).is_jmp then
  1898. begin
  1899. if (tasmlabel(taicpu(p).oper[0]^.sym).labelnr >= lolab) and
  1900. (tasmlabel(taicpu(p).oper[0]^.sym).labelnr <= hilab) then
  1901. inc(labeltable^[tasmlabel(taicpu(p).oper[0]^.sym).labelnr-lolab].refsfound);
  1902. end;
  1903. end;
  1904. { ait_instruction:
  1905. begin
  1906. if (taicpu(p).opcode = A_PUSH) and
  1907. (taicpu(p).oper[0]^.typ = top_symbol) and
  1908. (PCSymbol(taicpu(p).oper[0]^)^.offset = 0) then
  1909. begin
  1910. TmpStr := StrPas(PCSymbol(taicpu(p).oper[0]^)^.symbol);
  1911. if}
  1912. end;
  1913. {$endif JumpAnal}
  1914. inc(NrOftaiObjs);
  1915. getnextinstruction(p,p);
  1916. end;
  1917. if nroftaiobjs <> 0 then
  1918. begin
  1919. initdfapass2 := True;
  1920. getmem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
  1921. fillchar(taiPropblock^,nroftaiobjs*sizeof(ttaiprop),0);
  1922. p := blockstart;
  1923. skiphead(p);
  1924. for count := 1 To nroftaiobjs do
  1925. begin
  1926. ptaiprop(p.optinfo) := @taipropblock^[count];
  1927. getnextinstruction(p, p);
  1928. end;
  1929. end
  1930. else
  1931. initdfapass2 := false;
  1932. end;
  1933. procedure tdfaobj.dodfapass2;
  1934. {Analyzes the Data Flow of an assembler list. Starts creating the reg
  1935. contents for the instructions starting with p. Returns the last tai which has
  1936. been processed}
  1937. var
  1938. curprop, LastFlagsChangeProp: ptaiprop;
  1939. Cnt, InstrCnt : Longint;
  1940. InstrProp: TInsProp;
  1941. UsedRegs: TRegSet;
  1942. prev,p : tai;
  1943. tmpref: TReference;
  1944. tmpsupreg: tsuperregister;
  1945. {$ifdef statedebug}
  1946. hp : tai;
  1947. {$endif}
  1948. {$ifdef AnalyzeLoops}
  1949. hp : tai;
  1950. TmpState: Byte;
  1951. {$endif AnalyzeLoops}
  1952. begin
  1953. p := BlockStart;
  1954. LastFlagsChangeProp := nil;
  1955. prev := nil;
  1956. UsedRegs := [];
  1957. UpdateUsedregs(UsedRegs, p);
  1958. SkipHead(p);
  1959. BlockStart := p;
  1960. InstrCnt := 1;
  1961. fillchar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0);
  1962. while (p <> Blockend) Do
  1963. begin
  1964. curprop := @taiPropBlock^[InstrCnt];
  1965. if assigned(prev)
  1966. then
  1967. begin
  1968. {$ifdef JumpAnal}
  1969. if (p.Typ <> ait_label) then
  1970. {$endif JumpAnal}
  1971. begin
  1972. curprop^.regs := ptaiprop(prev.OptInfo)^.Regs;
  1973. curprop^.DirFlag := ptaiprop(prev.OptInfo)^.DirFlag;
  1974. curprop^.FlagsUsed := false;
  1975. end
  1976. end
  1977. else
  1978. begin
  1979. fillchar(curprop^, SizeOf(curprop^), 0);
  1980. { For tmpreg := RS_EAX to RS_EDI Do
  1981. curprop^.regs[tmpreg].WState := 1;}
  1982. end;
  1983. curprop^.UsedRegs := UsedRegs;
  1984. curprop^.CanBeRemoved := False;
  1985. UpdateUsedRegs(UsedRegs, tai(p.Next));
  1986. For tmpsupreg := RS_EAX To RS_EDI Do
  1987. if NrOfInstrSinceLastMod[tmpsupreg] < 255 then
  1988. inc(NrOfInstrSinceLastMod[tmpsupreg])
  1989. else
  1990. begin
  1991. NrOfInstrSinceLastMod[tmpsupreg] := 0;
  1992. curprop^.regs[tmpsupreg].typ := con_unknown;
  1993. end;
  1994. case p.typ Of
  1995. ait_marker:;
  1996. ait_label:
  1997. {$ifndef JumpAnal}
  1998. if not labelCanBeSkipped(tai_label(p)) then
  1999. DestroyAllRegs(curprop,false,false);
  2000. {$else JumpAnal}
  2001. begin
  2002. if not labelCanBeSkipped(tai_label(p)) then
  2003. With LTable^[tai_Label(p).l^.labelnr-LoLab] Do
  2004. {$ifDef AnalyzeLoops}
  2005. if (RefsFound = tai_Label(p).l^.RefCount)
  2006. {$else AnalyzeLoops}
  2007. if (JmpsProcessed = tai_Label(p).l^.RefCount)
  2008. {$endif AnalyzeLoops}
  2009. then
  2010. {all jumps to this label have been found}
  2011. {$ifDef AnalyzeLoops}
  2012. if (JmpsProcessed > 0)
  2013. then
  2014. {$endif AnalyzeLoops}
  2015. {we've processed at least one jump to this label}
  2016. begin
  2017. if (GetLastInstruction(p, hp) and
  2018. not(((hp.typ = ait_instruction)) and
  2019. (taicpu_labeled(hp).is_jmp))
  2020. then
  2021. {previous instruction not a JMP -> the contents of the registers after the
  2022. previous intruction has been executed have to be taken into account as well}
  2023. For tmpsupreg := RS_EAX to RS_EDI Do
  2024. begin
  2025. if (curprop^.regs[tmpsupreg].WState <>
  2026. ptaiprop(hp.OptInfo)^.Regs[tmpsupreg].WState)
  2027. then DestroyReg(curprop, tmpsupreg, true)
  2028. end
  2029. end
  2030. {$ifDef AnalyzeLoops}
  2031. else
  2032. {a label from a backward jump (e.g. a loop), no jump to this label has
  2033. already been processed}
  2034. if GetLastInstruction(p, hp) and
  2035. not(hp.typ = ait_instruction) and
  2036. (taicpu_labeled(hp).opcode = A_JMP))
  2037. then
  2038. {previous instruction not a jmp, so keep all the registers' contents from the
  2039. previous instruction}
  2040. begin
  2041. curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
  2042. curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
  2043. end
  2044. else
  2045. {previous instruction a jmp and no jump to this label processed yet}
  2046. begin
  2047. hp := p;
  2048. Cnt := InstrCnt;
  2049. {continue until we find a jump to the label or a label which has already
  2050. been processed}
  2051. while GetNextInstruction(hp, hp) and
  2052. not((hp.typ = ait_instruction) and
  2053. (taicpu(hp).is_jmp) and
  2054. (tasmlabel(taicpu(hp).oper[0]^.sym).labelnr = tai_Label(p).l^.labelnr)) and
  2055. not((hp.typ = ait_label) and
  2056. (LTable^[tai_Label(hp).l^.labelnr-LoLab].RefsFound
  2057. = tai_Label(hp).l^.RefCount) and
  2058. (LTable^[tai_Label(hp).l^.labelnr-LoLab].JmpsProcessed > 0)) Do
  2059. inc(Cnt);
  2060. if (hp.typ = ait_label)
  2061. then
  2062. {there's a processed label after the current one}
  2063. begin
  2064. curprop^.regs := taiPropBlock^[Cnt].Regs;
  2065. curprop.DirFlag := taiPropBlock^[Cnt].DirFlag;
  2066. end
  2067. else
  2068. {there's no label anymore after the current one, or they haven't been
  2069. processed yet}
  2070. begin
  2071. GetLastInstruction(p, hp);
  2072. curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
  2073. curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
  2074. DestroyAllRegs(ptaiprop(hp.OptInfo),true,true)
  2075. end
  2076. end
  2077. {$endif AnalyzeLoops}
  2078. else
  2079. {not all references to this label have been found, so destroy all registers}
  2080. begin
  2081. GetLastInstruction(p, hp);
  2082. curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
  2083. curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
  2084. DestroyAllRegs(curprop,true,true)
  2085. end;
  2086. end;
  2087. {$endif JumpAnal}
  2088. {$ifdef GDB}
  2089. ait_stabs, ait_stabn, ait_stab_function_name:;
  2090. {$endif GDB}
  2091. ait_align: ; { may destroy flags !!! }
  2092. ait_instruction:
  2093. begin
  2094. if taicpu(p).is_jmp or
  2095. (taicpu(p).opcode = A_JMP) then
  2096. begin
  2097. {$ifNDef JumpAnal}
  2098. for tmpsupreg := RS_EAX to RS_EDI do
  2099. with curprop^.regs[tmpsupreg] do
  2100. case typ of
  2101. con_ref: typ := con_noRemoveRef;
  2102. con_const: typ := con_noRemoveConst;
  2103. con_invalid: typ := con_unknown;
  2104. end;
  2105. {$else JumpAnal}
  2106. With LTable^[tasmlabel(taicpu(p).oper[0]^.sym).labelnr-LoLab] Do
  2107. if (RefsFound = tasmlabel(taicpu(p).oper[0]^.sym).RefCount) then
  2108. begin
  2109. if (InstrCnt < InstrNr)
  2110. then
  2111. {forward jump}
  2112. if (JmpsProcessed = 0) then
  2113. {no jump to this label has been processed yet}
  2114. begin
  2115. taiPropBlock^[InstrNr].Regs := curprop^.regs;
  2116. taiPropBlock^[InstrNr].DirFlag := curprop.DirFlag;
  2117. inc(JmpsProcessed);
  2118. end
  2119. else
  2120. begin
  2121. For tmpreg := RS_EAX to RS_EDI Do
  2122. if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
  2123. curprop^.regs[tmpreg].WState) then
  2124. DestroyReg(@taiPropBlock^[InstrNr], tmpreg, true);
  2125. inc(JmpsProcessed);
  2126. end
  2127. {$ifdef AnalyzeLoops}
  2128. else
  2129. { backward jump, a loop for example}
  2130. { if (JmpsProcessed > 0) or
  2131. not(GetLastInstruction(taiObj, hp) and
  2132. (hp.typ = ait_labeled_instruction) and
  2133. (taicpu_labeled(hp).opcode = A_JMP))
  2134. then}
  2135. {instruction prior to label is not a jmp, or at least one jump to the label
  2136. has yet been processed}
  2137. begin
  2138. inc(JmpsProcessed);
  2139. For tmpreg := RS_EAX to RS_EDI Do
  2140. if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
  2141. curprop^.regs[tmpreg].WState)
  2142. then
  2143. begin
  2144. TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
  2145. Cnt := InstrNr;
  2146. while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
  2147. begin
  2148. DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
  2149. inc(Cnt);
  2150. end;
  2151. while (Cnt <= InstrCnt) Do
  2152. begin
  2153. inc(taiPropBlock^[Cnt].Regs[tmpreg].WState);
  2154. inc(Cnt)
  2155. end
  2156. end;
  2157. end
  2158. { else }
  2159. {instruction prior to label is a jmp and no jumps to the label have yet been
  2160. processed}
  2161. { begin
  2162. inc(JmpsProcessed);
  2163. For tmpreg := RS_EAX to RS_EDI Do
  2164. begin
  2165. TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
  2166. Cnt := InstrNr;
  2167. while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
  2168. begin
  2169. taiPropBlock^[Cnt].Regs[tmpreg] := curprop^.regs[tmpreg];
  2170. inc(Cnt);
  2171. end;
  2172. TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
  2173. while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
  2174. begin
  2175. DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
  2176. inc(Cnt);
  2177. end;
  2178. while (Cnt <= InstrCnt) Do
  2179. begin
  2180. inc(taiPropBlock^[Cnt].Regs[tmpreg].WState);
  2181. inc(Cnt)
  2182. end
  2183. end
  2184. end}
  2185. {$endif AnalyzeLoops}
  2186. end;
  2187. {$endif JumpAnal}
  2188. end
  2189. else
  2190. begin
  2191. InstrProp := InsProp[taicpu(p).opcode];
  2192. case taicpu(p).opcode Of
  2193. A_MOV, A_MOVZX, A_MOVSX:
  2194. begin
  2195. case taicpu(p).oper[0]^.typ Of
  2196. top_ref, top_reg:
  2197. case taicpu(p).oper[1]^.typ Of
  2198. top_reg:
  2199. begin
  2200. {$ifdef statedebug}
  2201. hp := tai_comment.Create(strpnew('destroying '+std_regname(taicpu(p).oper[1]^.reg)));
  2202. insertllitem(list,p,p.next,hp);
  2203. {$endif statedebug}
  2204. readOp(curprop, taicpu(p).oper[0]^);
  2205. tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
  2206. if reginop(tmpsupreg, taicpu(p).oper[0]^) and
  2207. (curprop^.regs[tmpsupreg].typ in [con_ref,con_noRemoveRef]) then
  2208. begin
  2209. with curprop^.regs[tmpsupreg] Do
  2210. begin
  2211. incState(wstate,1);
  2212. { also store how many instructions are part of the sequence in the first }
  2213. { instruction's ptaiprop, so it can be easily accessed from within }
  2214. { CheckSequence }
  2215. inc(nrOfMods, nrOfInstrSinceLastMod[tmpsupreg]);
  2216. ptaiprop(startmod.optinfo)^.regs[tmpsupreg].nrOfMods := nrOfMods;
  2217. nrOfInstrSinceLastMod[tmpsupreg] := 0;
  2218. { Destroy the contents of the registers }
  2219. { that depended on the previous value of }
  2220. { this register }
  2221. invalidateDependingRegs(curprop,tmpsupreg);
  2222. curprop^.regs[tmpsupreg].memwrite := nil;
  2223. end;
  2224. end
  2225. else
  2226. begin
  2227. {$ifdef statedebug}
  2228. hp := tai_comment.Create(strpnew('destroying & initing '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
  2229. insertllitem(list,p,p.next,hp);
  2230. {$endif statedebug}
  2231. destroyReg(curprop, tmpsupreg, true);
  2232. if not(reginop(tmpsupreg, taicpu(p).oper[0]^)) then
  2233. with curprop^.regs[tmpsupreg] Do
  2234. begin
  2235. typ := con_ref;
  2236. startmod := p;
  2237. nrOfMods := 1;
  2238. end
  2239. end;
  2240. {$ifdef StateDebug}
  2241. hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))+': '+tostr(curprop^.regs[tmpsupreg].WState)));
  2242. insertllitem(list,p,p.next,hp);
  2243. {$endif StateDebug}
  2244. end;
  2245. top_ref:
  2246. begin
  2247. readref(curprop, taicpu(p).oper[1]^.ref);
  2248. if taicpu(p).oper[0]^.typ = top_reg then
  2249. begin
  2250. readreg(curprop, getsupreg(taicpu(p).oper[0]^.reg));
  2251. DestroyRefs(p, taicpu(p).oper[1]^.ref^, getsupreg(taicpu(p).oper[0]^.reg));
  2252. ptaiprop(p.optinfo)^.regs[getsupreg(taicpu(p).oper[0]^.reg)].memwrite :=
  2253. taicpu(p);
  2254. end
  2255. else
  2256. DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID);
  2257. end;
  2258. end;
  2259. top_Const:
  2260. begin
  2261. case taicpu(p).oper[1]^.typ Of
  2262. top_reg:
  2263. begin
  2264. tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
  2265. {$ifdef statedebug}
  2266. hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
  2267. insertllitem(list,p,p.next,hp);
  2268. {$endif statedebug}
  2269. With curprop^.regs[tmpsupreg] Do
  2270. begin
  2271. DestroyReg(curprop, tmpsupreg, true);
  2272. typ := Con_Const;
  2273. StartMod := p;
  2274. end
  2275. end;
  2276. top_ref:
  2277. begin
  2278. readref(curprop, taicpu(p).oper[1]^.ref);
  2279. DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID);
  2280. end;
  2281. end;
  2282. end;
  2283. end;
  2284. end;
  2285. A_DIV, A_IDIV, A_MUL:
  2286. begin
  2287. ReadOp(curprop, taicpu(p).oper[0]^);
  2288. readreg(curprop,RS_EAX);
  2289. if (taicpu(p).OpCode = A_IDIV) or
  2290. (taicpu(p).OpCode = A_DIV) then
  2291. begin
  2292. readreg(curprop,RS_EDX);
  2293. end;
  2294. {$ifdef statedebug}
  2295. hp := tai_comment.Create(strpnew('destroying eax and edx'));
  2296. insertllitem(list,p,p.next,hp);
  2297. {$endif statedebug}
  2298. { DestroyReg(curprop, RS_EAX, true);}
  2299. AddInstr2RegContents({$ifdef statedebug}list,{$endif}
  2300. taicpu(p), RS_EAX);
  2301. DestroyReg(curprop, RS_EDX, true)
  2302. end;
  2303. A_IMUL:
  2304. begin
  2305. ReadOp(curprop,taicpu(p).oper[0]^);
  2306. if (taicpu(p).ops >= 2) then
  2307. ReadOp(curprop,taicpu(p).oper[1]^);
  2308. if (taicpu(p).ops <= 2) then
  2309. if (taicpu(p).oper[1]^.typ = top_none) then
  2310. begin
  2311. readreg(curprop,RS_EAX);
  2312. {$ifdef statedebug}
  2313. hp := tai_comment.Create(strpnew('destroying eax and edx'));
  2314. insertllitem(list,p,p.next,hp);
  2315. {$endif statedebug}
  2316. { DestroyReg(curprop, RS_EAX, true); }
  2317. AddInstr2RegContents({$ifdef statedebug}list,{$endif}
  2318. taicpu(p), RS_EAX);
  2319. DestroyReg(curprop,RS_EDX, true)
  2320. end
  2321. else
  2322. AddInstr2OpContents(
  2323. {$ifdef statedebug}list,{$endif}
  2324. taicpu(p), taicpu(p).oper[1]^)
  2325. else
  2326. AddInstr2OpContents({$ifdef statedebug}list,{$endif}
  2327. taicpu(p), taicpu(p).oper[2]^);
  2328. end;
  2329. A_LEA:
  2330. begin
  2331. readop(curprop,taicpu(p).oper[0]^);
  2332. if reginref(getsupreg(taicpu(p).oper[1]^.reg),taicpu(p).oper[0]^.ref^) then
  2333. AddInstr2RegContents({$ifdef statedebug}list,{$endif}
  2334. taicpu(p), getsupreg(taicpu(p).oper[1]^.reg))
  2335. else
  2336. begin
  2337. {$ifdef statedebug}
  2338. hp := tai_comment.Create(strpnew('destroying & initing'+
  2339. std_regname(taicpu(p).oper[1]^.reg)));
  2340. insertllitem(list,p,p.next,hp);
  2341. {$endif statedebug}
  2342. destroyreg(curprop,getsupreg(taicpu(p).oper[1]^.reg),true);
  2343. with curprop^.regs[getsupreg(taicpu(p).oper[1]^.reg)] Do
  2344. begin
  2345. typ := con_ref;
  2346. startmod := p;
  2347. nrOfMods := 1;
  2348. end
  2349. end;
  2350. end;
  2351. else
  2352. begin
  2353. Cnt := 1;
  2354. while (Cnt <= maxinschanges) and
  2355. (InstrProp.Ch[Cnt] <> Ch_None) Do
  2356. begin
  2357. case InstrProp.Ch[Cnt] Of
  2358. Ch_REAX..Ch_REDI:
  2359. begin
  2360. tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
  2361. readreg(curprop,tmpsupreg);
  2362. end;
  2363. Ch_WEAX..Ch_RWEDI:
  2364. begin
  2365. if (InstrProp.Ch[Cnt] >= Ch_RWEAX) then
  2366. begin
  2367. tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
  2368. readreg(curprop,tmpsupreg);
  2369. end;
  2370. {$ifdef statedebug}
  2371. hp := tai_comment.Create(strpnew('destroying '+
  2372. std_regname(tch2reg(InstrProp.Ch[Cnt]))));
  2373. insertllitem(list,p,p.next,hp);
  2374. {$endif statedebug}
  2375. tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
  2376. DestroyReg(curprop,tmpsupreg, true);
  2377. end;
  2378. Ch_MEAX..Ch_MEDI:
  2379. begin
  2380. tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
  2381. AddInstr2RegContents({$ifdef statedebug} list,{$endif}
  2382. taicpu(p),tmpsupreg);
  2383. end;
  2384. Ch_CDirFlag: curprop^.DirFlag := F_notSet;
  2385. Ch_SDirFlag: curprop^.DirFlag := F_Set;
  2386. Ch_Rop1: ReadOp(curprop, taicpu(p).oper[0]^);
  2387. Ch_Rop2: ReadOp(curprop, taicpu(p).oper[1]^);
  2388. Ch_ROp3: ReadOp(curprop, taicpu(p).oper[2]^);
  2389. Ch_Wop1..Ch_RWop1:
  2390. begin
  2391. if (InstrProp.Ch[Cnt] in [Ch_RWop1]) then
  2392. ReadOp(curprop, taicpu(p).oper[0]^);
  2393. DestroyOp(p, taicpu(p).oper[0]^);
  2394. end;
  2395. Ch_Mop1:
  2396. AddInstr2OpContents({$ifdef statedebug} list, {$endif}
  2397. taicpu(p), taicpu(p).oper[0]^);
  2398. Ch_Wop2..Ch_RWop2:
  2399. begin
  2400. if (InstrProp.Ch[Cnt] = Ch_RWop2) then
  2401. ReadOp(curprop, taicpu(p).oper[1]^);
  2402. DestroyOp(p, taicpu(p).oper[1]^);
  2403. end;
  2404. Ch_Mop2:
  2405. AddInstr2OpContents({$ifdef statedebug} list, {$endif}
  2406. taicpu(p), taicpu(p).oper[1]^);
  2407. Ch_WOp3..Ch_RWOp3:
  2408. begin
  2409. if (InstrProp.Ch[Cnt] = Ch_RWOp3) then
  2410. ReadOp(curprop, taicpu(p).oper[2]^);
  2411. DestroyOp(p, taicpu(p).oper[2]^);
  2412. end;
  2413. Ch_Mop3:
  2414. AddInstr2OpContents({$ifdef statedebug} list, {$endif}
  2415. taicpu(p), taicpu(p).oper[2]^);
  2416. Ch_WMemEDI:
  2417. begin
  2418. readreg(curprop, RS_EDI);
  2419. fillchar(tmpref, SizeOf(tmpref), 0);
  2420. tmpref.base := NR_EDI;
  2421. tmpref.index := NR_EDI;
  2422. DestroyRefs(p, tmpref,RS_INVALID)
  2423. end;
  2424. Ch_RFlags:
  2425. if assigned(LastFlagsChangeProp) then
  2426. LastFlagsChangeProp^.FlagsUsed := true;
  2427. Ch_WFlags:
  2428. LastFlagsChangeProp := curprop;
  2429. Ch_RWFlags:
  2430. begin
  2431. if assigned(LastFlagsChangeProp) then
  2432. LastFlagsChangeProp^.FlagsUsed := true;
  2433. LastFlagsChangeProp := curprop;
  2434. end;
  2435. Ch_FPU:;
  2436. else
  2437. begin
  2438. {$ifdef statedebug}
  2439. hp := tai_comment.Create(strpnew(
  2440. 'destroying all regs for prev instruction'));
  2441. insertllitem(list,p, p.next,hp);
  2442. {$endif statedebug}
  2443. DestroyAllRegs(curprop,true,true);
  2444. LastFlagsChangeProp := curprop;
  2445. end;
  2446. end;
  2447. inc(Cnt);
  2448. end
  2449. end;
  2450. end;
  2451. end;
  2452. end
  2453. else
  2454. begin
  2455. {$ifdef statedebug}
  2456. hp := tai_comment.Create(strpnew(
  2457. 'destroying all regs: unknown tai: '+tostr(ord(p.typ))));
  2458. insertllitem(list,p, p.next,hp);
  2459. {$endif statedebug}
  2460. DestroyAllRegs(curprop,true,true);
  2461. end;
  2462. end;
  2463. inc(InstrCnt);
  2464. prev := p;
  2465. GetNextInstruction(p, p);
  2466. end;
  2467. end;
  2468. function tdfaobj.pass_2: boolean;
  2469. begin
  2470. if initdfapass2 then
  2471. begin
  2472. dodfapass2;
  2473. pass_2 := true
  2474. end
  2475. else
  2476. pass_2 := false;
  2477. end;
  2478. {$ifopt r+}
  2479. {$define rangewason}
  2480. {$r-}
  2481. {$endif}
  2482. function tdfaobj.getlabelwithsym(sym: tasmlabel): tai;
  2483. begin
  2484. if (sym.labelnr >= lolab) and
  2485. (sym.labelnr <= hilab) then { range check, a jump can go past an assembler block! }
  2486. getlabelwithsym := labeltable^[sym.labelnr-lolab].taiobj
  2487. else
  2488. getlabelwithsym := nil;
  2489. end;
  2490. {$ifdef rangewason}
  2491. {$r+}
  2492. {$undef rangewason}
  2493. {$endif}
  2494. procedure tdfaobj.clear;
  2495. begin
  2496. if labdif <> 0 then
  2497. begin
  2498. freemem(labeltable);
  2499. labeltable := nil;
  2500. end;
  2501. if assigned(taipropblock) then
  2502. begin
  2503. freemem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
  2504. taipropblock := nil;
  2505. end;
  2506. end;
  2507. end.
  2508. {
  2509. $Log$
  2510. Revision 1.71 2004-10-05 20:41:01 peter
  2511. * more spilling rewrites
  2512. Revision 1.70 2004/10/04 20:46:22 peter
  2513. * spilling code rewritten for x86. It now used the generic
  2514. spilling routines. Special x86 optimization still needs
  2515. to be added.
  2516. * Spilling fixed when both operands needed to be spilled
  2517. * Cleanup of spilling routine, do_spill_readwritten removed
  2518. Revision 1.69 2004/09/26 17:45:30 peter
  2519. * simple regvar support, not yet finished
  2520. Revision 1.68 2004/06/20 08:55:31 florian
  2521. * logs truncated
  2522. Revision 1.67 2004/05/22 23:34:28 peter
  2523. tai_regalloc.allocation changed to ratype to notify rgobj of register size changes
  2524. Revision 1.66 2004/02/27 19:55:23 jonas
  2525. * fixed optimizer for new treference fields
  2526. Revision 1.65 2004/02/27 10:21:05 florian
  2527. * top_symbol killed
  2528. + refaddr to treference added
  2529. + refsymbol to treference added
  2530. * top_local stuff moved to an extra record to save memory
  2531. + aint introduced
  2532. * tppufile.get/putint64/aint implemented
  2533. }