1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602 |
- /* Integrated Register Allocator (IRA) entry point.
- Copyright (C) 2006-2015 Free Software Foundation, Inc.
- Contributed by Vladimir Makarov <vmakarov@redhat.com>.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* The integrated register allocator (IRA) is a
- regional register allocator performing graph coloring on a top-down
- traversal of nested regions. Graph coloring in a region is based
- on Chaitin-Briggs algorithm. It is called integrated because
- register coalescing, register live range splitting, and choosing a
- better hard register are done on-the-fly during coloring. Register
- coalescing and choosing a cheaper hard register is done by hard
- register preferencing during hard register assigning. The live
- range splitting is a byproduct of the regional register allocation.
- Major IRA notions are:
- o *Region* is a part of CFG where graph coloring based on
- Chaitin-Briggs algorithm is done. IRA can work on any set of
- nested CFG regions forming a tree. Currently the regions are
- the entire function for the root region and natural loops for
- the other regions. Therefore data structure representing a
- region is called loop_tree_node.
- o *Allocno class* is a register class used for allocation of
- given allocno. It means that only hard register of given
- register class can be assigned to given allocno. In reality,
- even smaller subset of (*profitable*) hard registers can be
- assigned. In rare cases, the subset can be even smaller
- because our modification of Chaitin-Briggs algorithm requires
- that sets of hard registers can be assigned to allocnos forms a
- forest, i.e. the sets can be ordered in a way where any
- previous set is not intersected with given set or is a superset
- of given set.
- o *Pressure class* is a register class belonging to a set of
- register classes containing all of the hard-registers available
- for register allocation. The set of all pressure classes for a
- target is defined in the corresponding machine-description file
- according some criteria. Register pressure is calculated only
- for pressure classes and it affects some IRA decisions as
- forming allocation regions.
- o *Allocno* represents the live range of a pseudo-register in a
- region. Besides the obvious attributes like the corresponding
- pseudo-register number, allocno class, conflicting allocnos and
- conflicting hard-registers, there are a few allocno attributes
- which are important for understanding the allocation algorithm:
- - *Live ranges*. This is a list of ranges of *program points*
- where the allocno lives. Program points represent places
- where a pseudo can be born or become dead (there are
- approximately two times more program points than the insns)
- and they are represented by integers starting with 0. The
- live ranges are used to find conflicts between allocnos.
- They also play very important role for the transformation of
- the IRA internal representation of several regions into a one
- region representation. The later is used during the reload
- pass work because each allocno represents all of the
- corresponding pseudo-registers.
- - *Hard-register costs*. This is a vector of size equal to the
- number of available hard-registers of the allocno class. The
- cost of a callee-clobbered hard-register for an allocno is
- increased by the cost of save/restore code around the calls
- through the given allocno's life. If the allocno is a move
- instruction operand and another operand is a hard-register of
- the allocno class, the cost of the hard-register is decreased
- by the move cost.
- When an allocno is assigned, the hard-register with minimal
- full cost is used. Initially, a hard-register's full cost is
- the corresponding value from the hard-register's cost vector.
- If the allocno is connected by a *copy* (see below) to
- another allocno which has just received a hard-register, the
- cost of the hard-register is decreased. Before choosing a
- hard-register for an allocno, the allocno's current costs of
- the hard-registers are modified by the conflict hard-register
- costs of all of the conflicting allocnos which are not
- assigned yet.
- - *Conflict hard-register costs*. This is a vector of the same
- size as the hard-register costs vector. To permit an
- unassigned allocno to get a better hard-register, IRA uses
- this vector to calculate the final full cost of the
- available hard-registers. Conflict hard-register costs of an
- unassigned allocno are also changed with a change of the
- hard-register cost of the allocno when a copy involving the
- allocno is processed as described above. This is done to
- show other unassigned allocnos that a given allocno prefers
- some hard-registers in order to remove the move instruction
- corresponding to the copy.
- o *Cap*. If a pseudo-register does not live in a region but
- lives in a nested region, IRA creates a special allocno called
- a cap in the outer region. A region cap is also created for a
- subregion cap.
- o *Copy*. Allocnos can be connected by copies. Copies are used
- to modify hard-register costs for allocnos during coloring.
- Such modifications reflects a preference to use the same
- hard-register for the allocnos connected by copies. Usually
- copies are created for move insns (in this case it results in
- register coalescing). But IRA also creates copies for operands
- of an insn which should be assigned to the same hard-register
- due to constraints in the machine description (it usually
- results in removing a move generated in reload to satisfy
- the constraints) and copies referring to the allocno which is
- the output operand of an instruction and the allocno which is
- an input operand dying in the instruction (creation of such
- copies results in less register shuffling). IRA *does not*
- create copies between the same register allocnos from different
- regions because we use another technique for propagating
- hard-register preference on the borders of regions.
- Allocnos (including caps) for the upper region in the region tree
- *accumulate* information important for coloring from allocnos with
- the same pseudo-register from nested regions. This includes
- hard-register and memory costs, conflicts with hard-registers,
- allocno conflicts, allocno copies and more. *Thus, attributes for
- allocnos in a region have the same values as if the region had no
- subregions*. It means that attributes for allocnos in the
- outermost region corresponding to the function have the same values
- as though the allocation used only one region which is the entire
- function. It also means that we can look at IRA work as if the
- first IRA did allocation for all function then it improved the
- allocation for loops then their subloops and so on.
- IRA major passes are:
- o Building IRA internal representation which consists of the
- following subpasses:
- * First, IRA builds regions and creates allocnos (file
- ira-build.c) and initializes most of their attributes.
- * Then IRA finds an allocno class for each allocno and
- calculates its initial (non-accumulated) cost of memory and
- each hard-register of its allocno class (file ira-cost.c).
- * IRA creates live ranges of each allocno, calculates register
- pressure for each pressure class in each region, sets up
- conflict hard registers for each allocno and info about calls
- the allocno lives through (file ira-lives.c).
- * IRA removes low register pressure loops from the regions
- mostly to speed IRA up (file ira-build.c).
- * IRA propagates accumulated allocno info from lower region
- allocnos to corresponding upper region allocnos (file
- ira-build.c).
- * IRA creates all caps (file ira-build.c).
- * Having live-ranges of allocnos and their classes, IRA creates
- conflicting allocnos for each allocno. Conflicting allocnos
- are stored as a bit vector or array of pointers to the
- conflicting allocnos whatever is more profitable (file
- ira-conflicts.c). At this point IRA creates allocno copies.
- o Coloring. Now IRA has all necessary info to start graph coloring
- process. It is done in each region on top-down traverse of the
- region tree (file ira-color.c). There are following subpasses:
- * Finding profitable hard registers of corresponding allocno
- class for each allocno. For example, only callee-saved hard
- registers are frequently profitable for allocnos living
- through colors. If the profitable hard register set of
- allocno does not form a tree based on subset relation, we use
- some approximation to form the tree. This approximation is
- used to figure out trivial colorability of allocnos. The
- approximation is a pretty rare case.
- * Putting allocnos onto the coloring stack. IRA uses Briggs
- optimistic coloring which is a major improvement over
- Chaitin's coloring. Therefore IRA does not spill allocnos at
- this point. There is some freedom in the order of putting
- allocnos on the stack which can affect the final result of
- the allocation. IRA uses some heuristics to improve the
- order. The major one is to form *threads* from colorable
- allocnos and push them on the stack by threads. Thread is a
- set of non-conflicting colorable allocnos connected by
- copies. The thread contains allocnos from the colorable
- bucket or colorable allocnos already pushed onto the coloring
- stack. Pushing thread allocnos one after another onto the
- stack increases chances of removing copies when the allocnos
- get the same hard reg.
-
- We also use a modification of Chaitin-Briggs algorithm which
- works for intersected register classes of allocnos. To
- figure out trivial colorability of allocnos, the mentioned
- above tree of hard register sets is used. To get an idea how
- the algorithm works in i386 example, let us consider an
- allocno to which any general hard register can be assigned.
- If the allocno conflicts with eight allocnos to which only
- EAX register can be assigned, given allocno is still
- trivially colorable because all conflicting allocnos might be
- assigned only to EAX and all other general hard registers are
- still free.
- To get an idea of the used trivial colorability criterion, it
- is also useful to read article "Graph-Coloring Register
- Allocation for Irregular Architectures" by Michael D. Smith
- and Glen Holloway. Major difference between the article
- approach and approach used in IRA is that Smith's approach
- takes register classes only from machine description and IRA
- calculate register classes from intermediate code too
- (e.g. an explicit usage of hard registers in RTL code for
- parameter passing can result in creation of additional
- register classes which contain or exclude the hard
- registers). That makes IRA approach useful for improving
- coloring even for architectures with regular register files
- and in fact some benchmarking shows the improvement for
- regular class architectures is even bigger than for irregular
- ones. Another difference is that Smith's approach chooses
- intersection of classes of all insn operands in which a given
- pseudo occurs. IRA can use bigger classes if it is still
- more profitable than memory usage.
- * Popping the allocnos from the stack and assigning them hard
- registers. If IRA can not assign a hard register to an
- allocno and the allocno is coalesced, IRA undoes the
- coalescing and puts the uncoalesced allocnos onto the stack in
- the hope that some such allocnos will get a hard register
- separately. If IRA fails to assign hard register or memory
- is more profitable for it, IRA spills the allocno. IRA
- assigns the allocno the hard-register with minimal full
- allocation cost which reflects the cost of usage of the
- hard-register for the allocno and cost of usage of the
- hard-register for allocnos conflicting with given allocno.
- * Chaitin-Briggs coloring assigns as many pseudos as possible
- to hard registers. After coloring we try to improve
- allocation with cost point of view. We improve the
- allocation by spilling some allocnos and assigning the freed
- hard registers to other allocnos if it decreases the overall
- allocation cost.
- * After allocno assigning in the region, IRA modifies the hard
- register and memory costs for the corresponding allocnos in
- the subregions to reflect the cost of possible loads, stores,
- or moves on the border of the region and its subregions.
- When default regional allocation algorithm is used
- (-fira-algorithm=mixed), IRA just propagates the assignment
- for allocnos if the register pressure in the region for the
- corresponding pressure class is less than number of available
- hard registers for given pressure class.
- o Spill/restore code moving. When IRA performs an allocation
- by traversing regions in top-down order, it does not know what
- happens below in the region tree. Therefore, sometimes IRA
- misses opportunities to perform a better allocation. A simple
- optimization tries to improve allocation in a region having
- subregions and containing in another region. If the
- corresponding allocnos in the subregion are spilled, it spills
- the region allocno if it is profitable. The optimization
- implements a simple iterative algorithm performing profitable
- transformations while they are still possible. It is fast in
- practice, so there is no real need for a better time complexity
- algorithm.
- o Code change. After coloring, two allocnos representing the
- same pseudo-register outside and inside a region respectively
- may be assigned to different locations (hard-registers or
- memory). In this case IRA creates and uses a new
- pseudo-register inside the region and adds code to move allocno
- values on the region's borders. This is done during top-down
- traversal of the regions (file ira-emit.c). In some
- complicated cases IRA can create a new allocno to move allocno
- values (e.g. when a swap of values stored in two hard-registers
- is needed). At this stage, the new allocno is marked as
- spilled. IRA still creates the pseudo-register and the moves
- on the region borders even when both allocnos were assigned to
- the same hard-register. If the reload pass spills a
- pseudo-register for some reason, the effect will be smaller
- because another allocno will still be in the hard-register. In
- most cases, this is better then spilling both allocnos. If
- reload does not change the allocation for the two
- pseudo-registers, the trivial move will be removed by
- post-reload optimizations. IRA does not generate moves for
- allocnos assigned to the same hard register when the default
- regional allocation algorithm is used and the register pressure
- in the region for the corresponding pressure class is less than
- number of available hard registers for given pressure class.
- IRA also does some optimizations to remove redundant stores and
- to reduce code duplication on the region borders.
- o Flattening internal representation. After changing code, IRA
- transforms its internal representation for several regions into
- one region representation (file ira-build.c). This process is
- called IR flattening. Such process is more complicated than IR
- rebuilding would be, but is much faster.
- o After IR flattening, IRA tries to assign hard registers to all
- spilled allocnos. This is implemented by a simple and fast
- priority coloring algorithm (see function
- ira_reassign_conflict_allocnos::ira-color.c). Here new allocnos
- created during the code change pass can be assigned to hard
- registers.
- o At the end IRA calls the reload pass. The reload pass
- communicates with IRA through several functions in file
- ira-color.c to improve its decisions in
- * sharing stack slots for the spilled pseudos based on IRA info
- about pseudo-register conflicts.
- * reassigning hard-registers to all spilled pseudos at the end
- of each reload iteration.
- * choosing a better hard-register to spill based on IRA info
- about pseudo-register live ranges and the register pressure
- in places where the pseudo-register lives.
- IRA uses a lot of data representing the target processors. These
- data are initialized in file ira.c.
- If function has no loops (or the loops are ignored when
- -fira-algorithm=CB is used), we have classic Chaitin-Briggs
- coloring (only instead of separate pass of coalescing, we use hard
- register preferencing). In such case, IRA works much faster
- because many things are not made (like IR flattening, the
- spill/restore optimization, and the code change).
- Literature is worth to read for better understanding the code:
- o Preston Briggs, Keith D. Cooper, Linda Torczon. Improvements to
- Graph Coloring Register Allocation.
- o David Callahan, Brian Koblenz. Register allocation via
- hierarchical graph coloring.
- o Keith Cooper, Anshuman Dasgupta, Jason Eckhardt. Revisiting Graph
- Coloring Register Allocation: A Study of the Chaitin-Briggs and
- Callahan-Koblenz Algorithms.
- o Guei-Yuan Lueh, Thomas Gross, and Ali-Reza Adl-Tabatabai. Global
- Register Allocation Based on Graph Fusion.
- o Michael D. Smith and Glenn Holloway. Graph-Coloring Register
- Allocation for Irregular Architectures
- o Vladimir Makarov. The Integrated Register Allocator for GCC.
- o Vladimir Makarov. The top-down register allocator for irregular
- register file architectures.
- */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "regs.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "rtl.h"
- #include "tm_p.h"
- #include "target.h"
- #include "flags.h"
- #include "obstack.h"
- #include "bitmap.h"
- #include "hard-reg-set.h"
- #include "predict.h"
- #include "function.h"
- #include "dominance.h"
- #include "cfg.h"
- #include "cfgrtl.h"
- #include "cfgbuild.h"
- #include "cfgcleanup.h"
- #include "basic-block.h"
- #include "df.h"
- #include "hashtab.h"
- #include "statistics.h"
- #include "real.h"
- #include "fixed-value.h"
- #include "insn-config.h"
- #include "expmed.h"
- #include "dojump.h"
- #include "explow.h"
- #include "calls.h"
- #include "emit-rtl.h"
- #include "varasm.h"
- #include "stmt.h"
- #include "expr.h"
- #include "recog.h"
- #include "params.h"
- #include "tree-pass.h"
- #include "output.h"
- #include "except.h"
- #include "reload.h"
- #include "diagnostic-core.h"
- #include "ggc.h"
- #include "ira-int.h"
- #include "lra.h"
- #include "dce.h"
- #include "dbgcnt.h"
- #include "rtl-iter.h"
- #include "shrink-wrap.h"
- struct target_ira default_target_ira;
- struct target_ira_int default_target_ira_int;
- #if SWITCHABLE_TARGET
- struct target_ira *this_target_ira = &default_target_ira;
- struct target_ira_int *this_target_ira_int = &default_target_ira_int;
- #endif
- /* A modified value of flag `-fira-verbose' used internally. */
- int internal_flag_ira_verbose;
- /* Dump file of the allocator if it is not NULL. */
- FILE *ira_dump_file;
- /* The number of elements in the following array. */
- int ira_spilled_reg_stack_slots_num;
- /* The following array contains info about spilled pseudo-registers
- stack slots used in current function so far. */
- struct ira_spilled_reg_stack_slot *ira_spilled_reg_stack_slots;
- /* Correspondingly overall cost of the allocation, overall cost before
- reload, cost of the allocnos assigned to hard-registers, cost of
- the allocnos assigned to memory, cost of loads, stores and register
- move insns generated for pseudo-register live range splitting (see
- ira-emit.c). */
- int64_t ira_overall_cost, overall_cost_before;
- int64_t ira_reg_cost, ira_mem_cost;
- int64_t ira_load_cost, ira_store_cost, ira_shuffle_cost;
- int ira_move_loops_num, ira_additional_jumps_num;
- /* All registers that can be eliminated. */
- HARD_REG_SET eliminable_regset;
- /* Value of max_reg_num () before IRA work start. This value helps
- us to recognize a situation when new pseudos were created during
- IRA work. */
- static int max_regno_before_ira;
- /* Temporary hard reg set used for a different calculation. */
- static HARD_REG_SET temp_hard_regset;
- #define last_mode_for_init_move_cost \
- (this_target_ira_int->x_last_mode_for_init_move_cost)
- /* The function sets up the map IRA_REG_MODE_HARD_REGSET. */
- static void
- setup_reg_mode_hard_regset (void)
- {
- int i, m, hard_regno;
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- for (hard_regno = 0; hard_regno < FIRST_PSEUDO_REGISTER; hard_regno++)
- {
- CLEAR_HARD_REG_SET (ira_reg_mode_hard_regset[hard_regno][m]);
- for (i = hard_regno_nregs[hard_regno][m] - 1; i >= 0; i--)
- if (hard_regno + i < FIRST_PSEUDO_REGISTER)
- SET_HARD_REG_BIT (ira_reg_mode_hard_regset[hard_regno][m],
- hard_regno + i);
- }
- }
- #define no_unit_alloc_regs \
- (this_target_ira_int->x_no_unit_alloc_regs)
- /* The function sets up the three arrays declared above. */
- static void
- setup_class_hard_regs (void)
- {
- int cl, i, hard_regno, n;
- HARD_REG_SET processed_hard_reg_set;
- ira_assert (SHRT_MAX >= FIRST_PSEUDO_REGISTER);
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- CLEAR_HARD_REG_SET (processed_hard_reg_set);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- ira_non_ordered_class_hard_regs[cl][i] = -1;
- ira_class_hard_reg_index[cl][i] = -1;
- }
- for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- #ifdef REG_ALLOC_ORDER
- hard_regno = reg_alloc_order[i];
- #else
- hard_regno = i;
- #endif
- if (TEST_HARD_REG_BIT (processed_hard_reg_set, hard_regno))
- continue;
- SET_HARD_REG_BIT (processed_hard_reg_set, hard_regno);
- if (! TEST_HARD_REG_BIT (temp_hard_regset, hard_regno))
- ira_class_hard_reg_index[cl][hard_regno] = -1;
- else
- {
- ira_class_hard_reg_index[cl][hard_regno] = n;
- ira_class_hard_regs[cl][n++] = hard_regno;
- }
- }
- ira_class_hard_regs_num[cl] = n;
- for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (temp_hard_regset, i))
- ira_non_ordered_class_hard_regs[cl][n++] = i;
- ira_assert (ira_class_hard_regs_num[cl] == n);
- }
- }
- /* Set up global variables defining info about hard registers for the
- allocation. These depend on USE_HARD_FRAME_P whose TRUE value means
- that we can use the hard frame pointer for the allocation. */
- static void
- setup_alloc_regs (bool use_hard_frame_p)
- {
- #ifdef ADJUST_REG_ALLOC_ORDER
- ADJUST_REG_ALLOC_ORDER;
- #endif
- COPY_HARD_REG_SET (no_unit_alloc_regs, fixed_reg_set);
- if (! use_hard_frame_p)
- SET_HARD_REG_BIT (no_unit_alloc_regs, HARD_FRAME_POINTER_REGNUM);
- setup_class_hard_regs ();
- }
- #define alloc_reg_class_subclasses \
- (this_target_ira_int->x_alloc_reg_class_subclasses)
- /* Initialize the table of subclasses of each reg class. */
- static void
- setup_reg_subclasses (void)
- {
- int i, j;
- HARD_REG_SET temp_hard_regset2;
- for (i = 0; i < N_REG_CLASSES; i++)
- for (j = 0; j < N_REG_CLASSES; j++)
- alloc_reg_class_subclasses[i][j] = LIM_REG_CLASSES;
- for (i = 0; i < N_REG_CLASSES; i++)
- {
- if (i == (int) NO_REGS)
- continue;
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- if (hard_reg_set_empty_p (temp_hard_regset))
- continue;
- for (j = 0; j < N_REG_CLASSES; j++)
- if (i != j)
- {
- enum reg_class *p;
- COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[j]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
- if (! hard_reg_set_subset_p (temp_hard_regset,
- temp_hard_regset2))
- continue;
- p = &alloc_reg_class_subclasses[j][0];
- while (*p != LIM_REG_CLASSES) p++;
- *p = (enum reg_class) i;
- }
- }
- }
- /* Set up IRA_MEMORY_MOVE_COST and IRA_MAX_MEMORY_MOVE_COST. */
- static void
- setup_class_subset_and_memory_move_costs (void)
- {
- int cl, cl2, mode, cost;
- HARD_REG_SET temp_hard_regset2;
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- ira_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][NO_REGS][1] = SHRT_MAX;
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- if (cl != (int) NO_REGS)
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- ira_max_memory_move_cost[mode][cl][0]
- = ira_memory_move_cost[mode][cl][0]
- = memory_move_cost ((machine_mode) mode,
- (reg_class_t) cl, false);
- ira_max_memory_move_cost[mode][cl][1]
- = ira_memory_move_cost[mode][cl][1]
- = memory_move_cost ((machine_mode) mode,
- (reg_class_t) cl, true);
- /* Costs for NO_REGS are used in cost calculation on the
- 1st pass when the preferred register classes are not
- known yet. In this case we take the best scenario. */
- if (ira_memory_move_cost[mode][NO_REGS][0]
- > ira_memory_move_cost[mode][cl][0])
- ira_max_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][NO_REGS][0]
- = ira_memory_move_cost[mode][cl][0];
- if (ira_memory_move_cost[mode][NO_REGS][1]
- > ira_memory_move_cost[mode][cl][1])
- ira_max_memory_move_cost[mode][NO_REGS][1]
- = ira_memory_move_cost[mode][NO_REGS][1]
- = ira_memory_move_cost[mode][cl][1];
- }
- }
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (cl2 = (int) N_REG_CLASSES - 1; cl2 >= 0; cl2--)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
- ira_class_subset_p[cl][cl2]
- = hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2);
- if (! hard_reg_set_empty_p (temp_hard_regset2)
- && hard_reg_set_subset_p (reg_class_contents[cl2],
- reg_class_contents[cl]))
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- cost = ira_memory_move_cost[mode][cl2][0];
- if (cost > ira_max_memory_move_cost[mode][cl][0])
- ira_max_memory_move_cost[mode][cl][0] = cost;
- cost = ira_memory_move_cost[mode][cl2][1];
- if (cost > ira_max_memory_move_cost[mode][cl][1])
- ira_max_memory_move_cost[mode][cl][1] = cost;
- }
- }
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- ira_memory_move_cost[mode][cl][0]
- = ira_max_memory_move_cost[mode][cl][0];
- ira_memory_move_cost[mode][cl][1]
- = ira_max_memory_move_cost[mode][cl][1];
- }
- setup_reg_subclasses ();
- }
- /* Define the following macro if allocation through malloc if
- preferable. */
- #define IRA_NO_OBSTACK
- #ifndef IRA_NO_OBSTACK
- /* Obstack used for storing all dynamic data (except bitmaps) of the
- IRA. */
- static struct obstack ira_obstack;
- #endif
- /* Obstack used for storing all bitmaps of the IRA. */
- static struct bitmap_obstack ira_bitmap_obstack;
- /* Allocate memory of size LEN for IRA data. */
- void *
- ira_allocate (size_t len)
- {
- void *res;
- #ifndef IRA_NO_OBSTACK
- res = obstack_alloc (&ira_obstack, len);
- #else
- res = xmalloc (len);
- #endif
- return res;
- }
- /* Free memory ADDR allocated for IRA data. */
- void
- ira_free (void *addr ATTRIBUTE_UNUSED)
- {
- #ifndef IRA_NO_OBSTACK
- /* do nothing */
- #else
- free (addr);
- #endif
- }
- /* Allocate and returns bitmap for IRA. */
- bitmap
- ira_allocate_bitmap (void)
- {
- return BITMAP_ALLOC (&ira_bitmap_obstack);
- }
- /* Free bitmap B allocated for IRA. */
- void
- ira_free_bitmap (bitmap b ATTRIBUTE_UNUSED)
- {
- /* do nothing */
- }
- /* Output information about allocation of all allocnos (except for
- caps) into file F. */
- void
- ira_print_disposition (FILE *f)
- {
- int i, n, max_regno;
- ira_allocno_t a;
- basic_block bb;
- fprintf (f, "Disposition:");
- max_regno = max_reg_num ();
- for (n = 0, i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- for (a = ira_regno_allocno_map[i];
- a != NULL;
- a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
- {
- if (n % 4 == 0)
- fprintf (f, "\n");
- n++;
- fprintf (f, " %4d:r%-4d", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
- if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
- fprintf (f, "b%-3d", bb->index);
- else
- fprintf (f, "l%-3d", ALLOCNO_LOOP_TREE_NODE (a)->loop_num);
- if (ALLOCNO_HARD_REGNO (a) >= 0)
- fprintf (f, " %3d", ALLOCNO_HARD_REGNO (a));
- else
- fprintf (f, " mem");
- }
- fprintf (f, "\n");
- }
- /* Outputs information about allocation of all allocnos into
- stderr. */
- void
- ira_debug_disposition (void)
- {
- ira_print_disposition (stderr);
- }
- /* Set up ira_stack_reg_pressure_class which is the biggest pressure
- register class containing stack registers or NO_REGS if there are
- no stack registers. To find this class, we iterate through all
- register pressure classes and choose the first register pressure
- class containing all the stack registers and having the biggest
- size. */
- static void
- setup_stack_reg_pressure_class (void)
- {
- ira_stack_reg_pressure_class = NO_REGS;
- #ifdef STACK_REGS
- {
- int i, best, size;
- enum reg_class cl;
- HARD_REG_SET temp_hard_regset2;
- CLEAR_HARD_REG_SET (temp_hard_regset);
- for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
- SET_HARD_REG_BIT (temp_hard_regset, i);
- best = 0;
- for (i = 0; i < ira_pressure_classes_num; i++)
- {
- cl = ira_pressure_classes[i];
- COPY_HARD_REG_SET (temp_hard_regset2, temp_hard_regset);
- AND_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]);
- size = hard_reg_set_size (temp_hard_regset2);
- if (best < size)
- {
- best = size;
- ira_stack_reg_pressure_class = cl;
- }
- }
- }
- #endif
- }
- /* Find pressure classes which are register classes for which we
- calculate register pressure in IRA, register pressure sensitive
- insn scheduling, and register pressure sensitive loop invariant
- motion.
- To make register pressure calculation easy, we always use
- non-intersected register pressure classes. A move of hard
- registers from one register pressure class is not more expensive
- than load and store of the hard registers. Most likely an allocno
- class will be a subset of a register pressure class and in many
- cases a register pressure class. That makes usage of register
- pressure classes a good approximation to find a high register
- pressure. */
- static void
- setup_pressure_classes (void)
- {
- int cost, i, n, curr;
- int cl, cl2;
- enum reg_class pressure_classes[N_REG_CLASSES];
- int m;
- HARD_REG_SET temp_hard_regset2;
- bool insert_p;
- n = 0;
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- if (ira_class_hard_regs_num[cl] == 0)
- continue;
- if (ira_class_hard_regs_num[cl] != 1
- /* A register class without subclasses may contain a few
- hard registers and movement between them is costly
- (e.g. SPARC FPCC registers). We still should consider it
- as a candidate for a pressure class. */
- && alloc_reg_class_subclasses[cl][0] < cl)
- {
- /* Check that the moves between any hard registers of the
- current class are not more expensive for a legal mode
- than load/store of the hard registers of the current
- class. Such class is a potential candidate to be a
- register pressure class. */
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- AND_COMPL_HARD_REG_SET (temp_hard_regset,
- ira_prohibited_class_mode_regs[cl][m]);
- if (hard_reg_set_empty_p (temp_hard_regset))
- continue;
- ira_init_register_move_cost_if_necessary ((machine_mode) m);
- cost = ira_register_move_cost[m][cl][cl];
- if (cost <= ira_max_memory_move_cost[m][cl][1]
- || cost <= ira_max_memory_move_cost[m][cl][0])
- break;
- }
- if (m >= NUM_MACHINE_MODES)
- continue;
- }
- curr = 0;
- insert_p = true;
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- /* Remove so far added pressure classes which are subset of the
- current candidate class. Prefer GENERAL_REGS as a pressure
- register class to another class containing the same
- allocatable hard registers. We do this because machine
- dependent cost hooks might give wrong costs for the latter
- class but always give the right cost for the former class
- (GENERAL_REGS). */
- for (i = 0; i < n; i++)
- {
- cl2 = pressure_classes[i];
- COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
- if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2)
- && (! hard_reg_set_equal_p (temp_hard_regset, temp_hard_regset2)
- || cl2 == (int) GENERAL_REGS))
- {
- pressure_classes[curr++] = (enum reg_class) cl2;
- insert_p = false;
- continue;
- }
- if (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset)
- && (! hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset)
- || cl == (int) GENERAL_REGS))
- continue;
- if (hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset))
- insert_p = false;
- pressure_classes[curr++] = (enum reg_class) cl2;
- }
- /* If the current candidate is a subset of a so far added
- pressure class, don't add it to the list of the pressure
- classes. */
- if (insert_p)
- pressure_classes[curr++] = (enum reg_class) cl;
- n = curr;
- }
- #ifdef ENABLE_IRA_CHECKING
- {
- HARD_REG_SET ignore_hard_regs;
- /* Check pressure classes correctness: here we check that hard
- registers from all register pressure classes contains all hard
- registers available for the allocation. */
- CLEAR_HARD_REG_SET (temp_hard_regset);
- CLEAR_HARD_REG_SET (temp_hard_regset2);
- COPY_HARD_REG_SET (ignore_hard_regs, no_unit_alloc_regs);
- for (cl = 0; cl < LIM_REG_CLASSES; cl++)
- {
- /* For some targets (like MIPS with MD_REGS), there are some
- classes with hard registers available for allocation but
- not able to hold value of any mode. */
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- if (contains_reg_of_mode[cl][m])
- break;
- if (m >= NUM_MACHINE_MODES)
- {
- IOR_HARD_REG_SET (ignore_hard_regs, reg_class_contents[cl]);
- continue;
- }
- for (i = 0; i < n; i++)
- if ((int) pressure_classes[i] == cl)
- break;
- IOR_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]);
- if (i < n)
- IOR_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- }
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- /* Some targets (like SPARC with ICC reg) have allocatable regs
- for which no reg class is defined. */
- if (REGNO_REG_CLASS (i) == NO_REGS)
- SET_HARD_REG_BIT (ignore_hard_regs, i);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, ignore_hard_regs);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, ignore_hard_regs);
- ira_assert (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset));
- }
- #endif
- ira_pressure_classes_num = 0;
- for (i = 0; i < n; i++)
- {
- cl = (int) pressure_classes[i];
- ira_reg_pressure_class_p[cl] = true;
- ira_pressure_classes[ira_pressure_classes_num++] = (enum reg_class) cl;
- }
- setup_stack_reg_pressure_class ();
- }
- /* Set up IRA_UNIFORM_CLASS_P. Uniform class is a register class
- whose register move cost between any registers of the class is the
- same as for all its subclasses. We use the data to speed up the
- 2nd pass of calculations of allocno costs. */
- static void
- setup_uniform_class_p (void)
- {
- int i, cl, cl2, m;
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- ira_uniform_class_p[cl] = false;
- if (ira_class_hard_regs_num[cl] == 0)
- continue;
- /* We can not use alloc_reg_class_subclasses here because move
- cost hooks does not take into account that some registers are
- unavailable for the subtarget. E.g. for i686, INT_SSE_REGS
- is element of alloc_reg_class_subclasses for GENERAL_REGS
- because SSE regs are unavailable. */
- for (i = 0; (cl2 = reg_class_subclasses[cl][i]) != LIM_REG_CLASSES; i++)
- {
- if (ira_class_hard_regs_num[cl2] == 0)
- continue;
- for (m = 0; m < NUM_MACHINE_MODES; m++)
- if (contains_reg_of_mode[cl][m] && contains_reg_of_mode[cl2][m])
- {
- ira_init_register_move_cost_if_necessary ((machine_mode) m);
- if (ira_register_move_cost[m][cl][cl]
- != ira_register_move_cost[m][cl2][cl2])
- break;
- }
- if (m < NUM_MACHINE_MODES)
- break;
- }
- if (cl2 == LIM_REG_CLASSES)
- ira_uniform_class_p[cl] = true;
- }
- }
- /* Set up IRA_ALLOCNO_CLASSES, IRA_ALLOCNO_CLASSES_NUM,
- IRA_IMPORTANT_CLASSES, and IRA_IMPORTANT_CLASSES_NUM.
- Target may have many subtargets and not all target hard registers can
- be used for allocation, e.g. x86 port in 32-bit mode can not use
- hard registers introduced in x86-64 like r8-r15). Some classes
- might have the same allocatable hard registers, e.g. INDEX_REGS
- and GENERAL_REGS in x86 port in 32-bit mode. To decrease different
- calculations efforts we introduce allocno classes which contain
- unique non-empty sets of allocatable hard-registers.
- Pseudo class cost calculation in ira-costs.c is very expensive.
- Therefore we are trying to decrease number of classes involved in
- such calculation. Register classes used in the cost calculation
- are called important classes. They are allocno classes and other
- non-empty classes whose allocatable hard register sets are inside
- of an allocno class hard register set. From the first sight, it
- looks like that they are just allocno classes. It is not true. In
- example of x86-port in 32-bit mode, allocno classes will contain
- GENERAL_REGS but not LEGACY_REGS (because allocatable hard
- registers are the same for the both classes). The important
- classes will contain GENERAL_REGS and LEGACY_REGS. It is done
- because a machine description insn constraint may refers for
- LEGACY_REGS and code in ira-costs.c is mostly base on investigation
- of the insn constraints. */
- static void
- setup_allocno_and_important_classes (void)
- {
- int i, j, n, cl;
- bool set_p;
- HARD_REG_SET temp_hard_regset2;
- static enum reg_class classes[LIM_REG_CLASSES + 1];
- n = 0;
- /* Collect classes which contain unique sets of allocatable hard
- registers. Prefer GENERAL_REGS to other classes containing the
- same set of hard registers. */
- for (i = 0; i < LIM_REG_CLASSES; i++)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[i]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- for (j = 0; j < n; j++)
- {
- cl = classes[j];
- COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2,
- no_unit_alloc_regs);
- if (hard_reg_set_equal_p (temp_hard_regset,
- temp_hard_regset2))
- break;
- }
- if (j >= n)
- classes[n++] = (enum reg_class) i;
- else if (i == GENERAL_REGS)
- /* Prefer general regs. For i386 example, it means that
- we prefer GENERAL_REGS over INDEX_REGS or LEGACY_REGS
- (all of them consists of the same available hard
- registers). */
- classes[j] = (enum reg_class) i;
- }
- classes[n] = LIM_REG_CLASSES;
- /* Set up classes which can be used for allocnos as classes
- containing non-empty unique sets of allocatable hard
- registers. */
- ira_allocno_classes_num = 0;
- for (i = 0; (cl = classes[i]) != LIM_REG_CLASSES; i++)
- if (ira_class_hard_regs_num[cl] > 0)
- ira_allocno_classes[ira_allocno_classes_num++] = (enum reg_class) cl;
- ira_important_classes_num = 0;
- /* Add non-allocno classes containing to non-empty set of
- allocatable hard regs. */
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- if (ira_class_hard_regs_num[cl] > 0)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- set_p = false;
- for (j = 0; j < ira_allocno_classes_num; j++)
- {
- COPY_HARD_REG_SET (temp_hard_regset2,
- reg_class_contents[ira_allocno_classes[j]]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
- if ((enum reg_class) cl == ira_allocno_classes[j])
- break;
- else if (hard_reg_set_subset_p (temp_hard_regset,
- temp_hard_regset2))
- set_p = true;
- }
- if (set_p && j >= ira_allocno_classes_num)
- ira_important_classes[ira_important_classes_num++]
- = (enum reg_class) cl;
- }
- /* Now add allocno classes to the important classes. */
- for (j = 0; j < ira_allocno_classes_num; j++)
- ira_important_classes[ira_important_classes_num++]
- = ira_allocno_classes[j];
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- ira_reg_allocno_class_p[cl] = false;
- ira_reg_pressure_class_p[cl] = false;
- }
- for (j = 0; j < ira_allocno_classes_num; j++)
- ira_reg_allocno_class_p[ira_allocno_classes[j]] = true;
- setup_pressure_classes ();
- setup_uniform_class_p ();
- }
- /* Setup translation in CLASS_TRANSLATE of all classes into a class
- given by array CLASSES of length CLASSES_NUM. The function is used
- make translation any reg class to an allocno class or to an
- pressure class. This translation is necessary for some
- calculations when we can use only allocno or pressure classes and
- such translation represents an approximate representation of all
- classes.
- The translation in case when allocatable hard register set of a
- given class is subset of allocatable hard register set of a class
- in CLASSES is pretty simple. We use smallest classes from CLASSES
- containing a given class. If allocatable hard register set of a
- given class is not a subset of any corresponding set of a class
- from CLASSES, we use the cheapest (with load/store point of view)
- class from CLASSES whose set intersects with given class set. */
- static void
- setup_class_translate_array (enum reg_class *class_translate,
- int classes_num, enum reg_class *classes)
- {
- int cl, mode;
- enum reg_class aclass, best_class, *cl_ptr;
- int i, cost, min_cost, best_cost;
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- class_translate[cl] = NO_REGS;
- for (i = 0; i < classes_num; i++)
- {
- aclass = classes[i];
- for (cl_ptr = &alloc_reg_class_subclasses[aclass][0];
- (cl = *cl_ptr) != LIM_REG_CLASSES;
- cl_ptr++)
- if (class_translate[cl] == NO_REGS)
- class_translate[cl] = aclass;
- class_translate[aclass] = aclass;
- }
- /* For classes which are not fully covered by one of given classes
- (in other words covered by more one given class), use the
- cheapest class. */
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- if (cl == NO_REGS || class_translate[cl] != NO_REGS)
- continue;
- best_class = NO_REGS;
- best_cost = INT_MAX;
- for (i = 0; i < classes_num; i++)
- {
- aclass = classes[i];
- COPY_HARD_REG_SET (temp_hard_regset,
- reg_class_contents[aclass]);
- AND_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- if (! hard_reg_set_empty_p (temp_hard_regset))
- {
- min_cost = INT_MAX;
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- {
- cost = (ira_memory_move_cost[mode][aclass][0]
- + ira_memory_move_cost[mode][aclass][1]);
- if (min_cost > cost)
- min_cost = cost;
- }
- if (best_class == NO_REGS || best_cost > min_cost)
- {
- best_class = aclass;
- best_cost = min_cost;
- }
- }
- }
- class_translate[cl] = best_class;
- }
- }
- /* Set up array IRA_ALLOCNO_CLASS_TRANSLATE and
- IRA_PRESSURE_CLASS_TRANSLATE. */
- static void
- setup_class_translate (void)
- {
- setup_class_translate_array (ira_allocno_class_translate,
- ira_allocno_classes_num, ira_allocno_classes);
- setup_class_translate_array (ira_pressure_class_translate,
- ira_pressure_classes_num, ira_pressure_classes);
- }
- /* Order numbers of allocno classes in original target allocno class
- array, -1 for non-allocno classes. */
- static int allocno_class_order[N_REG_CLASSES];
- /* The function used to sort the important classes. */
- static int
- comp_reg_classes_func (const void *v1p, const void *v2p)
- {
- enum reg_class cl1 = *(const enum reg_class *) v1p;
- enum reg_class cl2 = *(const enum reg_class *) v2p;
- enum reg_class tcl1, tcl2;
- int diff;
- tcl1 = ira_allocno_class_translate[cl1];
- tcl2 = ira_allocno_class_translate[cl2];
- if (tcl1 != NO_REGS && tcl2 != NO_REGS
- && (diff = allocno_class_order[tcl1] - allocno_class_order[tcl2]) != 0)
- return diff;
- return (int) cl1 - (int) cl2;
- }
- /* For correct work of function setup_reg_class_relation we need to
- reorder important classes according to the order of their allocno
- classes. It places important classes containing the same
- allocatable hard register set adjacent to each other and allocno
- class with the allocatable hard register set right after the other
- important classes with the same set.
- In example from comments of function
- setup_allocno_and_important_classes, it places LEGACY_REGS and
- GENERAL_REGS close to each other and GENERAL_REGS is after
- LEGACY_REGS. */
- static void
- reorder_important_classes (void)
- {
- int i;
- for (i = 0; i < N_REG_CLASSES; i++)
- allocno_class_order[i] = -1;
- for (i = 0; i < ira_allocno_classes_num; i++)
- allocno_class_order[ira_allocno_classes[i]] = i;
- qsort (ira_important_classes, ira_important_classes_num,
- sizeof (enum reg_class), comp_reg_classes_func);
- for (i = 0; i < ira_important_classes_num; i++)
- ira_important_class_nums[ira_important_classes[i]] = i;
- }
- /* Set up IRA_REG_CLASS_SUBUNION, IRA_REG_CLASS_SUPERUNION,
- IRA_REG_CLASS_SUPER_CLASSES, IRA_REG_CLASSES_INTERSECT, and
- IRA_REG_CLASSES_INTERSECT_P. For the meaning of the relations,
- please see corresponding comments in ira-int.h. */
- static void
- setup_reg_class_relations (void)
- {
- int i, cl1, cl2, cl3;
- HARD_REG_SET intersection_set, union_set, temp_set2;
- bool important_class_p[N_REG_CLASSES];
- memset (important_class_p, 0, sizeof (important_class_p));
- for (i = 0; i < ira_important_classes_num; i++)
- important_class_p[ira_important_classes[i]] = true;
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- {
- ira_reg_class_super_classes[cl1][0] = LIM_REG_CLASSES;
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- ira_reg_classes_intersect_p[cl1][cl2] = false;
- ira_reg_class_intersect[cl1][cl2] = NO_REGS;
- ira_reg_class_subset[cl1][cl2] = NO_REGS;
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl1]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- COPY_HARD_REG_SET (temp_set2, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (hard_reg_set_empty_p (temp_hard_regset)
- && hard_reg_set_empty_p (temp_set2))
- {
- /* The both classes have no allocatable hard registers
- -- take all class hard registers into account and use
- reg_class_subunion and reg_class_superunion. */
- for (i = 0;; i++)
- {
- cl3 = reg_class_subclasses[cl1][i];
- if (cl3 == LIM_REG_CLASSES)
- break;
- if (reg_class_subset_p (ira_reg_class_intersect[cl1][cl2],
- (enum reg_class) cl3))
- ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
- }
- ira_reg_class_subunion[cl1][cl2] = reg_class_subunion[cl1][cl2];
- ira_reg_class_superunion[cl1][cl2] = reg_class_superunion[cl1][cl2];
- continue;
- }
- ira_reg_classes_intersect_p[cl1][cl2]
- = hard_reg_set_intersect_p (temp_hard_regset, temp_set2);
- if (important_class_p[cl1] && important_class_p[cl2]
- && hard_reg_set_subset_p (temp_hard_regset, temp_set2))
- {
- /* CL1 and CL2 are important classes and CL1 allocatable
- hard register set is inside of CL2 allocatable hard
- registers -- make CL1 a superset of CL2. */
- enum reg_class *p;
- p = &ira_reg_class_super_classes[cl1][0];
- while (*p != LIM_REG_CLASSES)
- p++;
- *p++ = (enum reg_class) cl2;
- *p = LIM_REG_CLASSES;
- }
- ira_reg_class_subunion[cl1][cl2] = NO_REGS;
- ira_reg_class_superunion[cl1][cl2] = NO_REGS;
- COPY_HARD_REG_SET (intersection_set, reg_class_contents[cl1]);
- AND_HARD_REG_SET (intersection_set, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (intersection_set, no_unit_alloc_regs);
- COPY_HARD_REG_SET (union_set, reg_class_contents[cl1]);
- IOR_HARD_REG_SET (union_set, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (union_set, no_unit_alloc_regs);
- for (cl3 = 0; cl3 < N_REG_CLASSES; cl3++)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl3]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- if (hard_reg_set_subset_p (temp_hard_regset, intersection_set))
- {
- /* CL3 allocatable hard register set is inside of
- intersection of allocatable hard register sets
- of CL1 and CL2. */
- if (important_class_p[cl3])
- {
- COPY_HARD_REG_SET
- (temp_set2,
- reg_class_contents
- [(int) ira_reg_class_intersect[cl1][cl2]]);
- AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- /* If the allocatable hard register sets are
- the same, prefer GENERAL_REGS or the
- smallest class for debugging
- purposes. */
- || (hard_reg_set_equal_p (temp_hard_regset, temp_set2)
- && (cl3 == GENERAL_REGS
- || ((ira_reg_class_intersect[cl1][cl2]
- != GENERAL_REGS)
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int)
- ira_reg_class_intersect[cl1][cl2]])))))
- ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
- }
- COPY_HARD_REG_SET
- (temp_set2,
- reg_class_contents[(int) ira_reg_class_subset[cl1][cl2]]);
- AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- /* Ignore unavailable hard registers and prefer
- smallest class for debugging purposes. */
- || (hard_reg_set_equal_p (temp_hard_regset, temp_set2)
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_subset[cl1][cl2]])))
- ira_reg_class_subset[cl1][cl2] = (enum reg_class) cl3;
- }
- if (important_class_p[cl3]
- && hard_reg_set_subset_p (temp_hard_regset, union_set))
- {
- /* CL3 allocatable hard register set is inside of
- union of allocatable hard register sets of CL1
- and CL2. */
- COPY_HARD_REG_SET
- (temp_set2,
- reg_class_contents[(int) ira_reg_class_subunion[cl1][cl2]]);
- AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (ira_reg_class_subunion[cl1][cl2] == NO_REGS
- || (hard_reg_set_subset_p (temp_set2, temp_hard_regset)
-
- && (! hard_reg_set_equal_p (temp_set2,
- temp_hard_regset)
- || cl3 == GENERAL_REGS
- /* If the allocatable hard register sets are the
- same, prefer GENERAL_REGS or the smallest
- class for debugging purposes. */
- || (ira_reg_class_subunion[cl1][cl2] != GENERAL_REGS
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_subunion[cl1][cl2]])))))
- ira_reg_class_subunion[cl1][cl2] = (enum reg_class) cl3;
- }
- if (hard_reg_set_subset_p (union_set, temp_hard_regset))
- {
- /* CL3 allocatable hard register set contains union
- of allocatable hard register sets of CL1 and
- CL2. */
- COPY_HARD_REG_SET
- (temp_set2,
- reg_class_contents[(int) ira_reg_class_superunion[cl1][cl2]]);
- AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (ira_reg_class_superunion[cl1][cl2] == NO_REGS
- || (hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- && (! hard_reg_set_equal_p (temp_set2,
- temp_hard_regset)
- || cl3 == GENERAL_REGS
- /* If the allocatable hard register sets are the
- same, prefer GENERAL_REGS or the smallest
- class for debugging purposes. */
- || (ira_reg_class_superunion[cl1][cl2] != GENERAL_REGS
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_superunion[cl1][cl2]])))))
- ira_reg_class_superunion[cl1][cl2] = (enum reg_class) cl3;
- }
- }
- }
- }
- }
- /* Output all uniform and important classes into file F. */
- static void
- print_unform_and_important_classes (FILE *f)
- {
- static const char *const reg_class_names[] = REG_CLASS_NAMES;
- int i, cl;
- fprintf (f, "Uniform classes:\n");
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- if (ira_uniform_class_p[cl])
- fprintf (f, " %s", reg_class_names[cl]);
- fprintf (f, "\nImportant classes:\n");
- for (i = 0; i < ira_important_classes_num; i++)
- fprintf (f, " %s", reg_class_names[ira_important_classes[i]]);
- fprintf (f, "\n");
- }
- /* Output all possible allocno or pressure classes and their
- translation map into file F. */
- static void
- print_translated_classes (FILE *f, bool pressure_p)
- {
- int classes_num = (pressure_p
- ? ira_pressure_classes_num : ira_allocno_classes_num);
- enum reg_class *classes = (pressure_p
- ? ira_pressure_classes : ira_allocno_classes);
- enum reg_class *class_translate = (pressure_p
- ? ira_pressure_class_translate
- : ira_allocno_class_translate);
- static const char *const reg_class_names[] = REG_CLASS_NAMES;
- int i;
- fprintf (f, "%s classes:\n", pressure_p ? "Pressure" : "Allocno");
- for (i = 0; i < classes_num; i++)
- fprintf (f, " %s", reg_class_names[classes[i]]);
- fprintf (f, "\nClass translation:\n");
- for (i = 0; i < N_REG_CLASSES; i++)
- fprintf (f, " %s -> %s\n", reg_class_names[i],
- reg_class_names[class_translate[i]]);
- }
- /* Output all possible allocno and translation classes and the
- translation maps into stderr. */
- void
- ira_debug_allocno_classes (void)
- {
- print_unform_and_important_classes (stderr);
- print_translated_classes (stderr, false);
- print_translated_classes (stderr, true);
- }
- /* Set up different arrays concerning class subsets, allocno and
- important classes. */
- static void
- find_reg_classes (void)
- {
- setup_allocno_and_important_classes ();
- setup_class_translate ();
- reorder_important_classes ();
- setup_reg_class_relations ();
- }
- /* Set up the array above. */
- static void
- setup_hard_regno_aclass (void)
- {
- int i;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- #if 1
- ira_hard_regno_allocno_class[i]
- = (TEST_HARD_REG_BIT (no_unit_alloc_regs, i)
- ? NO_REGS
- : ira_allocno_class_translate[REGNO_REG_CLASS (i)]);
- #else
- int j;
- enum reg_class cl;
- ira_hard_regno_allocno_class[i] = NO_REGS;
- for (j = 0; j < ira_allocno_classes_num; j++)
- {
- cl = ira_allocno_classes[j];
- if (ira_class_hard_reg_index[cl][i] >= 0)
- {
- ira_hard_regno_allocno_class[i] = cl;
- break;
- }
- }
- #endif
- }
- }
- /* Form IRA_REG_CLASS_MAX_NREGS and IRA_REG_CLASS_MIN_NREGS maps. */
- static void
- setup_reg_class_nregs (void)
- {
- int i, cl, cl2, m;
- for (m = 0; m < MAX_MACHINE_MODE; m++)
- {
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- ira_reg_class_max_nregs[cl][m]
- = ira_reg_class_min_nregs[cl][m]
- = targetm.class_max_nregs ((reg_class_t) cl, (machine_mode) m);
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- for (i = 0;
- (cl2 = alloc_reg_class_subclasses[cl][i]) != LIM_REG_CLASSES;
- i++)
- if (ira_reg_class_min_nregs[cl2][m]
- < ira_reg_class_min_nregs[cl][m])
- ira_reg_class_min_nregs[cl][m] = ira_reg_class_min_nregs[cl2][m];
- }
- }
- /* Set up IRA_PROHIBITED_CLASS_MODE_REGS and IRA_CLASS_SINGLETON.
- This function is called once IRA_CLASS_HARD_REGS has been initialized. */
- static void
- setup_prohibited_class_mode_regs (void)
- {
- int j, k, hard_regno, cl, last_hard_regno, count;
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- {
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- {
- count = 0;
- last_hard_regno = -1;
- CLEAR_HARD_REG_SET (ira_prohibited_class_mode_regs[cl][j]);
- for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
- {
- hard_regno = ira_class_hard_regs[cl][k];
- if (! HARD_REGNO_MODE_OK (hard_regno, (machine_mode) j))
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- else if (in_hard_reg_set_p (temp_hard_regset,
- (machine_mode) j, hard_regno))
- {
- last_hard_regno = hard_regno;
- count++;
- }
- }
- ira_class_singleton[cl][j] = (count == 1 ? last_hard_regno : -1);
- }
- }
- }
- /* Clarify IRA_PROHIBITED_CLASS_MODE_REGS by excluding hard registers
- spanning from one register pressure class to another one. It is
- called after defining the pressure classes. */
- static void
- clarify_prohibited_class_mode_regs (void)
- {
- int j, k, hard_regno, cl, pclass, nregs;
- for (cl = (int) N_REG_CLASSES - 1; cl >= 0; cl--)
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- {
- CLEAR_HARD_REG_SET (ira_useful_class_mode_regs[cl][j]);
- for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
- {
- hard_regno = ira_class_hard_regs[cl][k];
- if (TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j], hard_regno))
- continue;
- nregs = hard_regno_nregs[hard_regno][j];
- if (hard_regno + nregs > FIRST_PSEUDO_REGISTER)
- {
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- continue;
- }
- pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)];
- for (nregs-- ;nregs >= 0; nregs--)
- if (((enum reg_class) pclass
- != ira_pressure_class_translate[REGNO_REG_CLASS
- (hard_regno + nregs)]))
- {
- SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno);
- break;
- }
- if (!TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
- hard_regno))
- add_to_hard_reg_set (&ira_useful_class_mode_regs[cl][j],
- (machine_mode) j, hard_regno);
- }
- }
- }
- /* Allocate and initialize IRA_REGISTER_MOVE_COST, IRA_MAY_MOVE_IN_COST
- and IRA_MAY_MOVE_OUT_COST for MODE. */
- void
- ira_init_register_move_cost (machine_mode mode)
- {
- static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
- bool all_match = true;
- unsigned int cl1, cl2;
- ira_assert (ira_register_move_cost[mode] == NULL
- && ira_may_move_in_cost[mode] == NULL
- && ira_may_move_out_cost[mode] == NULL);
- ira_assert (have_regs_of_mode[mode]);
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- int cost;
- if (!contains_reg_of_mode[cl1][mode]
- || !contains_reg_of_mode[cl2][mode])
- {
- if ((ira_reg_class_max_nregs[cl1][mode]
- > ira_class_hard_regs_num[cl1])
- || (ira_reg_class_max_nregs[cl2][mode]
- > ira_class_hard_regs_num[cl2]))
- cost = 65535;
- else
- cost = (ira_memory_move_cost[mode][cl1][0]
- + ira_memory_move_cost[mode][cl2][1]) * 2;
- }
- else
- {
- cost = register_move_cost (mode, (enum reg_class) cl1,
- (enum reg_class) cl2);
- ira_assert (cost < 65535);
- }
- all_match &= (last_move_cost[cl1][cl2] == cost);
- last_move_cost[cl1][cl2] = cost;
- }
- if (all_match && last_mode_for_init_move_cost != -1)
- {
- ira_register_move_cost[mode]
- = ira_register_move_cost[last_mode_for_init_move_cost];
- ira_may_move_in_cost[mode]
- = ira_may_move_in_cost[last_mode_for_init_move_cost];
- ira_may_move_out_cost[mode]
- = ira_may_move_out_cost[last_mode_for_init_move_cost];
- return;
- }
- last_mode_for_init_move_cost = mode;
- ira_register_move_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- ira_may_move_in_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- ira_may_move_out_cost[mode] = XNEWVEC (move_table, N_REG_CLASSES);
- for (cl1 = 0; cl1 < N_REG_CLASSES; cl1++)
- for (cl2 = 0; cl2 < N_REG_CLASSES; cl2++)
- {
- int cost;
- enum reg_class *p1, *p2;
-
- if (last_move_cost[cl1][cl2] == 65535)
- {
- ira_register_move_cost[mode][cl1][cl2] = 65535;
- ira_may_move_in_cost[mode][cl1][cl2] = 65535;
- ira_may_move_out_cost[mode][cl1][cl2] = 65535;
- }
- else
- {
- cost = last_move_cost[cl1][cl2];
-
- for (p2 = ®_class_subclasses[cl2][0];
- *p2 != LIM_REG_CLASSES; p2++)
- if (ira_class_hard_regs_num[*p2] > 0
- && (ira_reg_class_max_nregs[*p2][mode]
- <= ira_class_hard_regs_num[*p2]))
- cost = MAX (cost, ira_register_move_cost[mode][cl1][*p2]);
-
- for (p1 = ®_class_subclasses[cl1][0];
- *p1 != LIM_REG_CLASSES; p1++)
- if (ira_class_hard_regs_num[*p1] > 0
- && (ira_reg_class_max_nregs[*p1][mode]
- <= ira_class_hard_regs_num[*p1]))
- cost = MAX (cost, ira_register_move_cost[mode][*p1][cl2]);
-
- ira_assert (cost <= 65535);
- ira_register_move_cost[mode][cl1][cl2] = cost;
-
- if (ira_class_subset_p[cl1][cl2])
- ira_may_move_in_cost[mode][cl1][cl2] = 0;
- else
- ira_may_move_in_cost[mode][cl1][cl2] = cost;
-
- if (ira_class_subset_p[cl2][cl1])
- ira_may_move_out_cost[mode][cl1][cl2] = 0;
- else
- ira_may_move_out_cost[mode][cl1][cl2] = cost;
- }
- }
- }
- /* This is called once during compiler work. It sets up
- different arrays whose values don't depend on the compiled
- function. */
- void
- ira_init_once (void)
- {
- ira_init_costs_once ();
- lra_init_once ();
- }
- /* Free ira_max_register_move_cost, ira_may_move_in_cost and
- ira_may_move_out_cost for each mode. */
- void
- target_ira_int::free_register_move_costs (void)
- {
- int mode, i;
- /* Reset move_cost and friends, making sure we only free shared
- table entries once. */
- for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
- if (x_ira_register_move_cost[mode])
- {
- for (i = 0;
- i < mode && (x_ira_register_move_cost[i]
- != x_ira_register_move_cost[mode]);
- i++)
- ;
- if (i == mode)
- {
- free (x_ira_register_move_cost[mode]);
- free (x_ira_may_move_in_cost[mode]);
- free (x_ira_may_move_out_cost[mode]);
- }
- }
- memset (x_ira_register_move_cost, 0, sizeof x_ira_register_move_cost);
- memset (x_ira_may_move_in_cost, 0, sizeof x_ira_may_move_in_cost);
- memset (x_ira_may_move_out_cost, 0, sizeof x_ira_may_move_out_cost);
- last_mode_for_init_move_cost = -1;
- }
- target_ira_int::~target_ira_int ()
- {
- free_ira_costs ();
- free_register_move_costs ();
- }
- /* This is called every time when register related information is
- changed. */
- void
- ira_init (void)
- {
- this_target_ira_int->free_register_move_costs ();
- setup_reg_mode_hard_regset ();
- setup_alloc_regs (flag_omit_frame_pointer != 0);
- setup_class_subset_and_memory_move_costs ();
- setup_reg_class_nregs ();
- setup_prohibited_class_mode_regs ();
- find_reg_classes ();
- clarify_prohibited_class_mode_regs ();
- setup_hard_regno_aclass ();
- ira_init_costs ();
- }
- #define ira_prohibited_mode_move_regs_initialized_p \
- (this_target_ira_int->x_ira_prohibited_mode_move_regs_initialized_p)
- /* Set up IRA_PROHIBITED_MODE_MOVE_REGS. */
- static void
- setup_prohibited_mode_move_regs (void)
- {
- int i, j;
- rtx test_reg1, test_reg2, move_pat;
- rtx_insn *move_insn;
- if (ira_prohibited_mode_move_regs_initialized_p)
- return;
- ira_prohibited_mode_move_regs_initialized_p = true;
- test_reg1 = gen_rtx_REG (VOIDmode, 0);
- test_reg2 = gen_rtx_REG (VOIDmode, 0);
- move_pat = gen_rtx_SET (VOIDmode, test_reg1, test_reg2);
- move_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, move_pat, 0, -1, 0);
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- {
- SET_HARD_REG_SET (ira_prohibited_mode_move_regs[i]);
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- {
- if (! HARD_REGNO_MODE_OK (j, (machine_mode) i))
- continue;
- SET_REGNO_RAW (test_reg1, j);
- PUT_MODE (test_reg1, (machine_mode) i);
- SET_REGNO_RAW (test_reg2, j);
- PUT_MODE (test_reg2, (machine_mode) i);
- INSN_CODE (move_insn) = -1;
- recog_memoized (move_insn);
- if (INSN_CODE (move_insn) < 0)
- continue;
- extract_insn (move_insn);
- /* We don't know whether the move will be in code that is optimized
- for size or speed, so consider all enabled alternatives. */
- if (! constrain_operands (1, get_enabled_alternatives (move_insn)))
- continue;
- CLEAR_HARD_REG_BIT (ira_prohibited_mode_move_regs[i], j);
- }
- }
- }
- /* Setup possible alternatives in ALTS for INSN. */
- void
- ira_setup_alts (rtx_insn *insn, HARD_REG_SET &alts)
- {
- /* MAP nalt * nop -> start of constraints for given operand and
- alternative. */
- static vec<const char *> insn_constraints;
- int nop, nalt;
- bool curr_swapped;
- const char *p;
- rtx op;
- int commutative = -1;
- extract_insn (insn);
- alternative_mask preferred = get_preferred_alternatives (insn);
- CLEAR_HARD_REG_SET (alts);
- insn_constraints.release ();
- insn_constraints.safe_grow_cleared (recog_data.n_operands
- * recog_data.n_alternatives + 1);
- /* Check that the hard reg set is enough for holding all
- alternatives. It is hard to imagine the situation when the
- assertion is wrong. */
- ira_assert (recog_data.n_alternatives
- <= (int) MAX (sizeof (HARD_REG_ELT_TYPE) * CHAR_BIT,
- FIRST_PSEUDO_REGISTER));
- for (curr_swapped = false;; curr_swapped = true)
- {
- /* Calculate some data common for all alternatives to speed up the
- function. */
- for (nop = 0; nop < recog_data.n_operands; nop++)
- {
- for (nalt = 0, p = recog_data.constraints[nop];
- nalt < recog_data.n_alternatives;
- nalt++)
- {
- insn_constraints[nop * recog_data.n_alternatives + nalt] = p;
- while (*p && *p != ',')
- p++;
- if (*p)
- p++;
- }
- }
- for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
- {
- if (!TEST_BIT (preferred, nalt)
- || TEST_HARD_REG_BIT (alts, nalt))
- continue;
- for (nop = 0; nop < recog_data.n_operands; nop++)
- {
- int c, len;
- op = recog_data.operand[nop];
- p = insn_constraints[nop * recog_data.n_alternatives + nalt];
- if (*p == 0 || *p == ',')
- continue;
-
- do
- switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
- {
- case '#':
- case ',':
- c = '\0';
- case '\0':
- len = 0;
- break;
-
- case '%':
- /* We only support one commutative marker, the
- first one. We already set commutative
- above. */
- if (commutative < 0)
- commutative = nop;
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- goto op_success;
- break;
-
- case 'g':
- goto op_success;
- break;
-
- default:
- {
- enum constraint_num cn = lookup_constraint (p);
- switch (get_constraint_type (cn))
- {
- case CT_REGISTER:
- if (reg_class_for_constraint (cn) != NO_REGS)
- goto op_success;
- break;
- case CT_CONST_INT:
- if (CONST_INT_P (op)
- && (insn_const_int_ok_for_constraint
- (INTVAL (op), cn)))
- goto op_success;
- break;
- case CT_ADDRESS:
- case CT_MEMORY:
- goto op_success;
- case CT_FIXED_FORM:
- if (constraint_satisfied_p (op, cn))
- goto op_success;
- break;
- }
- break;
- }
- }
- while (p += len, c);
- break;
- op_success:
- ;
- }
- if (nop >= recog_data.n_operands)
- SET_HARD_REG_BIT (alts, nalt);
- }
- if (commutative < 0)
- break;
- if (curr_swapped)
- break;
- op = recog_data.operand[commutative];
- recog_data.operand[commutative] = recog_data.operand[commutative + 1];
- recog_data.operand[commutative + 1] = op;
- }
- }
- /* Return the number of the output non-early clobber operand which
- should be the same in any case as operand with number OP_NUM (or
- negative value if there is no such operand). The function takes
- only really possible alternatives into consideration. */
- int
- ira_get_dup_out_num (int op_num, HARD_REG_SET &alts)
- {
- int curr_alt, c, original, dup;
- bool ignore_p, use_commut_op_p;
- const char *str;
- if (op_num < 0 || recog_data.n_alternatives == 0)
- return -1;
- /* We should find duplications only for input operands. */
- if (recog_data.operand_type[op_num] != OP_IN)
- return -1;
- str = recog_data.constraints[op_num];
- use_commut_op_p = false;
- for (;;)
- {
- rtx op = recog_data.operand[op_num];
-
- for (curr_alt = 0, ignore_p = !TEST_HARD_REG_BIT (alts, curr_alt),
- original = -1;;)
- {
- c = *str;
- if (c == '\0')
- break;
- if (c == '#')
- ignore_p = true;
- else if (c == ',')
- {
- curr_alt++;
- ignore_p = !TEST_HARD_REG_BIT (alts, curr_alt);
- }
- else if (! ignore_p)
- switch (c)
- {
- case 'g':
- goto fail;
- default:
- {
- enum constraint_num cn = lookup_constraint (str);
- enum reg_class cl = reg_class_for_constraint (cn);
- if (cl != NO_REGS
- && !targetm.class_likely_spilled_p (cl))
- goto fail;
- if (constraint_satisfied_p (op, cn))
- goto fail;
- break;
- }
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (original != -1 && original != c)
- goto fail;
- original = c;
- break;
- }
- str += CONSTRAINT_LEN (c, str);
- }
- if (original == -1)
- goto fail;
- dup = -1;
- for (ignore_p = false, str = recog_data.constraints[original - '0'];
- *str != 0;
- str++)
- if (ignore_p)
- {
- if (*str == ',')
- ignore_p = false;
- }
- else if (*str == '#')
- ignore_p = true;
- else if (! ignore_p)
- {
- if (*str == '=')
- dup = original - '0';
- /* It is better ignore an alternative with early clobber. */
- else if (*str == '&')
- goto fail;
- }
- if (dup >= 0)
- return dup;
- fail:
- if (use_commut_op_p)
- break;
- use_commut_op_p = true;
- if (recog_data.constraints[op_num][0] == '%')
- str = recog_data.constraints[op_num + 1];
- else if (op_num > 0 && recog_data.constraints[op_num - 1][0] == '%')
- str = recog_data.constraints[op_num - 1];
- else
- break;
- }
- return -1;
- }
- /* Search forward to see if the source register of a copy insn dies
- before either it or the destination register is modified, but don't
- scan past the end of the basic block. If so, we can replace the
- source with the destination and let the source die in the copy
- insn.
- This will reduce the number of registers live in that range and may
- enable the destination and the source coalescing, thus often saving
- one register in addition to a register-register copy. */
- static void
- decrease_live_ranges_number (void)
- {
- basic_block bb;
- rtx_insn *insn;
- rtx set, src, dest, dest_death, q, note;
- rtx_insn *p;
- int sregno, dregno;
- if (! flag_expensive_optimizations)
- return;
- if (ira_dump_file)
- fprintf (ira_dump_file, "Starting decreasing number of live ranges...\n");
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- {
- set = single_set (insn);
- if (! set)
- continue;
- src = SET_SRC (set);
- dest = SET_DEST (set);
- if (! REG_P (src) || ! REG_P (dest)
- || find_reg_note (insn, REG_DEAD, src))
- continue;
- sregno = REGNO (src);
- dregno = REGNO (dest);
-
- /* We don't want to mess with hard regs if register classes
- are small. */
- if (sregno == dregno
- || (targetm.small_register_classes_for_mode_p (GET_MODE (src))
- && (sregno < FIRST_PSEUDO_REGISTER
- || dregno < FIRST_PSEUDO_REGISTER))
- /* We don't see all updates to SP if they are in an
- auto-inc memory reference, so we must disallow this
- optimization on them. */
- || sregno == STACK_POINTER_REGNUM
- || dregno == STACK_POINTER_REGNUM)
- continue;
-
- dest_death = NULL_RTX;
- for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
- {
- if (! INSN_P (p))
- continue;
- if (BLOCK_FOR_INSN (p) != bb)
- break;
-
- if (reg_set_p (src, p) || reg_set_p (dest, p)
- /* If SRC is an asm-declared register, it must not be
- replaced in any asm. Unfortunately, the REG_EXPR
- tree for the asm variable may be absent in the SRC
- rtx, so we can't check the actual register
- declaration easily (the asm operand will have it,
- though). To avoid complicating the test for a rare
- case, we just don't perform register replacement
- for a hard reg mentioned in an asm. */
- || (sregno < FIRST_PSEUDO_REGISTER
- && asm_noperands (PATTERN (p)) >= 0
- && reg_overlap_mentioned_p (src, PATTERN (p)))
- /* Don't change hard registers used by a call. */
- || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER
- && find_reg_fusage (p, USE, src))
- /* Don't change a USE of a register. */
- || (GET_CODE (PATTERN (p)) == USE
- && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
- break;
-
- /* See if all of SRC dies in P. This test is slightly
- more conservative than it needs to be. */
- if ((note = find_regno_note (p, REG_DEAD, sregno))
- && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
- {
- int failed = 0;
-
- /* We can do the optimization. Scan forward from INSN
- again, replacing regs as we go. Set FAILED if a
- replacement can't be done. In that case, we can't
- move the death note for SRC. This should be
- rare. */
-
- /* Set to stop at next insn. */
- for (q = next_real_insn (insn);
- q != next_real_insn (p);
- q = next_real_insn (q))
- {
- if (reg_overlap_mentioned_p (src, PATTERN (q)))
- {
- /* If SRC is a hard register, we might miss
- some overlapping registers with
- validate_replace_rtx, so we would have to
- undo it. We can't if DEST is present in
- the insn, so fail in that combination of
- cases. */
- if (sregno < FIRST_PSEUDO_REGISTER
- && reg_mentioned_p (dest, PATTERN (q)))
- failed = 1;
-
- /* Attempt to replace all uses. */
- else if (!validate_replace_rtx (src, dest, q))
- failed = 1;
-
- /* If this succeeded, but some part of the
- register is still present, undo the
- replacement. */
- else if (sregno < FIRST_PSEUDO_REGISTER
- && reg_overlap_mentioned_p (src, PATTERN (q)))
- {
- validate_replace_rtx (dest, src, q);
- failed = 1;
- }
- }
-
- /* If DEST dies here, remove the death note and
- save it for later. Make sure ALL of DEST dies
- here; again, this is overly conservative. */
- if (! dest_death
- && (dest_death = find_regno_note (q, REG_DEAD, dregno)))
- {
- if (GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))
- remove_note (q, dest_death);
- else
- {
- failed = 1;
- dest_death = 0;
- }
- }
- }
-
- if (! failed)
- {
- /* Move death note of SRC from P to INSN. */
- remove_note (p, note);
- XEXP (note, 1) = REG_NOTES (insn);
- REG_NOTES (insn) = note;
- }
-
- /* DEST is also dead if INSN has a REG_UNUSED note for
- DEST. */
- if (! dest_death
- && (dest_death
- = find_regno_note (insn, REG_UNUSED, dregno)))
- {
- PUT_REG_NOTE_KIND (dest_death, REG_DEAD);
- remove_note (insn, dest_death);
- }
-
- /* Put death note of DEST on P if we saw it die. */
- if (dest_death)
- {
- XEXP (dest_death, 1) = REG_NOTES (p);
- REG_NOTES (p) = dest_death;
- }
- break;
- }
-
- /* If SRC is a hard register which is set or killed in
- some other way, we can't do this optimization. */
- else if (sregno < FIRST_PSEUDO_REGISTER && dead_or_set_p (p, src))
- break;
- }
- }
- }
- /* Return nonzero if REGNO is a particularly bad choice for reloading X. */
- static bool
- ira_bad_reload_regno_1 (int regno, rtx x)
- {
- int x_regno, n, i;
- ira_allocno_t a;
- enum reg_class pref;
- /* We only deal with pseudo regs. */
- if (! x || GET_CODE (x) != REG)
- return false;
- x_regno = REGNO (x);
- if (x_regno < FIRST_PSEUDO_REGISTER)
- return false;
- /* If the pseudo prefers REGNO explicitly, then do not consider
- REGNO a bad spill choice. */
- pref = reg_preferred_class (x_regno);
- if (reg_class_size[pref] == 1)
- return !TEST_HARD_REG_BIT (reg_class_contents[pref], regno);
- /* If the pseudo conflicts with REGNO, then we consider REGNO a
- poor choice for a reload regno. */
- a = ira_regno_allocno_map[x_regno];
- n = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < n; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
- if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno))
- return true;
- }
- return false;
- }
- /* Return nonzero if REGNO is a particularly bad choice for reloading
- IN or OUT. */
- bool
- ira_bad_reload_regno (int regno, rtx in, rtx out)
- {
- return (ira_bad_reload_regno_1 (regno, in)
- || ira_bad_reload_regno_1 (regno, out));
- }
- /* Add register clobbers from asm statements. */
- static void
- compute_regs_asm_clobbered (void)
- {
- basic_block bb;
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- df_ref def;
- if (NONDEBUG_INSN_P (insn) && extract_asm_operands (PATTERN (insn)))
- FOR_EACH_INSN_DEF (def, insn)
- {
- unsigned int dregno = DF_REF_REGNO (def);
- if (HARD_REGISTER_NUM_P (dregno))
- add_to_hard_reg_set (&crtl->asm_clobbers,
- GET_MODE (DF_REF_REAL_REG (def)),
- dregno);
- }
- }
- }
- }
- /* Set up ELIMINABLE_REGSET, IRA_NO_ALLOC_REGS, and
- REGS_EVER_LIVE. */
- void
- ira_setup_eliminable_regset (void)
- {
- #ifdef ELIMINABLE_REGS
- int i;
- static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
- #endif
- /* FIXME: If EXIT_IGNORE_STACK is set, we will not save and restore
- sp for alloca. So we can't eliminate the frame pointer in that
- case. At some point, we should improve this by emitting the
- sp-adjusting insns for this case. */
- frame_pointer_needed
- = (! flag_omit_frame_pointer
- || (cfun->calls_alloca && EXIT_IGNORE_STACK)
- /* We need the frame pointer to catch stack overflow exceptions
- if the stack pointer is moving. */
- || (flag_stack_check && STACK_CHECK_MOVING_SP)
- || crtl->accesses_prior_frames
- || (SUPPORTS_STACK_ALIGNMENT && crtl->stack_realign_needed)
- /* We need a frame pointer for all Cilk Plus functions that use
- Cilk keywords. */
- || (flag_cilkplus && cfun->is_cilk_function)
- || targetm.frame_pointer_required ());
- /* The chance that FRAME_POINTER_NEEDED is changed from inspecting
- RTL is very small. So if we use frame pointer for RA and RTL
- actually prevents this, we will spill pseudos assigned to the
- frame pointer in LRA. */
- if (frame_pointer_needed)
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
-
- COPY_HARD_REG_SET (ira_no_alloc_regs, no_unit_alloc_regs);
- CLEAR_HARD_REG_SET (eliminable_regset);
- compute_regs_asm_clobbered ();
- /* Build the regset of all eliminable registers and show we can't
- use those that we already know won't be eliminated. */
- #ifdef ELIMINABLE_REGS
- for (i = 0; i < (int) ARRAY_SIZE (eliminables); i++)
- {
- bool cannot_elim
- = (! targetm.can_eliminate (eliminables[i].from, eliminables[i].to)
- || (eliminables[i].to == STACK_POINTER_REGNUM && frame_pointer_needed));
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, eliminables[i].from))
- {
- SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
- if (cannot_elim)
- SET_HARD_REG_BIT (ira_no_alloc_regs, eliminables[i].from);
- }
- else if (cannot_elim)
- error ("%s cannot be used in asm here",
- reg_names[eliminables[i].from]);
- else
- df_set_regs_ever_live (eliminables[i].from, true);
- }
- #if !HARD_FRAME_POINTER_IS_FRAME_POINTER
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
- {
- SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
- if (frame_pointer_needed)
- SET_HARD_REG_BIT (ira_no_alloc_regs, HARD_FRAME_POINTER_REGNUM);
- }
- else if (frame_pointer_needed)
- error ("%s cannot be used in asm here",
- reg_names[HARD_FRAME_POINTER_REGNUM]);
- else
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
- #endif
- #else
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
- {
- SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
- if (frame_pointer_needed)
- SET_HARD_REG_BIT (ira_no_alloc_regs, FRAME_POINTER_REGNUM);
- }
- else if (frame_pointer_needed)
- error ("%s cannot be used in asm here", reg_names[FRAME_POINTER_REGNUM]);
- else
- df_set_regs_ever_live (FRAME_POINTER_REGNUM, true);
- #endif
- }
- /* Vector of substitutions of register numbers,
- used to map pseudo regs into hardware regs.
- This is set up as a result of register allocation.
- Element N is the hard reg assigned to pseudo reg N,
- or is -1 if no hard reg was assigned.
- If N is a hard reg number, element N is N. */
- short *reg_renumber;
- /* Set up REG_RENUMBER and CALLER_SAVE_NEEDED (used by reload) from
- the allocation found by IRA. */
- static void
- setup_reg_renumber (void)
- {
- int regno, hard_regno;
- ira_allocno_t a;
- ira_allocno_iterator ai;
- caller_save_needed = 0;
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (ira_use_lra_p && ALLOCNO_CAP_MEMBER (a) != NULL)
- continue;
- /* There are no caps at this point. */
- ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
- if (! ALLOCNO_ASSIGNED_P (a))
- /* It can happen if A is not referenced but partially anticipated
- somewhere in a region. */
- ALLOCNO_ASSIGNED_P (a) = true;
- ira_free_allocno_updated_costs (a);
- hard_regno = ALLOCNO_HARD_REGNO (a);
- regno = ALLOCNO_REGNO (a);
- reg_renumber[regno] = (hard_regno < 0 ? -1 : hard_regno);
- if (hard_regno >= 0)
- {
- int i, nwords;
- enum reg_class pclass;
- ira_object_t obj;
-
- pclass = ira_pressure_class_translate[REGNO_REG_CLASS (hard_regno)];
- nwords = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < nwords; i++)
- {
- obj = ALLOCNO_OBJECT (a, i);
- IOR_COMPL_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
- reg_class_contents[pclass]);
- }
- if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0
- && ira_hard_reg_set_intersection_p (hard_regno, ALLOCNO_MODE (a),
- call_used_reg_set))
- {
- ira_assert (!optimize || flag_caller_saves
- || (ALLOCNO_CALLS_CROSSED_NUM (a)
- == ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
- || regno >= ira_reg_equiv_len
- || ira_equiv_no_lvalue_p (regno));
- caller_save_needed = 1;
- }
- }
- }
- }
- /* Set up allocno assignment flags for further allocation
- improvements. */
- static void
- setup_allocno_assignment_flags (void)
- {
- int hard_regno;
- ira_allocno_t a;
- ira_allocno_iterator ai;
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (! ALLOCNO_ASSIGNED_P (a))
- /* It can happen if A is not referenced but partially anticipated
- somewhere in a region. */
- ira_free_allocno_updated_costs (a);
- hard_regno = ALLOCNO_HARD_REGNO (a);
- /* Don't assign hard registers to allocnos which are destination
- of removed store at the end of loop. It has no sense to keep
- the same value in different hard registers. It is also
- impossible to assign hard registers correctly to such
- allocnos because the cost info and info about intersected
- calls are incorrect for them. */
- ALLOCNO_ASSIGNED_P (a) = (hard_regno >= 0
- || ALLOCNO_EMIT_DATA (a)->mem_optimized_dest_p
- || (ALLOCNO_MEMORY_COST (a)
- - ALLOCNO_CLASS_COST (a)) < 0);
- ira_assert
- (hard_regno < 0
- || ira_hard_reg_in_set_p (hard_regno, ALLOCNO_MODE (a),
- reg_class_contents[ALLOCNO_CLASS (a)]));
- }
- }
- /* Evaluate overall allocation cost and the costs for using hard
- registers and memory for allocnos. */
- static void
- calculate_allocation_cost (void)
- {
- int hard_regno, cost;
- ira_allocno_t a;
- ira_allocno_iterator ai;
- ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
- FOR_EACH_ALLOCNO (a, ai)
- {
- hard_regno = ALLOCNO_HARD_REGNO (a);
- ira_assert (hard_regno < 0
- || (ira_hard_reg_in_set_p
- (hard_regno, ALLOCNO_MODE (a),
- reg_class_contents[ALLOCNO_CLASS (a)])));
- if (hard_regno < 0)
- {
- cost = ALLOCNO_MEMORY_COST (a);
- ira_mem_cost += cost;
- }
- else if (ALLOCNO_HARD_REG_COSTS (a) != NULL)
- {
- cost = (ALLOCNO_HARD_REG_COSTS (a)
- [ira_class_hard_reg_index
- [ALLOCNO_CLASS (a)][hard_regno]]);
- ira_reg_cost += cost;
- }
- else
- {
- cost = ALLOCNO_CLASS_COST (a);
- ira_reg_cost += cost;
- }
- ira_overall_cost += cost;
- }
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- {
- fprintf (ira_dump_file,
- "+++Costs: overall %"PRId64
- ", reg %"PRId64
- ", mem %"PRId64
- ", ld %"PRId64
- ", st %"PRId64
- ", move %"PRId64,
- ira_overall_cost, ira_reg_cost, ira_mem_cost,
- ira_load_cost, ira_store_cost, ira_shuffle_cost);
- fprintf (ira_dump_file, "\n+++ move loops %d, new jumps %d\n",
- ira_move_loops_num, ira_additional_jumps_num);
- }
- }
- #ifdef ENABLE_IRA_CHECKING
- /* Check the correctness of the allocation. We do need this because
- of complicated code to transform more one region internal
- representation into one region representation. */
- static void
- check_allocation (void)
- {
- ira_allocno_t a;
- int hard_regno, nregs, conflict_nregs;
- ira_allocno_iterator ai;
- FOR_EACH_ALLOCNO (a, ai)
- {
- int n = ALLOCNO_NUM_OBJECTS (a);
- int i;
- if (ALLOCNO_CAP_MEMBER (a) != NULL
- || (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
- continue;
- nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)];
- if (nregs == 1)
- /* We allocated a single hard register. */
- n = 1;
- else if (n > 1)
- /* We allocated multiple hard registers, and we will test
- conflicts in a granularity of single hard regs. */
- nregs = 1;
- for (i = 0; i < n; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
- ira_object_t conflict_obj;
- ira_object_conflict_iterator oci;
- int this_regno = hard_regno;
- if (n > 1)
- {
- if (REG_WORDS_BIG_ENDIAN)
- this_regno += n - i - 1;
- else
- this_regno += i;
- }
- FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
- {
- ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
- int conflict_hard_regno = ALLOCNO_HARD_REGNO (conflict_a);
- if (conflict_hard_regno < 0)
- continue;
- conflict_nregs
- = (hard_regno_nregs
- [conflict_hard_regno][ALLOCNO_MODE (conflict_a)]);
- if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1
- && conflict_nregs == ALLOCNO_NUM_OBJECTS (conflict_a))
- {
- if (REG_WORDS_BIG_ENDIAN)
- conflict_hard_regno += (ALLOCNO_NUM_OBJECTS (conflict_a)
- - OBJECT_SUBWORD (conflict_obj) - 1);
- else
- conflict_hard_regno += OBJECT_SUBWORD (conflict_obj);
- conflict_nregs = 1;
- }
- if ((conflict_hard_regno <= this_regno
- && this_regno < conflict_hard_regno + conflict_nregs)
- || (this_regno <= conflict_hard_regno
- && conflict_hard_regno < this_regno + nregs))
- {
- fprintf (stderr, "bad allocation for %d and %d\n",
- ALLOCNO_REGNO (a), ALLOCNO_REGNO (conflict_a));
- gcc_unreachable ();
- }
- }
- }
- }
- }
- #endif
- /* Allocate REG_EQUIV_INIT. Set up it from IRA_REG_EQUIV which should
- be already calculated. */
- static void
- setup_reg_equiv_init (void)
- {
- int i;
- int max_regno = max_reg_num ();
- for (i = 0; i < max_regno; i++)
- reg_equiv_init (i) = ira_reg_equiv[i].init_insns;
- }
- /* Update equiv regno from movement of FROM_REGNO to TO_REGNO. INSNS
- are insns which were generated for such movement. It is assumed
- that FROM_REGNO and TO_REGNO always have the same value at the
- point of any move containing such registers. This function is used
- to update equiv info for register shuffles on the region borders
- and for caller save/restore insns. */
- void
- ira_update_equiv_info_by_shuffle_insn (int to_regno, int from_regno, rtx_insn *insns)
- {
- rtx_insn *insn;
- rtx x, note;
- if (! ira_reg_equiv[from_regno].defined_p
- && (! ira_reg_equiv[to_regno].defined_p
- || ((x = ira_reg_equiv[to_regno].memory) != NULL_RTX
- && ! MEM_READONLY_P (x))))
- return;
- insn = insns;
- if (NEXT_INSN (insn) != NULL_RTX)
- {
- if (! ira_reg_equiv[to_regno].defined_p)
- {
- ira_assert (ira_reg_equiv[to_regno].init_insns == NULL_RTX);
- return;
- }
- ira_reg_equiv[to_regno].defined_p = false;
- ira_reg_equiv[to_regno].memory
- = ira_reg_equiv[to_regno].constant
- = ira_reg_equiv[to_regno].invariant
- = ira_reg_equiv[to_regno].init_insns = NULL;
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Invalidating equiv info for reg %d\n", to_regno);
- return;
- }
- /* It is possible that FROM_REGNO still has no equivalence because
- in shuffles to_regno<-from_regno and from_regno<-to_regno the 2nd
- insn was not processed yet. */
- if (ira_reg_equiv[from_regno].defined_p)
- {
- ira_reg_equiv[to_regno].defined_p = true;
- if ((x = ira_reg_equiv[from_regno].memory) != NULL_RTX)
- {
- ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX
- && ira_reg_equiv[from_regno].constant == NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].memory == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].memory, x));
- ira_reg_equiv[to_regno].memory = x;
- if (! MEM_READONLY_P (x))
- /* We don't add the insn to insn init list because memory
- equivalence is just to say what memory is better to use
- when the pseudo is spilled. */
- return;
- }
- else if ((x = ira_reg_equiv[from_regno].constant) != NULL_RTX)
- {
- ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].constant == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].constant, x));
- ira_reg_equiv[to_regno].constant = x;
- }
- else
- {
- x = ira_reg_equiv[from_regno].invariant;
- ira_assert (x != NULL_RTX);
- ira_assert (ira_reg_equiv[to_regno].invariant == NULL_RTX
- || rtx_equal_p (ira_reg_equiv[to_regno].invariant, x));
- ira_reg_equiv[to_regno].invariant = x;
- }
- if (find_reg_note (insn, REG_EQUIV, x) == NULL_RTX)
- {
- note = set_unique_reg_note (insn, REG_EQUIV, x);
- gcc_assert (note != NULL_RTX);
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- {
- fprintf (ira_dump_file,
- " Adding equiv note to insn %u for reg %d ",
- INSN_UID (insn), to_regno);
- dump_value_slim (ira_dump_file, x, 1);
- fprintf (ira_dump_file, "\n");
- }
- }
- }
- ira_reg_equiv[to_regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[to_regno].init_insns);
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Adding equiv init move insn %u to reg %d\n",
- INSN_UID (insn), to_regno);
- }
- /* Fix values of array REG_EQUIV_INIT after live range splitting done
- by IRA. */
- static void
- fix_reg_equiv_init (void)
- {
- int max_regno = max_reg_num ();
- int i, new_regno, max;
- rtx x, prev, next, insn, set;
- if (max_regno_before_ira < max_regno)
- {
- max = vec_safe_length (reg_equivs);
- grow_reg_equivs ();
- for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
- for (prev = NULL_RTX, x = reg_equiv_init (i);
- x != NULL_RTX;
- x = next)
- {
- next = XEXP (x, 1);
- insn = XEXP (x, 0);
- set = single_set (as_a <rtx_insn *> (insn));
- ira_assert (set != NULL_RTX
- && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))));
- if (REG_P (SET_DEST (set))
- && ((int) REGNO (SET_DEST (set)) == i
- || (int) ORIGINAL_REGNO (SET_DEST (set)) == i))
- new_regno = REGNO (SET_DEST (set));
- else if (REG_P (SET_SRC (set))
- && ((int) REGNO (SET_SRC (set)) == i
- || (int) ORIGINAL_REGNO (SET_SRC (set)) == i))
- new_regno = REGNO (SET_SRC (set));
- else
- gcc_unreachable ();
- if (new_regno == i)
- prev = x;
- else
- {
- /* Remove the wrong list element. */
- if (prev == NULL_RTX)
- reg_equiv_init (i) = next;
- else
- XEXP (prev, 1) = next;
- XEXP (x, 1) = reg_equiv_init (new_regno);
- reg_equiv_init (new_regno) = x;
- }
- }
- }
- }
- #ifdef ENABLE_IRA_CHECKING
- /* Print redundant memory-memory copies. */
- static void
- print_redundant_copies (void)
- {
- int hard_regno;
- ira_allocno_t a;
- ira_copy_t cp, next_cp;
- ira_allocno_iterator ai;
- FOR_EACH_ALLOCNO (a, ai)
- {
- if (ALLOCNO_CAP_MEMBER (a) != NULL)
- /* It is a cap. */
- continue;
- hard_regno = ALLOCNO_HARD_REGNO (a);
- if (hard_regno >= 0)
- continue;
- for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
- if (cp->first == a)
- next_cp = cp->next_first_allocno_copy;
- else
- {
- next_cp = cp->next_second_allocno_copy;
- if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL
- && cp->insn != NULL_RTX
- && ALLOCNO_HARD_REGNO (cp->first) == hard_regno)
- fprintf (ira_dump_file,
- " Redundant move from %d(freq %d):%d\n",
- INSN_UID (cp->insn), cp->freq, hard_regno);
- }
- }
- }
- #endif
- /* Setup preferred and alternative classes for new pseudo-registers
- created by IRA starting with START. */
- static void
- setup_preferred_alternate_classes_for_new_pseudos (int start)
- {
- int i, old_regno;
- int max_regno = max_reg_num ();
- for (i = start; i < max_regno; i++)
- {
- old_regno = ORIGINAL_REGNO (regno_reg_rtx[i]);
- ira_assert (i != old_regno);
- setup_reg_classes (i, reg_preferred_class (old_regno),
- reg_alternate_class (old_regno),
- reg_allocno_class (old_regno));
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " New r%d: setting preferred %s, alternative %s\n",
- i, reg_class_names[reg_preferred_class (old_regno)],
- reg_class_names[reg_alternate_class (old_regno)]);
- }
- }
- /* The number of entries allocated in reg_info. */
- static int allocated_reg_info_size;
- /* Regional allocation can create new pseudo-registers. This function
- expands some arrays for pseudo-registers. */
- static void
- expand_reg_info (void)
- {
- int i;
- int size = max_reg_num ();
- resize_reg_info ();
- for (i = allocated_reg_info_size; i < size; i++)
- setup_reg_classes (i, GENERAL_REGS, ALL_REGS, GENERAL_REGS);
- setup_preferred_alternate_classes_for_new_pseudos (allocated_reg_info_size);
- allocated_reg_info_size = size;
- }
- /* Return TRUE if there is too high register pressure in the function.
- It is used to decide when stack slot sharing is worth to do. */
- static bool
- too_high_register_pressure_p (void)
- {
- int i;
- enum reg_class pclass;
- for (i = 0; i < ira_pressure_classes_num; i++)
- {
- pclass = ira_pressure_classes[i];
- if (ira_loop_tree_root->reg_pressure[pclass] > 10000)
- return true;
- }
- return false;
- }
- /* Indicate that hard register number FROM was eliminated and replaced with
- an offset from hard register number TO. The status of hard registers live
- at the start of a basic block is updated by replacing a use of FROM with
- a use of TO. */
- void
- mark_elimination (int from, int to)
- {
- basic_block bb;
- bitmap r;
- FOR_EACH_BB_FN (bb, cfun)
- {
- r = DF_LR_IN (bb);
- if (bitmap_bit_p (r, from))
- {
- bitmap_clear_bit (r, from);
- bitmap_set_bit (r, to);
- }
- if (! df_live)
- continue;
- r = DF_LIVE_IN (bb);
- if (bitmap_bit_p (r, from))
- {
- bitmap_clear_bit (r, from);
- bitmap_set_bit (r, to);
- }
- }
- }
- /* The length of the following array. */
- int ira_reg_equiv_len;
- /* Info about equiv. info for each register. */
- struct ira_reg_equiv_s *ira_reg_equiv;
- /* Expand ira_reg_equiv if necessary. */
- void
- ira_expand_reg_equiv (void)
- {
- int old = ira_reg_equiv_len;
- if (ira_reg_equiv_len > max_reg_num ())
- return;
- ira_reg_equiv_len = max_reg_num () * 3 / 2 + 1;
- ira_reg_equiv
- = (struct ira_reg_equiv_s *) xrealloc (ira_reg_equiv,
- ira_reg_equiv_len
- * sizeof (struct ira_reg_equiv_s));
- gcc_assert (old < ira_reg_equiv_len);
- memset (ira_reg_equiv + old, 0,
- sizeof (struct ira_reg_equiv_s) * (ira_reg_equiv_len - old));
- }
- static void
- init_reg_equiv (void)
- {
- ira_reg_equiv_len = 0;
- ira_reg_equiv = NULL;
- ira_expand_reg_equiv ();
- }
- static void
- finish_reg_equiv (void)
- {
- free (ira_reg_equiv);
- }
- struct equivalence
- {
- /* Set when a REG_EQUIV note is found or created. Use to
- keep track of what memory accesses might be created later,
- e.g. by reload. */
- rtx replacement;
- rtx *src_p;
- /* The list of each instruction which initializes this register.
- NULL indicates we know nothing about this register's equivalence
- properties.
- An INSN_LIST with a NULL insn indicates this pseudo is already
- known to not have a valid equivalence. */
- rtx_insn_list *init_insns;
- /* Loop depth is used to recognize equivalences which appear
- to be present within the same loop (or in an inner loop). */
- short loop_depth;
- /* Nonzero if this had a preexisting REG_EQUIV note. */
- unsigned char is_arg_equivalence : 1;
- /* Set when an attempt should be made to replace a register
- with the associated src_p entry. */
- unsigned char replace : 1;
- /* Set if this register has no known equivalence. */
- unsigned char no_equiv : 1;
- };
- /* reg_equiv[N] (where N is a pseudo reg number) is the equivalence
- structure for that register. */
- static struct equivalence *reg_equiv;
- /* Used for communication between the following two functions: contains
- a MEM that we wish to ensure remains unchanged. */
- static rtx equiv_mem;
- /* Set nonzero if EQUIV_MEM is modified. */
- static int equiv_mem_modified;
- /* If EQUIV_MEM is modified by modifying DEST, indicate that it is modified.
- Called via note_stores. */
- static void
- validate_equiv_mem_from_store (rtx dest, const_rtx set ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
- {
- if ((REG_P (dest)
- && reg_overlap_mentioned_p (dest, equiv_mem))
- || (MEM_P (dest)
- && anti_dependence (equiv_mem, dest)))
- equiv_mem_modified = 1;
- }
- /* Verify that no store between START and the death of REG invalidates
- MEMREF. MEMREF is invalidated by modifying a register used in MEMREF,
- by storing into an overlapping memory location, or with a non-const
- CALL_INSN.
- Return 1 if MEMREF remains valid. */
- static int
- validate_equiv_mem (rtx_insn *start, rtx reg, rtx memref)
- {
- rtx_insn *insn;
- rtx note;
- equiv_mem = memref;
- equiv_mem_modified = 0;
- /* If the memory reference has side effects or is volatile, it isn't a
- valid equivalence. */
- if (side_effects_p (memref))
- return 0;
- for (insn = start; insn && ! equiv_mem_modified; insn = NEXT_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
- if (find_reg_note (insn, REG_DEAD, reg))
- return 1;
- /* This used to ignore readonly memory and const/pure calls. The problem
- is the equivalent form may reference a pseudo which gets assigned a
- call clobbered hard reg. When we later replace REG with its
- equivalent form, the value in the call-clobbered reg has been
- changed and all hell breaks loose. */
- if (CALL_P (insn))
- return 0;
- note_stores (PATTERN (insn), validate_equiv_mem_from_store, NULL);
- /* If a register mentioned in MEMREF is modified via an
- auto-increment, we lose the equivalence. Do the same if one
- dies; although we could extend the life, it doesn't seem worth
- the trouble. */
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if ((REG_NOTE_KIND (note) == REG_INC
- || REG_NOTE_KIND (note) == REG_DEAD)
- && REG_P (XEXP (note, 0))
- && reg_overlap_mentioned_p (XEXP (note, 0), memref))
- return 0;
- }
- return 0;
- }
- /* Returns zero if X is known to be invariant. */
- static int
- equiv_init_varies_p (rtx x)
- {
- RTX_CODE code = GET_CODE (x);
- int i;
- const char *fmt;
- switch (code)
- {
- case MEM:
- return !MEM_READONLY_P (x) || equiv_init_varies_p (XEXP (x, 0));
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- return 0;
- case REG:
- return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x, 0);
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 1;
- /* Fall through. */
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- if (equiv_init_varies_p (XEXP (x, i)))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (equiv_init_varies_p (XVECEXP (x, i, j)))
- return 1;
- }
- return 0;
- }
- /* Returns nonzero if X (used to initialize register REGNO) is movable.
- X is only movable if the registers it uses have equivalent initializations
- which appear to be within the same loop (or in an inner loop) and movable
- or if they are not candidates for local_alloc and don't vary. */
- static int
- equiv_init_movable_p (rtx x, int regno)
- {
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
- switch (code)
- {
- case SET:
- return equiv_init_movable_p (SET_SRC (x), regno);
- case CC0:
- case CLOBBER:
- return 0;
- case PRE_INC:
- case PRE_DEC:
- case POST_INC:
- case POST_DEC:
- case PRE_MODIFY:
- case POST_MODIFY:
- return 0;
- case REG:
- return ((reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth
- && reg_equiv[REGNO (x)].replace)
- || (REG_BASIC_BLOCK (REGNO (x)) < NUM_FIXED_BLOCKS
- && ! rtx_varies_p (x, 0)));
- case UNSPEC_VOLATILE:
- return 0;
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 0;
- /* Fall through. */
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (! equiv_init_movable_p (XEXP (x, i), regno))
- return 0;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (! equiv_init_movable_p (XVECEXP (x, i, j), regno))
- return 0;
- break;
- }
- return 1;
- }
- /* TRUE if X uses any registers for which reg_equiv[REGNO].replace is
- true. */
- static int
- contains_replace_regs (rtx x)
- {
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
- switch (code)
- {
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- CASE_CONST_ANY:
- case PC:
- case CC0:
- case HIGH:
- return 0;
- case REG:
- return reg_equiv[REGNO (x)].replace;
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (contains_replace_regs (XEXP (x, i)))
- return 1;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (contains_replace_regs (XVECEXP (x, i, j)))
- return 1;
- break;
- }
- return 0;
- }
- /* TRUE if X references a memory location that would be affected by a store
- to MEMREF. */
- static int
- memref_referenced_p (rtx memref, rtx x)
- {
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
- switch (code)
- {
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- CASE_CONST_ANY:
- case PC:
- case CC0:
- case HIGH:
- case LO_SUM:
- return 0;
- case REG:
- return (reg_equiv[REGNO (x)].replacement
- && memref_referenced_p (memref,
- reg_equiv[REGNO (x)].replacement));
- case MEM:
- if (true_dependence (memref, VOIDmode, x))
- return 1;
- break;
- case SET:
- /* If we are setting a MEM, it doesn't count (its address does), but any
- other SET_DEST that has a MEM in it is referencing the MEM. */
- if (MEM_P (SET_DEST (x)))
- {
- if (memref_referenced_p (memref, XEXP (SET_DEST (x), 0)))
- return 1;
- }
- else if (memref_referenced_p (memref, SET_DEST (x)))
- return 1;
- return memref_referenced_p (memref, SET_SRC (x));
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (memref_referenced_p (memref, XEXP (x, i)))
- return 1;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (memref_referenced_p (memref, XVECEXP (x, i, j)))
- return 1;
- break;
- }
- return 0;
- }
- /* TRUE if some insn in the range (START, END] references a memory location
- that would be affected by a store to MEMREF. */
- static int
- memref_used_between_p (rtx memref, rtx_insn *start, rtx_insn *end)
- {
- rtx_insn *insn;
- for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
- insn = NEXT_INSN (insn))
- {
- if (!NONDEBUG_INSN_P (insn))
- continue;
- if (memref_referenced_p (memref, PATTERN (insn)))
- return 1;
- /* Nonconst functions may access memory. */
- if (CALL_P (insn) && (! RTL_CONST_CALL_P (insn)))
- return 1;
- }
- return 0;
- }
- /* Mark REG as having no known equivalence.
- Some instructions might have been processed before and furnished
- with REG_EQUIV notes for this register; these notes will have to be
- removed.
- STORE is the piece of RTL that does the non-constant / conflicting
- assignment - a SET, CLOBBER or REG_INC note. It is currently not used,
- but needs to be there because this function is called from note_stores. */
- static void
- no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
- {
- int regno;
- rtx_insn_list *list;
- if (!REG_P (reg))
- return;
- regno = REGNO (reg);
- reg_equiv[regno].no_equiv = 1;
- list = reg_equiv[regno].init_insns;
- if (list && list->insn () == NULL)
- return;
- reg_equiv[regno].init_insns = gen_rtx_INSN_LIST (VOIDmode, NULL_RTX, NULL);
- reg_equiv[regno].replacement = NULL_RTX;
- /* This doesn't matter for equivalences made for argument registers, we
- should keep their initialization insns. */
- if (reg_equiv[regno].is_arg_equivalence)
- return;
- ira_reg_equiv[regno].defined_p = false;
- ira_reg_equiv[regno].init_insns = NULL;
- for (; list; list = list->next ())
- {
- rtx_insn *insn = list->insn ();
- remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
- }
- }
- /* Check whether the SUBREG is a paradoxical subreg and set the result
- in PDX_SUBREGS. */
- static void
- set_paradoxical_subreg (rtx_insn *insn, bool *pdx_subregs)
- {
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
- {
- const_rtx subreg = *iter;
- if (GET_CODE (subreg) == SUBREG)
- {
- const_rtx reg = SUBREG_REG (subreg);
- if (REG_P (reg) && paradoxical_subreg_p (subreg))
- pdx_subregs[REGNO (reg)] = true;
- }
- }
- }
- /* In DEBUG_INSN location adjust REGs from CLEARED_REGS bitmap to the
- equivalent replacement. */
- static rtx
- adjust_cleared_regs (rtx loc, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
- {
- if (REG_P (loc))
- {
- bitmap cleared_regs = (bitmap) data;
- if (bitmap_bit_p (cleared_regs, REGNO (loc)))
- return simplify_replace_fn_rtx (copy_rtx (*reg_equiv[REGNO (loc)].src_p),
- NULL_RTX, adjust_cleared_regs, data);
- }
- return NULL_RTX;
- }
- /* Nonzero if we recorded an equivalence for a LABEL_REF. */
- static int recorded_label_ref;
- /* Find registers that are equivalent to a single value throughout the
- compilation (either because they can be referenced in memory or are
- set once from a single constant). Lower their priority for a
- register.
- If such a register is only referenced once, try substituting its
- value into the using insn. If it succeeds, we can eliminate the
- register completely.
- Initialize init_insns in ira_reg_equiv array.
- Return non-zero if jump label rebuilding should be done. */
- static int
- update_equiv_regs (void)
- {
- rtx_insn *insn;
- basic_block bb;
- int loop_depth;
- bitmap cleared_regs;
- bool *pdx_subregs;
- /* We need to keep track of whether or not we recorded a LABEL_REF so
- that we know if the jump optimizer needs to be rerun. */
- recorded_label_ref = 0;
- /* Use pdx_subregs to show whether a reg is used in a paradoxical
- subreg. */
- pdx_subregs = XCNEWVEC (bool, max_regno);
- reg_equiv = XCNEWVEC (struct equivalence, max_regno);
- grow_reg_equivs ();
- init_alias_analysis ();
- /* Scan insns and set pdx_subregs[regno] if the reg is used in a
- paradoxical subreg. Don't set such reg equivalent to a mem,
- because lra will not substitute such equiv memory in order to
- prevent access beyond allocated memory for paradoxical memory subreg. */
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- set_paradoxical_subreg (insn, pdx_subregs);
- /* Scan the insns and find which registers have equivalences. Do this
- in a separate scan of the insns because (due to -fcse-follow-jumps)
- a register can be set below its use. */
- FOR_EACH_BB_FN (bb, cfun)
- {
- loop_depth = bb_loop_depth (bb);
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- rtx note;
- rtx set;
- rtx dest, src;
- int regno;
- if (! INSN_P (insn))
- continue;
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_INC)
- no_equiv (XEXP (note, 0), note, NULL);
- set = single_set (insn);
- /* If this insn contains more (or less) than a single SET,
- only mark all destinations as having no known equivalence. */
- if (set == NULL_RTX)
- {
- note_stores (PATTERN (insn), no_equiv, NULL);
- continue;
- }
- else if (GET_CODE (PATTERN (insn)) == PARALLEL)
- {
- int i;
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- {
- rtx part = XVECEXP (PATTERN (insn), 0, i);
- if (part != set)
- note_stores (part, no_equiv, NULL);
- }
- }
- dest = SET_DEST (set);
- src = SET_SRC (set);
- /* See if this is setting up the equivalence between an argument
- register and its stack slot. */
- note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note)
- {
- gcc_assert (REG_P (dest));
- regno = REGNO (dest);
- /* Note that we don't want to clear init_insns in
- ira_reg_equiv even if there are multiple sets of this
- register. */
- reg_equiv[regno].is_arg_equivalence = 1;
- /* The insn result can have equivalence memory although
- the equivalence is not set up by the insn. We add
- this insn to init insns as it is a flag for now that
- regno has an equivalence. We will remove the insn
- from init insn list later. */
- if (rtx_equal_p (src, XEXP (note, 0)) || MEM_P (XEXP (note, 0)))
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[regno].init_insns);
- /* Continue normally in case this is a candidate for
- replacements. */
- }
- if (!optimize)
- continue;
- /* We only handle the case of a pseudo register being set
- once, or always to the same value. */
- /* ??? The mn10200 port breaks if we add equivalences for
- values that need an ADDRESS_REGS register and set them equivalent
- to a MEM of a pseudo. The actual problem is in the over-conservative
- handling of INPADDR_ADDRESS / INPUT_ADDRESS / INPUT triples in
- calculate_needs, but we traditionally work around this problem
- here by rejecting equivalences when the destination is in a register
- that's likely spilled. This is fragile, of course, since the
- preferred class of a pseudo depends on all instructions that set
- or use it. */
- if (!REG_P (dest)
- || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
- || (reg_equiv[regno].init_insns
- && reg_equiv[regno].init_insns->insn () == NULL)
- || (targetm.class_likely_spilled_p (reg_preferred_class (regno))
- && MEM_P (src) && ! reg_equiv[regno].is_arg_equivalence))
- {
- /* This might be setting a SUBREG of a pseudo, a pseudo that is
- also set somewhere else to a constant. */
- note_stores (set, no_equiv, NULL);
- continue;
- }
- /* Don't set reg (if pdx_subregs[regno] == true) equivalent to a mem. */
- if (MEM_P (src) && pdx_subregs[regno])
- {
- note_stores (set, no_equiv, NULL);
- continue;
- }
- note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- /* cse sometimes generates function invariants, but doesn't put a
- REG_EQUAL note on the insn. Since this note would be redundant,
- there's no point creating it earlier than here. */
- if (! note && ! rtx_varies_p (src, 0))
- note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
- /* Don't bother considering a REG_EQUAL note containing an EXPR_LIST
- since it represents a function call. */
- if (note && GET_CODE (XEXP (note, 0)) == EXPR_LIST)
- note = NULL_RTX;
- if (DF_REG_DEF_COUNT (regno) != 1)
- {
- bool equal_p = true;
- rtx_insn_list *list;
- /* If we have already processed this pseudo and determined it
- can not have an equivalence, then honor that decision. */
- if (reg_equiv[regno].no_equiv)
- continue;
- if (! note
- || rtx_varies_p (XEXP (note, 0), 0)
- || (reg_equiv[regno].replacement
- && ! rtx_equal_p (XEXP (note, 0),
- reg_equiv[regno].replacement)))
- {
- no_equiv (dest, set, NULL);
- continue;
- }
- list = reg_equiv[regno].init_insns;
- for (; list; list = list->next ())
- {
- rtx note_tmp;
- rtx_insn *insn_tmp;
- insn_tmp = list->insn ();
- note_tmp = find_reg_note (insn_tmp, REG_EQUAL, NULL_RTX);
- gcc_assert (note_tmp);
- if (! rtx_equal_p (XEXP (note, 0), XEXP (note_tmp, 0)))
- {
- equal_p = false;
- break;
- }
- }
- if (! equal_p)
- {
- no_equiv (dest, set, NULL);
- continue;
- }
- }
- /* Record this insn as initializing this register. */
- reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv[regno].init_insns);
- /* If this register is known to be equal to a constant, record that
- it is always equivalent to the constant. */
- if (DF_REG_DEF_COUNT (regno) == 1
- && note && ! rtx_varies_p (XEXP (note, 0), 0))
- {
- rtx note_value = XEXP (note, 0);
- remove_note (insn, note);
- set_unique_reg_note (insn, REG_EQUIV, note_value);
- }
- /* If this insn introduces a "constant" register, decrease the priority
- of that register. Record this insn if the register is only used once
- more and the equivalence value is the same as our source.
- The latter condition is checked for two reasons: First, it is an
- indication that it may be more efficient to actually emit the insn
- as written (if no registers are available, reload will substitute
- the equivalence). Secondly, it avoids problems with any registers
- dying in this insn whose death notes would be missed.
- If we don't have a REG_EQUIV note, see if this insn is loading
- a register used only in one basic block from a MEM. If so, and the
- MEM remains unchanged for the life of the register, add a REG_EQUIV
- note. */
- note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note == NULL_RTX && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
- && MEM_P (SET_SRC (set))
- && validate_equiv_mem (insn, dest, SET_SRC (set)))
- note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (SET_SRC (set)));
- if (note)
- {
- int regno = REGNO (dest);
- rtx x = XEXP (note, 0);
- /* If we haven't done so, record for reload that this is an
- equivalencing insn. */
- if (!reg_equiv[regno].is_arg_equivalence)
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[regno].init_insns);
- /* Record whether or not we created a REG_EQUIV note for a LABEL_REF.
- We might end up substituting the LABEL_REF for uses of the
- pseudo here or later. That kind of transformation may turn an
- indirect jump into a direct jump, in which case we must rerun the
- jump optimizer to ensure that the JUMP_LABEL fields are valid. */
- if (GET_CODE (x) == LABEL_REF
- || (GET_CODE (x) == CONST
- && GET_CODE (XEXP (x, 0)) == PLUS
- && (GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)))
- recorded_label_ref = 1;
- reg_equiv[regno].replacement = x;
- reg_equiv[regno].src_p = &SET_SRC (set);
- reg_equiv[regno].loop_depth = (short) loop_depth;
- /* Don't mess with things live during setjmp. */
- if (REG_LIVE_LENGTH (regno) >= 0 && optimize)
- {
- /* Note that the statement below does not affect the priority
- in local-alloc! */
- REG_LIVE_LENGTH (regno) *= 2;
- /* If the register is referenced exactly twice, meaning it is
- set once and used once, indicate that the reference may be
- replaced by the equivalence we computed above. Do this
- even if the register is only used in one block so that
- dependencies can be handled where the last register is
- used in a different block (i.e. HIGH / LO_SUM sequences)
- and to reduce the number of registers alive across
- calls. */
- if (REG_N_REFS (regno) == 2
- && (rtx_equal_p (x, src)
- || ! equiv_init_varies_p (src))
- && NONJUMP_INSN_P (insn)
- && equiv_init_movable_p (PATTERN (insn), regno))
- reg_equiv[regno].replace = 1;
- }
- }
- }
- }
- if (!optimize)
- goto out;
- /* A second pass, to gather additional equivalences with memory. This needs
- to be done after we know which registers we are going to replace. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- rtx set, src, dest;
- unsigned regno;
- if (! INSN_P (insn))
- continue;
- set = single_set (insn);
- if (! set)
- continue;
- dest = SET_DEST (set);
- src = SET_SRC (set);
- /* If this sets a MEM to the contents of a REG that is only used
- in a single basic block, see if the register is always equivalent
- to that memory location and if moving the store from INSN to the
- insn that set REG is safe. If so, put a REG_EQUIV note on the
- initializing insn.
- Don't add a REG_EQUIV note if the insn already has one. The existing
- REG_EQUIV is likely more useful than the one we are adding.
- If one of the regs in the address has reg_equiv[REGNO].replace set,
- then we can't add this REG_EQUIV note. The reg_equiv[REGNO].replace
- optimization may move the set of this register immediately before
- insn, which puts it after reg_equiv[REGNO].init_insns, and hence
- the mention in the REG_EQUIV note would be to an uninitialized
- pseudo. */
- if (MEM_P (dest) && REG_P (src)
- && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
- && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
- && DF_REG_DEF_COUNT (regno) == 1
- && reg_equiv[regno].init_insns != NULL
- && reg_equiv[regno].init_insns->insn () != NULL
- && ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
- REG_EQUIV, NULL_RTX)
- && ! contains_replace_regs (XEXP (dest, 0))
- && ! pdx_subregs[regno])
- {
- rtx_insn *init_insn =
- as_a <rtx_insn *> (XEXP (reg_equiv[regno].init_insns, 0));
- if (validate_equiv_mem (init_insn, src, dest)
- && ! memref_used_between_p (dest, init_insn, insn)
- /* Attaching a REG_EQUIV note will fail if INIT_INSN has
- multiple sets. */
- && set_unique_reg_note (init_insn, REG_EQUIV, copy_rtx (dest)))
- {
- /* This insn makes the equivalence, not the one initializing
- the register. */
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
- df_notes_rescan (init_insn);
- }
- }
- }
- cleared_regs = BITMAP_ALLOC (NULL);
- /* Now scan all regs killed in an insn to see if any of them are
- registers only used that once. If so, see if we can replace the
- reference with the equivalent form. If we can, delete the
- initializing reference and this register will go away. If we
- can't replace the reference, and the initializing reference is
- within the same loop (or in an inner loop), then move the register
- initialization just before the use, so that they are in the same
- basic block. */
- FOR_EACH_BB_REVERSE_FN (bb, cfun)
- {
- loop_depth = bb_loop_depth (bb);
- for (insn = BB_END (bb);
- insn != PREV_INSN (BB_HEAD (bb));
- insn = PREV_INSN (insn))
- {
- rtx link;
- if (! INSN_P (insn))
- continue;
- /* Don't substitute into a non-local goto, this confuses CFG. */
- if (JUMP_P (insn)
- && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
- continue;
- for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- {
- if (REG_NOTE_KIND (link) == REG_DEAD
- /* Make sure this insn still refers to the register. */
- && reg_mentioned_p (XEXP (link, 0), PATTERN (insn)))
- {
- int regno = REGNO (XEXP (link, 0));
- rtx equiv_insn;
- if (! reg_equiv[regno].replace
- || reg_equiv[regno].loop_depth < (short) loop_depth
- /* There is no sense to move insns if live range
- shrinkage or register pressure-sensitive
- scheduling were done because it will not
- improve allocation but worsen insn schedule
- with a big probability. */
- || flag_live_range_shrinkage
- || (flag_sched_pressure && flag_schedule_insns))
- continue;
- /* reg_equiv[REGNO].replace gets set only when
- REG_N_REFS[REGNO] is 2, i.e. the register is set
- once and used once. (If it were only set, but
- not used, flow would have deleted the setting
- insns.) Hence there can only be one insn in
- reg_equiv[REGNO].init_insns. */
- gcc_assert (reg_equiv[regno].init_insns
- && !XEXP (reg_equiv[regno].init_insns, 1));
- equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
- /* We may not move instructions that can throw, since
- that changes basic block boundaries and we are not
- prepared to adjust the CFG to match. */
- if (can_throw_internal (equiv_insn))
- continue;
- if (asm_noperands (PATTERN (equiv_insn)) < 0
- && validate_replace_rtx (regno_reg_rtx[regno],
- *(reg_equiv[regno].src_p), insn))
- {
- rtx equiv_link;
- rtx last_link;
- rtx note;
- /* Find the last note. */
- for (last_link = link; XEXP (last_link, 1);
- last_link = XEXP (last_link, 1))
- ;
- /* Append the REG_DEAD notes from equiv_insn. */
- equiv_link = REG_NOTES (equiv_insn);
- while (equiv_link)
- {
- note = equiv_link;
- equiv_link = XEXP (equiv_link, 1);
- if (REG_NOTE_KIND (note) == REG_DEAD)
- {
- remove_note (equiv_insn, note);
- XEXP (last_link, 1) = note;
- XEXP (note, 1) = NULL_RTX;
- last_link = note;
- }
- }
- remove_death (regno, insn);
- SET_REG_N_REFS (regno, 0);
- REG_FREQ (regno) = 0;
- delete_insn (equiv_insn);
- reg_equiv[regno].init_insns
- = reg_equiv[regno].init_insns->next ();
- ira_reg_equiv[regno].init_insns = NULL;
- bitmap_set_bit (cleared_regs, regno);
- }
- /* Move the initialization of the register to just before
- INSN. Update the flow information. */
- else if (prev_nondebug_insn (insn) != equiv_insn)
- {
- rtx_insn *new_insn;
- new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
- REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
- REG_NOTES (equiv_insn) = 0;
- /* Rescan it to process the notes. */
- df_insn_rescan (new_insn);
- /* Make sure this insn is recognized before
- reload begins, otherwise
- eliminate_regs_in_insn will die. */
- INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
- delete_insn (equiv_insn);
- XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
- REG_BASIC_BLOCK (regno) = bb->index;
- REG_N_CALLS_CROSSED (regno) = 0;
- REG_FREQ_CALLS_CROSSED (regno) = 0;
- REG_N_THROWING_CALLS_CROSSED (regno) = 0;
- REG_LIVE_LENGTH (regno) = 2;
- if (insn == BB_HEAD (bb))
- BB_HEAD (bb) = PREV_INSN (insn);
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
- bitmap_set_bit (cleared_regs, regno);
- }
- }
- }
- }
- }
- if (!bitmap_empty_p (cleared_regs))
- {
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs);
- bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs);
- if (! df_live)
- continue;
- bitmap_and_compl_into (DF_LIVE_IN (bb), cleared_regs);
- bitmap_and_compl_into (DF_LIVE_OUT (bb), cleared_regs);
- }
- /* Last pass - adjust debug insns referencing cleared regs. */
- if (MAY_HAVE_DEBUG_INSNS)
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (DEBUG_INSN_P (insn))
- {
- rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
- INSN_VAR_LOCATION_LOC (insn)
- = simplify_replace_fn_rtx (old_loc, NULL_RTX,
- adjust_cleared_regs,
- (void *) cleared_regs);
- if (old_loc != INSN_VAR_LOCATION_LOC (insn))
- df_insn_rescan (insn);
- }
- }
- BITMAP_FREE (cleared_regs);
- out:
- /* Clean up. */
- end_alias_analysis ();
- free (reg_equiv);
- free (pdx_subregs);
- return recorded_label_ref;
- }
- /* Set up fields memory, constant, and invariant from init_insns in
- the structures of array ira_reg_equiv. */
- static void
- setup_reg_equiv (void)
- {
- int i;
- rtx_insn_list *elem, *prev_elem, *next_elem;
- rtx_insn *insn;
- rtx set, x;
- for (i = FIRST_PSEUDO_REGISTER; i < ira_reg_equiv_len; i++)
- for (prev_elem = NULL, elem = ira_reg_equiv[i].init_insns;
- elem;
- prev_elem = elem, elem = next_elem)
- {
- next_elem = elem->next ();
- insn = elem->insn ();
- set = single_set (insn);
-
- /* Init insns can set up equivalence when the reg is a destination or
- a source (in this case the destination is memory). */
- if (set != 0 && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))))
- {
- if ((x = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL)
- {
- x = XEXP (x, 0);
- if (REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == (unsigned int) i
- && ! rtx_equal_p (SET_SRC (set), x) && MEM_P (x))
- {
- /* This insn reporting the equivalence but
- actually not setting it. Remove it from the
- list. */
- if (prev_elem == NULL)
- ira_reg_equiv[i].init_insns = next_elem;
- else
- XEXP (prev_elem, 1) = next_elem;
- elem = prev_elem;
- }
- }
- else if (REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == (unsigned int) i)
- x = SET_SRC (set);
- else
- {
- gcc_assert (REG_P (SET_SRC (set))
- && REGNO (SET_SRC (set)) == (unsigned int) i);
- x = SET_DEST (set);
- }
- if (! function_invariant_p (x)
- || ! flag_pic
- /* A function invariant is often CONSTANT_P but may
- include a register. We promise to only pass
- CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
- || (CONSTANT_P (x) && LEGITIMATE_PIC_OPERAND_P (x)))
- {
- /* It can happen that a REG_EQUIV note contains a MEM
- that is not a legitimate memory operand. As later
- stages of reload assume that all addresses found in
- the lra_regno_equiv_* arrays were originally
- legitimate, we ignore such REG_EQUIV notes. */
- if (memory_operand (x, VOIDmode))
- {
- ira_reg_equiv[i].defined_p = true;
- ira_reg_equiv[i].memory = x;
- continue;
- }
- else if (function_invariant_p (x))
- {
- machine_mode mode;
-
- mode = GET_MODE (SET_DEST (set));
- if (GET_CODE (x) == PLUS
- || x == frame_pointer_rtx || x == arg_pointer_rtx)
- /* This is PLUS of frame pointer and a constant,
- or fp, or argp. */
- ira_reg_equiv[i].invariant = x;
- else if (targetm.legitimate_constant_p (mode, x))
- ira_reg_equiv[i].constant = x;
- else
- {
- ira_reg_equiv[i].memory = force_const_mem (mode, x);
- if (ira_reg_equiv[i].memory == NULL_RTX)
- {
- ira_reg_equiv[i].defined_p = false;
- ira_reg_equiv[i].init_insns = NULL;
- break;
- }
- }
- ira_reg_equiv[i].defined_p = true;
- continue;
- }
- }
- }
- ira_reg_equiv[i].defined_p = false;
- ira_reg_equiv[i].init_insns = NULL;
- break;
- }
- }
- /* Print chain C to FILE. */
- static void
- print_insn_chain (FILE *file, struct insn_chain *c)
- {
- fprintf (file, "insn=%d, ", INSN_UID (c->insn));
- bitmap_print (file, &c->live_throughout, "live_throughout: ", ", ");
- bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
- }
- /* Print all reload_insn_chains to FILE. */
- static void
- print_insn_chains (FILE *file)
- {
- struct insn_chain *c;
- for (c = reload_insn_chain; c ; c = c->next)
- print_insn_chain (file, c);
- }
- /* Return true if pseudo REGNO should be added to set live_throughout
- or dead_or_set of the insn chains for reload consideration. */
- static bool
- pseudo_for_reload_consideration_p (int regno)
- {
- /* Consider spilled pseudos too for IRA because they still have a
- chance to get hard-registers in the reload when IRA is used. */
- return (reg_renumber[regno] >= 0 || ira_conflicts_p);
- }
- /* Init LIVE_SUBREGS[ALLOCNUM] and LIVE_SUBREGS_USED[ALLOCNUM] using
- REG to the number of nregs, and INIT_VALUE to get the
- initialization. ALLOCNUM need not be the regno of REG. */
- static void
- init_live_subregs (bool init_value, sbitmap *live_subregs,
- bitmap live_subregs_used, int allocnum, rtx reg)
- {
- unsigned int regno = REGNO (SUBREG_REG (reg));
- int size = GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno]));
- gcc_assert (size > 0);
- /* Been there, done that. */
- if (bitmap_bit_p (live_subregs_used, allocnum))
- return;
- /* Create a new one. */
- if (live_subregs[allocnum] == NULL)
- live_subregs[allocnum] = sbitmap_alloc (size);
- /* If the entire reg was live before blasting into subregs, we need
- to init all of the subregs to ones else init to 0. */
- if (init_value)
- bitmap_ones (live_subregs[allocnum]);
- else
- bitmap_clear (live_subregs[allocnum]);
- bitmap_set_bit (live_subregs_used, allocnum);
- }
- /* Walk the insns of the current function and build reload_insn_chain,
- and record register life information. */
- static void
- build_insn_chain (void)
- {
- unsigned int i;
- struct insn_chain **p = &reload_insn_chain;
- basic_block bb;
- struct insn_chain *c = NULL;
- struct insn_chain *next = NULL;
- bitmap live_relevant_regs = BITMAP_ALLOC (NULL);
- bitmap elim_regset = BITMAP_ALLOC (NULL);
- /* live_subregs is a vector used to keep accurate information about
- which hardregs are live in multiword pseudos. live_subregs and
- live_subregs_used are indexed by pseudo number. The live_subreg
- entry for a particular pseudo is only used if the corresponding
- element is non zero in live_subregs_used. The sbitmap size of
- live_subreg[allocno] is number of bytes that the pseudo can
- occupy. */
- sbitmap *live_subregs = XCNEWVEC (sbitmap, max_regno);
- bitmap live_subregs_used = BITMAP_ALLOC (NULL);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (eliminable_regset, i))
- bitmap_set_bit (elim_regset, i);
- FOR_EACH_BB_REVERSE_FN (bb, cfun)
- {
- bitmap_iterator bi;
- rtx_insn *insn;
- CLEAR_REG_SET (live_relevant_regs);
- bitmap_clear (live_subregs_used);
- EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), 0, i, bi)
- {
- if (i >= FIRST_PSEUDO_REGISTER)
- break;
- bitmap_set_bit (live_relevant_regs, i);
- }
- EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb),
- FIRST_PSEUDO_REGISTER, i, bi)
- {
- if (pseudo_for_reload_consideration_p (i))
- bitmap_set_bit (live_relevant_regs, i);
- }
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- if (!NOTE_P (insn) && !BARRIER_P (insn))
- {
- struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- df_ref def, use;
- c = new_insn_chain ();
- c->next = next;
- next = c;
- *p = c;
- p = &c->prev;
- c->insn = insn;
- c->block = bb->index;
- if (NONDEBUG_INSN_P (insn))
- FOR_EACH_INSN_INFO_DEF (def, insn_info)
- {
- unsigned int regno = DF_REF_REGNO (def);
- /* Ignore may clobbers because these are generated
- from calls. However, every other kind of def is
- added to dead_or_set. */
- if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- if (!fixed_regs[regno])
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- else if (pseudo_for_reload_consideration_p (regno))
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- if ((regno < FIRST_PSEUDO_REGISTER
- || reg_renumber[regno] >= 0
- || ira_conflicts_p)
- && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
- {
- rtx reg = DF_REF_REG (def);
- /* We can model subregs, but not if they are
- wrapped in ZERO_EXTRACTS. */
- if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
- {
- unsigned int start = SUBREG_BYTE (reg);
- unsigned int last = start
- + GET_MODE_SIZE (GET_MODE (reg));
- init_live_subregs
- (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used, regno, reg);
- if (!DF_REF_FLAGS_IS_SET
- (def, DF_REF_STRICT_LOW_PART))
- {
- /* Expand the range to cover entire words.
- Bytes added here are "don't care". */
- start
- = start / UNITS_PER_WORD * UNITS_PER_WORD;
- last = ((last + UNITS_PER_WORD - 1)
- / UNITS_PER_WORD * UNITS_PER_WORD);
- }
- /* Ignore the paradoxical bits. */
- if (last > SBITMAP_SIZE (live_subregs[regno]))
- last = SBITMAP_SIZE (live_subregs[regno]);
- while (start < last)
- {
- bitmap_clear_bit (live_subregs[regno], start);
- start++;
- }
- if (bitmap_empty_p (live_subregs[regno]))
- {
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_clear_bit (live_relevant_regs, regno);
- }
- else
- /* Set live_relevant_regs here because
- that bit has to be true to get us to
- look at the live_subregs fields. */
- bitmap_set_bit (live_relevant_regs, regno);
- }
- else
- {
- /* DF_REF_PARTIAL is generated for
- subregs, STRICT_LOW_PART, and
- ZERO_EXTRACT. We handle the subreg
- case above so here we have to keep from
- modeling the def as a killing def. */
- if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL))
- {
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_clear_bit (live_relevant_regs, regno);
- }
- }
- }
- }
- bitmap_and_compl_into (live_relevant_regs, elim_regset);
- bitmap_copy (&c->live_throughout, live_relevant_regs);
- if (NONDEBUG_INSN_P (insn))
- FOR_EACH_INSN_INFO_USE (use, insn_info)
- {
- unsigned int regno = DF_REF_REGNO (use);
- rtx reg = DF_REF_REG (use);
- /* DF_REF_READ_WRITE on a use means that this use
- is fabricated from a def that is a partial set
- to a multiword reg. Here, we only model the
- subreg case that is not wrapped in ZERO_EXTRACT
- precisely so we do not need to look at the
- fabricated use. */
- if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE)
- && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)
- && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
- continue;
- /* Add the last use of each var to dead_or_set. */
- if (!bitmap_bit_p (live_relevant_regs, regno))
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- if (!fixed_regs[regno])
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- else if (pseudo_for_reload_consideration_p (regno))
- bitmap_set_bit (&c->dead_or_set, regno);
- }
- if (regno < FIRST_PSEUDO_REGISTER
- || pseudo_for_reload_consideration_p (regno))
- {
- if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (use,
- DF_REF_SIGN_EXTRACT
- | DF_REF_ZERO_EXTRACT))
- {
- unsigned int start = SUBREG_BYTE (reg);
- unsigned int last = start
- + GET_MODE_SIZE (GET_MODE (reg));
- init_live_subregs
- (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used, regno, reg);
- /* Ignore the paradoxical bits. */
- if (last > SBITMAP_SIZE (live_subregs[regno]))
- last = SBITMAP_SIZE (live_subregs[regno]);
- while (start < last)
- {
- bitmap_set_bit (live_subregs[regno], start);
- start++;
- }
- }
- else
- /* Resetting the live_subregs_used is
- effectively saying do not use the subregs
- because we are reading the whole
- pseudo. */
- bitmap_clear_bit (live_subregs_used, regno);
- bitmap_set_bit (live_relevant_regs, regno);
- }
- }
- }
- }
- /* FIXME!! The following code is a disaster. Reload needs to see the
- labels and jump tables that are just hanging out in between
- the basic blocks. See pr33676. */
- insn = BB_HEAD (bb);
- /* Skip over the barriers and cruft. */
- while (insn && (BARRIER_P (insn) || NOTE_P (insn)
- || BLOCK_FOR_INSN (insn) == bb))
- insn = PREV_INSN (insn);
- /* While we add anything except barriers and notes, the focus is
- to get the labels and jump tables into the
- reload_insn_chain. */
- while (insn)
- {
- if (!NOTE_P (insn) && !BARRIER_P (insn))
- {
- if (BLOCK_FOR_INSN (insn))
- break;
- c = new_insn_chain ();
- c->next = next;
- next = c;
- *p = c;
- p = &c->prev;
- /* The block makes no sense here, but it is what the old
- code did. */
- c->block = bb->index;
- c->insn = insn;
- bitmap_copy (&c->live_throughout, live_relevant_regs);
- }
- insn = PREV_INSN (insn);
- }
- }
- reload_insn_chain = c;
- *p = NULL;
- for (i = 0; i < (unsigned int) max_regno; i++)
- if (live_subregs[i] != NULL)
- sbitmap_free (live_subregs[i]);
- free (live_subregs);
- BITMAP_FREE (live_subregs_used);
- BITMAP_FREE (live_relevant_regs);
- BITMAP_FREE (elim_regset);
- if (dump_file)
- print_insn_chains (dump_file);
- }
-
- /* Examine the rtx found in *LOC, which is read or written to as determined
- by TYPE. Return false if we find a reason why an insn containing this
- rtx should not be moved (such as accesses to non-constant memory), true
- otherwise. */
- static bool
- rtx_moveable_p (rtx *loc, enum op_type type)
- {
- const char *fmt;
- rtx x = *loc;
- enum rtx_code code = GET_CODE (x);
- int i, j;
- code = GET_CODE (x);
- switch (code)
- {
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- return true;
- case PC:
- return type == OP_IN;
- case CC0:
- return false;
- case REG:
- if (x == frame_pointer_rtx)
- return true;
- if (HARD_REGISTER_P (x))
- return false;
-
- return true;
- case MEM:
- if (type == OP_IN && MEM_READONLY_P (x))
- return rtx_moveable_p (&XEXP (x, 0), OP_IN);
- return false;
- case SET:
- return (rtx_moveable_p (&SET_SRC (x), OP_IN)
- && rtx_moveable_p (&SET_DEST (x), OP_OUT));
- case STRICT_LOW_PART:
- return rtx_moveable_p (&XEXP (x, 0), OP_OUT);
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- return (rtx_moveable_p (&XEXP (x, 0), type)
- && rtx_moveable_p (&XEXP (x, 1), OP_IN)
- && rtx_moveable_p (&XEXP (x, 2), OP_IN));
- case CLOBBER:
- return rtx_moveable_p (&SET_DEST (x), OP_OUT);
- case UNSPEC_VOLATILE:
- /* It is a bad idea to consider insns with with such rtl
- as moveable ones. The insn scheduler also considers them as barrier
- for a reason. */
- return false;
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (!rtx_moveable_p (&XEXP (x, i), type))
- return false;
- }
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- {
- if (!rtx_moveable_p (&XVECEXP (x, i, j), type))
- return false;
- }
- }
- return true;
- }
- /* A wrapper around dominated_by_p, which uses the information in UID_LUID
- to give dominance relationships between two insns I1 and I2. */
- static bool
- insn_dominated_by_p (rtx i1, rtx i2, int *uid_luid)
- {
- basic_block bb1 = BLOCK_FOR_INSN (i1);
- basic_block bb2 = BLOCK_FOR_INSN (i2);
- if (bb1 == bb2)
- return uid_luid[INSN_UID (i2)] < uid_luid[INSN_UID (i1)];
- return dominated_by_p (CDI_DOMINATORS, bb1, bb2);
- }
- /* Record the range of register numbers added by find_moveable_pseudos. */
- int first_moveable_pseudo, last_moveable_pseudo;
- /* These two vectors hold data for every register added by
- find_movable_pseudos, with index 0 holding data for the
- first_moveable_pseudo. */
- /* The original home register. */
- static vec<rtx> pseudo_replaced_reg;
- /* Look for instances where we have an instruction that is known to increase
- register pressure, and whose result is not used immediately. If it is
- possible to move the instruction downwards to just before its first use,
- split its lifetime into two ranges. We create a new pseudo to compute the
- value, and emit a move instruction just before the first use. If, after
- register allocation, the new pseudo remains unallocated, the function
- move_unallocated_pseudos then deletes the move instruction and places
- the computation just before the first use.
- Such a move is safe and profitable if all the input registers remain live
- and unchanged between the original computation and its first use. In such
- a situation, the computation is known to increase register pressure, and
- moving it is known to at least not worsen it.
- We restrict moves to only those cases where a register remains unallocated,
- in order to avoid interfering too much with the instruction schedule. As
- an exception, we may move insns which only modify their input register
- (typically induction variables), as this increases the freedom for our
- intended transformation, and does not limit the second instruction
- scheduler pass. */
-
- static void
- find_moveable_pseudos (void)
- {
- unsigned i;
- int max_regs = max_reg_num ();
- int max_uid = get_max_uid ();
- basic_block bb;
- int *uid_luid = XNEWVEC (int, max_uid);
- rtx_insn **closest_uses = XNEWVEC (rtx_insn *, max_regs);
- /* A set of registers which are live but not modified throughout a block. */
- bitmap_head *bb_transp_live = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- /* A set of registers which only exist in a given basic block. */
- bitmap_head *bb_local = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- /* A set of registers which are set once, in an instruction that can be
- moved freely downwards, but are otherwise transparent to a block. */
- bitmap_head *bb_moveable_reg_sets = XNEWVEC (bitmap_head,
- last_basic_block_for_fn (cfun));
- bitmap_head live, used, set, interesting, unusable_as_input;
- bitmap_iterator bi;
- bitmap_initialize (&interesting, 0);
- first_moveable_pseudo = max_regs;
- pseudo_replaced_reg.release ();
- pseudo_replaced_reg.safe_grow_cleared (max_regs);
- df_analyze ();
- calculate_dominance_info (CDI_DOMINATORS);
- i = 0;
- bitmap_initialize (&live, 0);
- bitmap_initialize (&used, 0);
- bitmap_initialize (&set, 0);
- bitmap_initialize (&unusable_as_input, 0);
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
- bitmap transp = bb_transp_live + bb->index;
- bitmap moveable = bb_moveable_reg_sets + bb->index;
- bitmap local = bb_local + bb->index;
- bitmap_initialize (local, 0);
- bitmap_initialize (transp, 0);
- bitmap_initialize (moveable, 0);
- bitmap_copy (&live, df_get_live_out (bb));
- bitmap_and_into (&live, df_get_live_in (bb));
- bitmap_copy (transp, &live);
- bitmap_clear (moveable);
- bitmap_clear (&live);
- bitmap_clear (&used);
- bitmap_clear (&set);
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- {
- df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- df_ref def, use;
- uid_luid[INSN_UID (insn)] = i++;
-
- def = df_single_def (insn_info);
- use = df_single_use (insn_info);
- if (use
- && def
- && DF_REF_REGNO (use) == DF_REF_REGNO (def)
- && !bitmap_bit_p (&set, DF_REF_REGNO (use))
- && rtx_moveable_p (&PATTERN (insn), OP_IN))
- {
- unsigned regno = DF_REF_REGNO (use);
- bitmap_set_bit (moveable, regno);
- bitmap_set_bit (&set, regno);
- bitmap_set_bit (&used, regno);
- bitmap_clear_bit (transp, regno);
- continue;
- }
- FOR_EACH_INSN_INFO_USE (use, insn_info)
- {
- unsigned regno = DF_REF_REGNO (use);
- bitmap_set_bit (&used, regno);
- if (bitmap_clear_bit (moveable, regno))
- bitmap_clear_bit (transp, regno);
- }
- FOR_EACH_INSN_INFO_DEF (def, insn_info)
- {
- unsigned regno = DF_REF_REGNO (def);
- bitmap_set_bit (&set, regno);
- bitmap_clear_bit (transp, regno);
- bitmap_clear_bit (moveable, regno);
- }
- }
- }
- bitmap_clear (&live);
- bitmap_clear (&used);
- bitmap_clear (&set);
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap local = bb_local + bb->index;
- rtx_insn *insn;
- FOR_BB_INSNS (bb, insn)
- if (NONDEBUG_INSN_P (insn))
- {
- df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
- rtx_insn *def_insn;
- rtx closest_use, note;
- df_ref def, use;
- unsigned regno;
- bool all_dominated, all_local;
- machine_mode mode;
- def = df_single_def (insn_info);
- /* There must be exactly one def in this insn. */
- if (!def || !single_set (insn))
- continue;
- /* This must be the only definition of the reg. We also limit
- which modes we deal with so that we can assume we can generate
- move instructions. */
- regno = DF_REF_REGNO (def);
- mode = GET_MODE (DF_REF_REG (def));
- if (DF_REG_DEF_COUNT (regno) != 1
- || !DF_REF_INSN_INFO (def)
- || HARD_REGISTER_NUM_P (regno)
- || DF_REG_EQ_USE_COUNT (regno) > 0
- || (!INTEGRAL_MODE_P (mode) && !FLOAT_MODE_P (mode)))
- continue;
- def_insn = DF_REF_INSN (def);
- for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_EQUIV && MEM_P (XEXP (note, 0)))
- break;
-
- if (note)
- {
- if (dump_file)
- fprintf (dump_file, "Ignoring reg %d, has equiv memory\n",
- regno);
- bitmap_set_bit (&unusable_as_input, regno);
- continue;
- }
- use = DF_REG_USE_CHAIN (regno);
- all_dominated = true;
- all_local = true;
- closest_use = NULL_RTX;
- for (; use; use = DF_REF_NEXT_REG (use))
- {
- rtx_insn *insn;
- if (!DF_REF_INSN_INFO (use))
- {
- all_dominated = false;
- all_local = false;
- break;
- }
- insn = DF_REF_INSN (use);
- if (DEBUG_INSN_P (insn))
- continue;
- if (BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (def_insn))
- all_local = false;
- if (!insn_dominated_by_p (insn, def_insn, uid_luid))
- all_dominated = false;
- if (closest_use != insn && closest_use != const0_rtx)
- {
- if (closest_use == NULL_RTX)
- closest_use = insn;
- else if (insn_dominated_by_p (closest_use, insn, uid_luid))
- closest_use = insn;
- else if (!insn_dominated_by_p (insn, closest_use, uid_luid))
- closest_use = const0_rtx;
- }
- }
- if (!all_dominated)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d not all uses dominated by set\n",
- regno);
- continue;
- }
- if (all_local)
- bitmap_set_bit (local, regno);
- if (closest_use == const0_rtx || closest_use == NULL
- || next_nonnote_nondebug_insn (def_insn) == closest_use)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d uninteresting%s\n", regno,
- closest_use == const0_rtx || closest_use == NULL
- ? " (no unique first use)" : "");
- continue;
- }
- #ifdef HAVE_cc0
- if (reg_referenced_p (cc0_rtx, PATTERN (closest_use)))
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d: closest user uses cc0\n",
- regno);
- continue;
- }
- #endif
- bitmap_set_bit (&interesting, regno);
- /* If we get here, we know closest_use is a non-NULL insn
- (as opposed to const_0_rtx). */
- closest_uses[regno] = as_a <rtx_insn *> (closest_use);
- if (dump_file && (all_local || all_dominated))
- {
- fprintf (dump_file, "Reg %u:", regno);
- if (all_local)
- fprintf (dump_file, " local to bb %d", bb->index);
- if (all_dominated)
- fprintf (dump_file, " def dominates all uses");
- if (closest_use != const0_rtx)
- fprintf (dump_file, " has unique first use");
- fputs ("\n", dump_file);
- }
- }
- }
- EXECUTE_IF_SET_IN_BITMAP (&interesting, 0, i, bi)
- {
- df_ref def = DF_REG_DEF_CHAIN (i);
- rtx_insn *def_insn = DF_REF_INSN (def);
- basic_block def_block = BLOCK_FOR_INSN (def_insn);
- bitmap def_bb_local = bb_local + def_block->index;
- bitmap def_bb_moveable = bb_moveable_reg_sets + def_block->index;
- bitmap def_bb_transp = bb_transp_live + def_block->index;
- bool local_to_bb_p = bitmap_bit_p (def_bb_local, i);
- rtx_insn *use_insn = closest_uses[i];
- df_ref use;
- bool all_ok = true;
- bool all_transp = true;
- if (!REG_P (DF_REF_REG (def)))
- continue;
- if (!local_to_bb_p)
- {
- if (dump_file)
- fprintf (dump_file, "Reg %u not local to one basic block\n",
- i);
- continue;
- }
- if (reg_equiv_init (i) != NULL_RTX)
- {
- if (dump_file)
- fprintf (dump_file, "Ignoring reg %u with equiv init insn\n",
- i);
- continue;
- }
- if (!rtx_moveable_p (&PATTERN (def_insn), OP_IN))
- {
- if (dump_file)
- fprintf (dump_file, "Found def insn %d for %d to be not moveable\n",
- INSN_UID (def_insn), i);
- continue;
- }
- if (dump_file)
- fprintf (dump_file, "Examining insn %d, def for %d\n",
- INSN_UID (def_insn), i);
- FOR_EACH_INSN_USE (use, def_insn)
- {
- unsigned regno = DF_REF_REGNO (use);
- if (bitmap_bit_p (&unusable_as_input, regno))
- {
- all_ok = false;
- if (dump_file)
- fprintf (dump_file, " found unusable input reg %u.\n", regno);
- break;
- }
- if (!bitmap_bit_p (def_bb_transp, regno))
- {
- if (bitmap_bit_p (def_bb_moveable, regno)
- && !control_flow_insn_p (use_insn)
- #ifdef HAVE_cc0
- && !sets_cc0_p (use_insn)
- #endif
- )
- {
- if (modified_between_p (DF_REF_REG (use), def_insn, use_insn))
- {
- rtx_insn *x = NEXT_INSN (def_insn);
- while (!modified_in_p (DF_REF_REG (use), x))
- {
- gcc_assert (x != use_insn);
- x = NEXT_INSN (x);
- }
- if (dump_file)
- fprintf (dump_file, " input reg %u modified but insn %d moveable\n",
- regno, INSN_UID (x));
- emit_insn_after (PATTERN (x), use_insn);
- set_insn_deleted (x);
- }
- else
- {
- if (dump_file)
- fprintf (dump_file, " input reg %u modified between def and use\n",
- regno);
- all_transp = false;
- }
- }
- else
- all_transp = false;
- }
- }
- if (!all_ok)
- continue;
- if (!dbg_cnt (ira_move))
- break;
- if (dump_file)
- fprintf (dump_file, " all ok%s\n", all_transp ? " and transp" : "");
- if (all_transp)
- {
- rtx def_reg = DF_REF_REG (def);
- rtx newreg = ira_create_new_reg (def_reg);
- if (validate_change (def_insn, DF_REF_REAL_LOC (def), newreg, 0))
- {
- unsigned nregno = REGNO (newreg);
- emit_insn_before (gen_move_insn (def_reg, newreg), use_insn);
- nregno -= max_regs;
- pseudo_replaced_reg[nregno] = def_reg;
- }
- }
- }
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- bitmap_clear (bb_local + bb->index);
- bitmap_clear (bb_transp_live + bb->index);
- bitmap_clear (bb_moveable_reg_sets + bb->index);
- }
- bitmap_clear (&interesting);
- bitmap_clear (&unusable_as_input);
- free (uid_luid);
- free (closest_uses);
- free (bb_local);
- free (bb_transp_live);
- free (bb_moveable_reg_sets);
- last_moveable_pseudo = max_reg_num ();
- fix_reg_equiv_init ();
- expand_reg_info ();
- regstat_free_n_sets_and_refs ();
- regstat_free_ri ();
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
- free_dominance_info (CDI_DOMINATORS);
- }
- /* If SET pattern SET is an assignment from a hard register to a pseudo which
- is live at CALL_DOM (if non-NULL, otherwise this check is omitted), return
- the destination. Otherwise return NULL. */
- static rtx
- interesting_dest_for_shprep_1 (rtx set, basic_block call_dom)
- {
- rtx src = SET_SRC (set);
- rtx dest = SET_DEST (set);
- if (!REG_P (src) || !HARD_REGISTER_P (src)
- || !REG_P (dest) || HARD_REGISTER_P (dest)
- || (call_dom && !bitmap_bit_p (df_get_live_in (call_dom), REGNO (dest))))
- return NULL;
- return dest;
- }
- /* If insn is interesting for parameter range-splitting shrink-wrapping
- preparation, i.e. it is a single set from a hard register to a pseudo, which
- is live at CALL_DOM (if non-NULL, otherwise this check is omitted), or a
- parallel statement with only one such statement, return the destination.
- Otherwise return NULL. */
- static rtx
- interesting_dest_for_shprep (rtx_insn *insn, basic_block call_dom)
- {
- if (!INSN_P (insn))
- return NULL;
- rtx pat = PATTERN (insn);
- if (GET_CODE (pat) == SET)
- return interesting_dest_for_shprep_1 (pat, call_dom);
- if (GET_CODE (pat) != PARALLEL)
- return NULL;
- rtx ret = NULL;
- for (int i = 0; i < XVECLEN (pat, 0); i++)
- {
- rtx sub = XVECEXP (pat, 0, i);
- if (GET_CODE (sub) == USE || GET_CODE (sub) == CLOBBER)
- continue;
- if (GET_CODE (sub) != SET
- || side_effects_p (sub))
- return NULL;
- rtx dest = interesting_dest_for_shprep_1 (sub, call_dom);
- if (dest && ret)
- return NULL;
- if (dest)
- ret = dest;
- }
- return ret;
- }
- /* Split live ranges of pseudos that are loaded from hard registers in the
- first BB in a BB that dominates all non-sibling call if such a BB can be
- found and is not in a loop. Return true if the function has made any
- changes. */
- static bool
- split_live_ranges_for_shrink_wrap (void)
- {
- basic_block bb, call_dom = NULL;
- basic_block first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
- rtx_insn *insn, *last_interesting_insn = NULL;
- bitmap_head need_new, reachable;
- vec<basic_block> queue;
- if (!SHRINK_WRAPPING_ENABLED)
- return false;
- bitmap_initialize (&need_new, 0);
- bitmap_initialize (&reachable, 0);
- queue.create (n_basic_blocks_for_fn (cfun));
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS (bb, insn)
- if (CALL_P (insn) && !SIBLING_CALL_P (insn))
- {
- if (bb == first)
- {
- bitmap_clear (&need_new);
- bitmap_clear (&reachable);
- queue.release ();
- return false;
- }
- bitmap_set_bit (&need_new, bb->index);
- bitmap_set_bit (&reachable, bb->index);
- queue.quick_push (bb);
- break;
- }
- if (queue.is_empty ())
- {
- bitmap_clear (&need_new);
- bitmap_clear (&reachable);
- queue.release ();
- return false;
- }
- while (!queue.is_empty ())
- {
- edge e;
- edge_iterator ei;
- bb = queue.pop ();
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
- && bitmap_set_bit (&reachable, e->dest->index))
- queue.quick_push (e->dest);
- }
- queue.release ();
- FOR_BB_INSNS (first, insn)
- {
- rtx dest = interesting_dest_for_shprep (insn, NULL);
- if (!dest)
- continue;
- if (DF_REG_DEF_COUNT (REGNO (dest)) > 1)
- {
- bitmap_clear (&need_new);
- bitmap_clear (&reachable);
- return false;
- }
- for (df_ref use = DF_REG_USE_CHAIN (REGNO(dest));
- use;
- use = DF_REF_NEXT_REG (use))
- {
- int ubbi = DF_REF_BB (use)->index;
- if (bitmap_bit_p (&reachable, ubbi))
- bitmap_set_bit (&need_new, ubbi);
- }
- last_interesting_insn = insn;
- }
- bitmap_clear (&reachable);
- if (!last_interesting_insn)
- {
- bitmap_clear (&need_new);
- return false;
- }
- call_dom = nearest_common_dominator_for_set (CDI_DOMINATORS, &need_new);
- bitmap_clear (&need_new);
- if (call_dom == first)
- return false;
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
- while (bb_loop_depth (call_dom) > 0)
- call_dom = get_immediate_dominator (CDI_DOMINATORS, call_dom);
- loop_optimizer_finalize ();
- if (call_dom == first)
- return false;
- calculate_dominance_info (CDI_POST_DOMINATORS);
- if (dominated_by_p (CDI_POST_DOMINATORS, first, call_dom))
- {
- free_dominance_info (CDI_POST_DOMINATORS);
- return false;
- }
- free_dominance_info (CDI_POST_DOMINATORS);
- if (dump_file)
- fprintf (dump_file, "Will split live ranges of parameters at BB %i\n",
- call_dom->index);
- bool ret = false;
- FOR_BB_INSNS (first, insn)
- {
- rtx dest = interesting_dest_for_shprep (insn, call_dom);
- if (!dest || dest == pic_offset_table_rtx)
- continue;
- rtx newreg = NULL_RTX;
- df_ref use, next;
- for (use = DF_REG_USE_CHAIN (REGNO (dest)); use; use = next)
- {
- rtx_insn *uin = DF_REF_INSN (use);
- next = DF_REF_NEXT_REG (use);
- basic_block ubb = BLOCK_FOR_INSN (uin);
- if (ubb == call_dom
- || dominated_by_p (CDI_DOMINATORS, ubb, call_dom))
- {
- if (!newreg)
- newreg = ira_create_new_reg (dest);
- validate_change (uin, DF_REF_REAL_LOC (use), newreg, true);
- }
- }
- if (newreg)
- {
- rtx new_move = gen_move_insn (newreg, dest);
- emit_insn_after (new_move, bb_note (call_dom));
- if (dump_file)
- {
- fprintf (dump_file, "Split live-range of register ");
- print_rtl_single (dump_file, dest);
- }
- ret = true;
- }
- if (insn == last_interesting_insn)
- break;
- }
- apply_change_group ();
- return ret;
- }
- /* Perform the second half of the transformation started in
- find_moveable_pseudos. We look for instances where the newly introduced
- pseudo remains unallocated, and remove it by moving the definition to
- just before its use, replacing the move instruction generated by
- find_moveable_pseudos. */
- static void
- move_unallocated_pseudos (void)
- {
- int i;
- for (i = first_moveable_pseudo; i < last_moveable_pseudo; i++)
- if (reg_renumber[i] < 0)
- {
- int idx = i - first_moveable_pseudo;
- rtx other_reg = pseudo_replaced_reg[idx];
- rtx_insn *def_insn = DF_REF_INSN (DF_REG_DEF_CHAIN (i));
- /* The use must follow all definitions of OTHER_REG, so we can
- insert the new definition immediately after any of them. */
- df_ref other_def = DF_REG_DEF_CHAIN (REGNO (other_reg));
- rtx_insn *move_insn = DF_REF_INSN (other_def);
- rtx_insn *newinsn = emit_insn_after (PATTERN (def_insn), move_insn);
- rtx set;
- int success;
- if (dump_file)
- fprintf (dump_file, "moving def of %d (insn %d now) ",
- REGNO (other_reg), INSN_UID (def_insn));
- delete_insn (move_insn);
- while ((other_def = DF_REG_DEF_CHAIN (REGNO (other_reg))))
- delete_insn (DF_REF_INSN (other_def));
- delete_insn (def_insn);
- set = single_set (newinsn);
- success = validate_change (newinsn, &SET_DEST (set), other_reg, 0);
- gcc_assert (success);
- if (dump_file)
- fprintf (dump_file, " %d) rather than keep unallocated replacement %d\n",
- INSN_UID (newinsn), i);
- SET_REG_N_REFS (i, 0);
- }
- }
- /* If the backend knows where to allocate pseudos for hard
- register initial values, register these allocations now. */
- static void
- allocate_initial_values (void)
- {
- if (targetm.allocate_initial_value)
- {
- rtx hreg, preg, x;
- int i, regno;
- for (i = 0; HARD_REGISTER_NUM_P (i); i++)
- {
- if (! initial_value_entry (i, &hreg, &preg))
- break;
- x = targetm.allocate_initial_value (hreg);
- regno = REGNO (preg);
- if (x && REG_N_SETS (regno) <= 1)
- {
- if (MEM_P (x))
- reg_equiv_memory_loc (regno) = x;
- else
- {
- basic_block bb;
- int new_regno;
- gcc_assert (REG_P (x));
- new_regno = REGNO (x);
- reg_renumber[regno] = new_regno;
- /* Poke the regno right into regno_reg_rtx so that even
- fixed regs are accepted. */
- SET_REGNO (preg, new_regno);
- /* Update global register liveness information. */
- FOR_EACH_BB_FN (bb, cfun)
- {
- if (REGNO_REG_SET_P (df_get_live_in (bb), regno))
- SET_REGNO_REG_SET (df_get_live_in (bb), new_regno);
- if (REGNO_REG_SET_P (df_get_live_out (bb), regno))
- SET_REGNO_REG_SET (df_get_live_out (bb), new_regno);
- }
- }
- }
- }
- gcc_checking_assert (! initial_value_entry (FIRST_PSEUDO_REGISTER,
- &hreg, &preg));
- }
- }
- /* True when we use LRA instead of reload pass for the current
- function. */
- bool ira_use_lra_p;
- /* True if we have allocno conflicts. It is false for non-optimized
- mode or when the conflict table is too big. */
- bool ira_conflicts_p;
- /* Saved between IRA and reload. */
- static int saved_flag_ira_share_spill_slots;
- /* This is the main entry of IRA. */
- static void
- ira (FILE *f)
- {
- bool loops_p;
- int ira_max_point_before_emit;
- int rebuild_p;
- bool saved_flag_caller_saves = flag_caller_saves;
- enum ira_region saved_flag_ira_region = flag_ira_region;
- /* Perform target specific PIC register initialization. */
- targetm.init_pic_reg ();
- ira_conflicts_p = optimize > 0;
- ira_use_lra_p = targetm.lra_p ();
- /* If there are too many pseudos and/or basic blocks (e.g. 10K
- pseudos and 10K blocks or 100K pseudos and 1K blocks), we will
- use simplified and faster algorithms in LRA. */
- lra_simple_p
- = (ira_use_lra_p
- && max_reg_num () >= (1 << 26) / last_basic_block_for_fn (cfun));
- if (lra_simple_p)
- {
- /* It permits to skip live range splitting in LRA. */
- flag_caller_saves = false;
- /* There is no sense to do regional allocation when we use
- simplified LRA. */
- flag_ira_region = IRA_REGION_ONE;
- ira_conflicts_p = false;
- }
- #ifndef IRA_NO_OBSTACK
- gcc_obstack_init (&ira_obstack);
- #endif
- bitmap_obstack_initialize (&ira_bitmap_obstack);
- /* LRA uses its own infrastructure to handle caller save registers. */
- if (flag_caller_saves && !ira_use_lra_p)
- init_caller_save ();
- if (flag_ira_verbose < 10)
- {
- internal_flag_ira_verbose = flag_ira_verbose;
- ira_dump_file = f;
- }
- else
- {
- internal_flag_ira_verbose = flag_ira_verbose - 10;
- ira_dump_file = stderr;
- }
- setup_prohibited_mode_move_regs ();
- decrease_live_ranges_number ();
- df_note_add_problem ();
- /* DF_LIVE can't be used in the register allocator, too many other
- parts of the compiler depend on using the "classic" liveness
- interpretation of the DF_LR problem. See PR38711.
- Remove the problem, so that we don't spend time updating it in
- any of the df_analyze() calls during IRA/LRA. */
- if (optimize > 1)
- df_remove_problem (df_live);
- gcc_checking_assert (df_live == NULL);
- #ifdef ENABLE_CHECKING
- df->changeable_flags |= DF_VERIFY_SCHEDULED;
- #endif
- df_analyze ();
- init_reg_equiv ();
- if (ira_conflicts_p)
- {
- calculate_dominance_info (CDI_DOMINATORS);
- if (split_live_ranges_for_shrink_wrap ())
- df_analyze ();
- free_dominance_info (CDI_DOMINATORS);
- }
- df_clear_flags (DF_NO_INSN_RESCAN);
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
- /* If we are not optimizing, then this is the only place before
- register allocation where dataflow is done. And that is needed
- to generate these warnings. */
- if (warn_clobbered)
- generate_setjmp_warnings ();
- /* Determine if the current function is a leaf before running IRA
- since this can impact optimizations done by the prologue and
- epilogue thus changing register elimination offsets. */
- crtl->is_leaf = leaf_function_p ();
- if (resize_reg_info () && flag_ira_loop_pressure)
- ira_set_pseudo_classes (true, ira_dump_file);
- rebuild_p = update_equiv_regs ();
- setup_reg_equiv ();
- setup_reg_equiv_init ();
- if (optimize && rebuild_p)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- if (purge_all_dead_edges ())
- delete_unreachable_blocks ();
- timevar_pop (TV_JUMP);
- }
- allocated_reg_info_size = max_reg_num ();
- if (delete_trivially_dead_insns (get_insns (), max_reg_num ()))
- df_analyze ();
- /* It is not worth to do such improvement when we use a simple
- allocation because of -O0 usage or because the function is too
- big. */
- if (ira_conflicts_p)
- find_moveable_pseudos ();
- max_regno_before_ira = max_reg_num ();
- ira_setup_eliminable_regset ();
- ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
- ira_load_cost = ira_store_cost = ira_shuffle_cost = 0;
- ira_move_loops_num = ira_additional_jumps_num = 0;
- ira_assert (current_loops == NULL);
- if (flag_ira_region == IRA_REGION_ALL || flag_ira_region == IRA_REGION_MIXED)
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS | LOOPS_HAVE_RECORDED_EXITS);
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- fprintf (ira_dump_file, "Building IRA IR\n");
- loops_p = ira_build ();
- ira_assert (ira_conflicts_p || !loops_p);
- saved_flag_ira_share_spill_slots = flag_ira_share_spill_slots;
- if (too_high_register_pressure_p () || cfun->calls_setjmp)
- /* It is just wasting compiler's time to pack spilled pseudos into
- stack slots in this case -- prohibit it. We also do this if
- there is setjmp call because a variable not modified between
- setjmp and longjmp the compiler is required to preserve its
- value and sharing slots does not guarantee it. */
- flag_ira_share_spill_slots = FALSE;
- ira_color ();
- ira_max_point_before_emit = ira_max_point;
- ira_initiate_emit_data ();
- ira_emit (loops_p);
- max_regno = max_reg_num ();
- if (ira_conflicts_p)
- {
- if (! loops_p)
- {
- if (! ira_use_lra_p)
- ira_initiate_assign ();
- }
- else
- {
- expand_reg_info ();
- if (ira_use_lra_p)
- {
- ira_allocno_t a;
- ira_allocno_iterator ai;
- FOR_EACH_ALLOCNO (a, ai)
- {
- int old_regno = ALLOCNO_REGNO (a);
- int new_regno = REGNO (ALLOCNO_EMIT_DATA (a)->reg);
- ALLOCNO_REGNO (a) = new_regno;
- if (old_regno != new_regno)
- setup_reg_classes (new_regno, reg_preferred_class (old_regno),
- reg_alternate_class (old_regno),
- reg_allocno_class (old_regno));
- }
- }
- else
- {
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- fprintf (ira_dump_file, "Flattening IR\n");
- ira_flattening (max_regno_before_ira, ira_max_point_before_emit);
- }
- /* New insns were generated: add notes and recalculate live
- info. */
- df_analyze ();
- /* ??? Rebuild the loop tree, but why? Does the loop tree
- change if new insns were generated? Can that be handled
- by updating the loop tree incrementally? */
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS
- | LOOPS_HAVE_RECORDED_EXITS);
- if (! ira_use_lra_p)
- {
- setup_allocno_assignment_flags ();
- ira_initiate_assign ();
- ira_reassign_conflict_allocnos (max_regno);
- }
- }
- }
- ira_finish_emit_data ();
- setup_reg_renumber ();
- calculate_allocation_cost ();
- #ifdef ENABLE_IRA_CHECKING
- if (ira_conflicts_p)
- check_allocation ();
- #endif
- if (max_regno != max_regno_before_ira)
- {
- regstat_free_n_sets_and_refs ();
- regstat_free_ri ();
- regstat_init_n_sets_and_refs ();
- regstat_compute_ri ();
- }
- overall_cost_before = ira_overall_cost;
- if (! ira_conflicts_p)
- grow_reg_equivs ();
- else
- {
- fix_reg_equiv_init ();
- #ifdef ENABLE_IRA_CHECKING
- print_redundant_copies ();
- #endif
- if (! ira_use_lra_p)
- {
- ira_spilled_reg_stack_slots_num = 0;
- ira_spilled_reg_stack_slots
- = ((struct ira_spilled_reg_stack_slot *)
- ira_allocate (max_regno
- * sizeof (struct ira_spilled_reg_stack_slot)));
- memset (ira_spilled_reg_stack_slots, 0,
- max_regno * sizeof (struct ira_spilled_reg_stack_slot));
- }
- }
- allocate_initial_values ();
- /* See comment for find_moveable_pseudos call. */
- if (ira_conflicts_p)
- move_unallocated_pseudos ();
- /* Restore original values. */
- if (lra_simple_p)
- {
- flag_caller_saves = saved_flag_caller_saves;
- flag_ira_region = saved_flag_ira_region;
- }
- }
- static void
- do_reload (void)
- {
- basic_block bb;
- bool need_dce;
- unsigned pic_offset_table_regno = INVALID_REGNUM;
- if (flag_ira_verbose < 10)
- ira_dump_file = dump_file;
- /* If pic_offset_table_rtx is a pseudo register, then keep it so
- after reload to avoid possible wrong usages of hard reg assigned
- to it. */
- if (pic_offset_table_rtx
- && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
- pic_offset_table_regno = REGNO (pic_offset_table_rtx);
- timevar_push (TV_RELOAD);
- if (ira_use_lra_p)
- {
- if (current_loops != NULL)
- {
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- }
- FOR_ALL_BB_FN (bb, cfun)
- bb->loop_father = NULL;
- current_loops = NULL;
- ira_destroy ();
- lra (ira_dump_file);
- /* ???!!! Move it before lra () when we use ira_reg_equiv in
- LRA. */
- vec_free (reg_equivs);
- reg_equivs = NULL;
- need_dce = false;
- }
- else
- {
- df_set_flags (DF_NO_INSN_RESCAN);
- build_insn_chain ();
-
- need_dce = reload (get_insns (), ira_conflicts_p);
- }
- timevar_pop (TV_RELOAD);
- timevar_push (TV_IRA);
- if (ira_conflicts_p && ! ira_use_lra_p)
- {
- ira_free (ira_spilled_reg_stack_slots);
- ira_finish_assign ();
- }
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL
- && overall_cost_before != ira_overall_cost)
- fprintf (ira_dump_file, "+++Overall after reload %"PRId64 "\n",
- ira_overall_cost);
- flag_ira_share_spill_slots = saved_flag_ira_share_spill_slots;
- if (! ira_use_lra_p)
- {
- ira_destroy ();
- if (current_loops != NULL)
- {
- loop_optimizer_finalize ();
- free_dominance_info (CDI_DOMINATORS);
- }
- FOR_ALL_BB_FN (bb, cfun)
- bb->loop_father = NULL;
- current_loops = NULL;
-
- regstat_free_ri ();
- regstat_free_n_sets_and_refs ();
- }
- if (optimize)
- cleanup_cfg (CLEANUP_EXPENSIVE);
- finish_reg_equiv ();
- bitmap_obstack_release (&ira_bitmap_obstack);
- #ifndef IRA_NO_OBSTACK
- obstack_free (&ira_obstack, NULL);
- #endif
- /* The code after the reload has changed so much that at this point
- we might as well just rescan everything. Note that
- df_rescan_all_insns is not going to help here because it does not
- touch the artificial uses and defs. */
- df_finish_pass (true);
- df_scan_alloc (NULL);
- df_scan_blocks ();
- if (optimize > 1)
- {
- df_live_add_problem ();
- df_live_set_all_dirty ();
- }
- if (optimize)
- df_analyze ();
- if (need_dce && optimize)
- run_fast_dce ();
- /* Diagnose uses of the hard frame pointer when it is used as a global
- register. Often we can get away with letting the user appropriate
- the frame pointer, but we should let them know when code generation
- makes that impossible. */
- if (global_regs[HARD_FRAME_POINTER_REGNUM] && frame_pointer_needed)
- {
- tree decl = global_regs_decl[HARD_FRAME_POINTER_REGNUM];
- error_at (DECL_SOURCE_LOCATION (current_function_decl),
- "frame pointer required, but reserved");
- inform (DECL_SOURCE_LOCATION (decl), "for %qD", decl);
- }
- if (pic_offset_table_regno != INVALID_REGNUM)
- pic_offset_table_rtx = gen_rtx_REG (Pmode, pic_offset_table_regno);
- timevar_pop (TV_IRA);
- }
- /* Run the integrated register allocator. */
- namespace {
- const pass_data pass_data_ira =
- {
- RTL_PASS, /* type */
- "ira", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_IRA, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_do_not_ggc_collect, /* todo_flags_finish */
- };
- class pass_ira : public rtl_opt_pass
- {
- public:
- pass_ira (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_ira, ctxt)
- {}
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return !targetm.no_register_allocation;
- }
- virtual unsigned int execute (function *)
- {
- ira (dump_file);
- return 0;
- }
- }; // class pass_ira
- } // anon namespace
- rtl_opt_pass *
- make_pass_ira (gcc::context *ctxt)
- {
- return new pass_ira (ctxt);
- }
- namespace {
- const pass_data pass_data_reload =
- {
- RTL_PASS, /* type */
- "reload", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_RELOAD, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- };
- class pass_reload : public rtl_opt_pass
- {
- public:
- pass_reload (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_reload, ctxt)
- {}
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return !targetm.no_register_allocation;
- }
- virtual unsigned int execute (function *)
- {
- do_reload ();
- return 0;
- }
- }; // class pass_reload
- } // anon namespace
- rtl_opt_pass *
- make_pass_reload (gcc::context *ctxt)
- {
- return new pass_reload (ctxt);
- }
|