加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0015-Backport-Structure-reorganization-optimization.patch 160.02 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170
From 8631d4a39453bb262675bea9abb5c1b7d52af624 Mon Sep 17 00:00:00 2001
From: eastb233 <xiezhiheng@huawei.com>
Date: Wed, 19 Jul 2023 10:28:04 +0800
Subject: [PATCH 15/22] [Backport] Structure reorganization optimization
Reference: https://gcc.gnu.org/git/?p=gcc-old.git;a=commit;h=6e1bd1c900533c627b5e4fbbecb41dcd7974b522
Introduce structure reorganization optimization, that change C-like
structures layout in order to better utilize spatial locality. This
transformation is affective for programs containing arrays of structures.
---
gcc/Makefile.in | 1 +
gcc/common.opt | 4 +-
gcc/configure | 2 +-
gcc/configure.ac | 2 +-
gcc/doc/invoke.texi | 23 +
gcc/gimple-ssa-warn-access.cc | 8 +
gcc/ipa-param-manipulation.cc | 3 +-
gcc/ipa-param-manipulation.h | 3 +-
gcc/ipa-struct-reorg/escapes.def | 60 +
gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 4015 +++++++++++++++++
gcc/ipa-struct-reorg/ipa-struct-reorg.h | 235 +
gcc/params.opt | 4 +
gcc/passes.def | 2 +
gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 35 +
gcc/testsuite/gcc.dg/struct/struct_reorg-1.c | 24 +
gcc/testsuite/gcc.dg/struct/struct_reorg-2.c | 29 +
gcc/testsuite/gcc.dg/struct/struct_reorg-3.c | 23 +
gcc/testsuite/gcc.dg/struct/struct_reorg-4.c | 59 +
.../gcc.dg/struct/w_prof_global_array.c | 29 +
.../gcc.dg/struct/w_prof_global_var.c | 42 +
.../gcc.dg/struct/w_prof_local_array.c | 37 +
.../gcc.dg/struct/w_prof_local_var.c | 40 +
.../gcc.dg/struct/w_prof_single_str_global.c | 31 +
gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c | 64 +
.../gcc.dg/struct/w_ratio_cold_str.c | 43 +
.../gcc.dg/struct/wo_prof_array_field.c | 26 +
.../struct/wo_prof_array_through_pointer.c | 38 +
.../gcc.dg/struct/wo_prof_double_malloc.c | 29 +
.../gcc.dg/struct/wo_prof_empty_str.c | 44 +
.../struct/wo_prof_escape_arg_to_local.c | 44 +
.../gcc.dg/struct/wo_prof_escape_return-1.c | 33 +
.../gcc.dg/struct/wo_prof_escape_return.c | 32 +
.../gcc.dg/struct/wo_prof_escape_str_init.c | 31 +
.../struct/wo_prof_escape_substr_array.c | 33 +
.../struct/wo_prof_escape_substr_pointer.c | 48 +
.../struct/wo_prof_escape_substr_value.c | 45 +
.../gcc.dg/struct/wo_prof_global_array.c | 32 +
.../gcc.dg/struct/wo_prof_global_var.c | 45 +
.../gcc.dg/struct/wo_prof_local_array.c | 40 +
.../gcc.dg/struct/wo_prof_local_var.c | 43 +
.../gcc.dg/struct/wo_prof_malloc_size_var-1.c | 47 +
.../gcc.dg/struct/wo_prof_malloc_size_var.c | 47 +
.../struct/wo_prof_mult_field_peeling.c | 42 +
.../gcc.dg/struct/wo_prof_single_str_global.c | 34 +
.../gcc.dg/struct/wo_prof_single_str_local.c | 34 +
.../struct/wo_prof_single_str_pointer.c | 38 +
.../gcc.dg/struct/wo_prof_two_strs.c | 67 +
gcc/timevar.def | 1 +
gcc/tree-pass.h | 1 +
49 files changed, 5686 insertions(+), 6 deletions(-)
create mode 100644 gcc/ipa-struct-reorg/escapes.def
create mode 100644 gcc/ipa-struct-reorg/ipa-struct-reorg.cc
create mode 100644 gcc/ipa-struct-reorg/ipa-struct-reorg.h
create mode 100644 gcc/testsuite/gcc.dg/struct/struct-reorg.exp
create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-2.c
create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-4.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_global_array.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_global_var.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_local_array.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_local_var.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c
create mode 100644 gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c
create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 31ff95500..c863ad992 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1451,6 +1451,7 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+ ipa-struct-reorg/ipa-struct-reorg.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index e365a48bc..b48fa3228 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1950,8 +1950,8 @@ Common Ignore
Does nothing. Preserved for backward compatibility.
fipa-struct-reorg
-Common Ignore
-Does nothing. Preserved for backward compatibility.
+Common Var(flag_ipa_struct_reorg) Init(0) Optimization
+Perform structure layout optimizations.
fipa-vrp
Common Var(flag_ipa_vrp) Optimization
diff --git a/gcc/configure b/gcc/configure
index c749ace01..98bbf0f85 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -34191,7 +34191,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
"depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;;
"gccdepdir":C)
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
- for lang in $subdirs c-family common analyzer rtl-ssa
+ for lang in $subdirs c-family common analyzer rtl-ssa ipa-struct-reorg
do
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
done ;;
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 992a50e7b..c74f4b555 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1340,7 +1340,7 @@ AC_CHECK_HEADERS(ext/hash_map)
ZW_CREATE_DEPDIR
AC_CONFIG_COMMANDS([gccdepdir],[
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
- for lang in $subdirs c-family common analyzer rtl-ssa
+ for lang in $subdirs c-family common analyzer rtl-ssa ipa-struct-reorg
do
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
done], [subdirs="$subdirs" ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR])
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ff8cd032f..e37bae5b1 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -526,6 +526,7 @@ Objective-C and Objective-C++ Dialects}.
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
-finline-small-functions -fipa-modref -fipa-cp -fipa-cp-clone @gol
-fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const @gol
+-fipa-struct-reorg @gol
-fipa-reference -fipa-reference-addressable @gol
-fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} @gol
-flive-patching=@var{level} @gol
@@ -11886,6 +11887,19 @@ higher.
Discover which functions are pure or constant.
Enabled by default at @option{-O1} and higher.
+@item -fipa-struct-reorg
+@opindex fipa-struct-reorg
+Perform structure reorganization optimization, that change C-like structures
+layout in order to better utilize spatial locality. This transformation is
+affective for programs containing arrays of structures. Available in two
+compilation modes: profile-based (enabled with @option{-fprofile-generate})
+or static (which uses built-in heuristics). It works only in whole program
+mode, so it requires @option{-fwhole-program} to be
+enabled. Structures considered @samp{cold} by this transformation are not
+affected (see @option{--param struct-reorg-cold-struct-ratio=@var{value}}).
+
+With this flag, the program debug info reflects a new structure layout.
+
@item -fipa-reference
@opindex fipa-reference
Discover which static variables do not escape the
@@ -13772,6 +13786,15 @@ In each case, the @var{value} is an integer. The following choices
of @var{name} are recognized for all targets:
@table @gcctabopt
+@item struct-reorg-cold-struct-ratio
+The threshold ratio (as a percentage) between a structure frequency
+and the frequency of the hottest structure in the program. This parameter
+is used by struct-reorg optimization enabled by @option{-fipa-struct-reorg}.
+We say that if the ratio of a structure frequency, calculated by profiling,
+to the hottest structure frequency in the program is less than this
+parameter, then structure reorganization is not applied to this structure.
+The default is 10.
+
@item predictable-branch-outcome
When branch is predicted to be taken with probability lower than this threshold
(in percent), then it is considered well predictable.
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 8d088ad33..a24645783 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2193,6 +2193,14 @@ pass_waccess::set_pass_param (unsigned int n, bool early)
bool
pass_waccess::gate (function *)
{
+ /* FIXME: In structure optimizations, some statements will be
+ rewritten and removed from the BB, leaving some unused SSA.
+ In pass waccess, it will traverse all SSA and cause ICE
+ when handling these unused SSA. So temporarily disable
+ pass waccess when enable structure optimizations. */
+ if (flag_ipa_struct_reorg)
+ return false;
+
return (warn_free_nonheap_object
|| warn_mismatched_alloc
|| warn_mismatched_new_delete);
diff --git a/gcc/ipa-param-manipulation.cc b/gcc/ipa-param-manipulation.cc
index 38328c3e8..f9e956008 100644
--- a/gcc/ipa-param-manipulation.cc
+++ b/gcc/ipa-param-manipulation.cc
@@ -55,7 +55,8 @@ static const char *ipa_param_prefixes[IPA_PARAM_PREFIX_COUNT]
= {"SYNTH",
"ISRA",
"simd",
- "mask"};
+ "mask",
+ "struct_reorg"};
/* Names of parameters for dumping. Keep in sync with enum ipa_parm_op. */
diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
index a9ad2b216..71f4a0a2f 100644
--- a/gcc/ipa-param-manipulation.h
+++ b/gcc/ipa-param-manipulation.h
@@ -126,6 +126,7 @@ enum ipa_param_name_prefix_indices
IPA_PARAM_PREFIX_ISRA,
IPA_PARAM_PREFIX_SIMD,
IPA_PARAM_PREFIX_MASK,
+ IPA_PARAM_PREFIX_REORG,
IPA_PARAM_PREFIX_COUNT
};
@@ -189,7 +190,7 @@ struct GTY(()) ipa_adjusted_param
/* Index into ipa_param_prefixes specifying a prefix to be used with
DECL_NAMEs of newly synthesized parameters. */
- unsigned param_prefix_index : 2;
+ unsigned param_prefix_index : 3;
/* Storage order of the original parameter (for the cases when the new
parameter is a component of an original one). */
diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def
new file mode 100644
index 000000000..c4c8e0739
--- /dev/null
+++ b/gcc/ipa-struct-reorg/escapes.def
@@ -0,0 +1,60 @@
+/* Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+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/>. */
+
+/* Before including this file, you should define a macro:
+ DEF_ESCAPE (ENUM, TEXT)
+
+ This macro will be called once for each escape reason. The
+ ENUM will be of type "escape_type". The TEXT is describing
+ the reason for the escape.
+*/
+DEF_ESCAPE (escape_marked_as_used, "Type used in variable marked as used")
+DEF_ESCAPE (escape_via_global_var, "Type used via a external visible variable")
+DEF_ESCAPE (escape_via_global_init, "Type used via a global init of a variable")
+DEF_ESCAPE (escape_non_supported_allocator, "Type used by allocation which is not currently supported")
+DEF_ESCAPE (escape_dependent_type_escapes, "Type uses a type which escapes or is used by a type which escapes")
+DEF_ESCAPE (escape_var_arg_function, "Types escapes via a variable argument function")
+DEF_ESCAPE (escape_bitfields, "Types has bitfields")
+DEF_ESCAPE (escape_recusive_type, "Type has a recusive relationship")
+DEF_ESCAPE (escape_variable_sized_array, "Type has a variable sized type")
+DEF_ESCAPE (escape_external_function, "Type escapes via an external function call")
+DEF_ESCAPE (escape_visible_function, "Type escapes via expternally visible function call")
+DEF_ESCAPE (escape_pointer_function, "Type escapes via an function pointer call")
+DEF_ESCAPE (escape_unkown_field, "Type escapes via an unkown field accessed")
+DEF_ESCAPE (escape_union, "Type escapes via an union")
+DEF_ESCAPE (escape_inline_asm, "Type escapes via inline-asm")
+DEF_ESCAPE (escape_non_multiply_size, "Type escapes a pointer plus which is not a multiplicate of the size")
+DEF_ESCAPE (escape_cast_void, "Type escapes a cast to/from void*")
+DEF_ESCAPE (escape_cast_another_ptr, "Type escapes a cast to a different pointer")
+DEF_ESCAPE (escape_cast_int, "Type escapes a cast from/to intergral type")
+DEF_ESCAPE (escape_int_const, "Type escapes via integer constant")
+DEF_ESCAPE (escape_vce, "Type escapes via a VIEW_CONVERT_EXPR")
+DEF_ESCAPE (escape_array_access, "Type escapes via an array access")
+DEF_ESCAPE (escape_noclonable_function, "Type escapes via a non-clonable function")
+DEF_ESCAPE (escape_rescusive_type, "Recusive type")
+DEF_ESCAPE (escape_user_alignment, "Type has an user alignment set")
+DEF_ESCAPE (escape_volatile, "Type has an variable which is volatile")
+DEF_ESCAPE (escape_non_eq, "Type has a comparison other than equals or not equals")
+DEF_ESCAPE (escape_addr, "Type escapes via taking the address of field")
+DEF_ESCAPE (escape_cannot_change_signature, "Type used in a call that cannot change signature")
+DEF_ESCAPE (escape_non_optimize, "Type used by a function which turns off struct reorg")
+DEF_ESCAPE (escape_array, "Type is used in an array [not handled yet]")
+DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]")
+DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]")
+
+#undef DEF_ESCAPE
diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
new file mode 100644
index 000000000..238530860
--- /dev/null
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
@@ -0,0 +1,4015 @@
+/* Struct-reorg optimizations.
+ Copyright (C) 2016-2023 Free Software Foundation, Inc.
+ Contributed by Andrew Pinski <apinski@cavium.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/>. */
+
+/* This pass implements the structure reorganization organization
+ (struct-reorg).
+
+ Right now it handles just splitting off the hottest fields for a struct
+ of 2 fields:
+ struct s {
+ type1 field1; // Hot field
+ type2 field2;
+ };
+ s *v;
+ into:
+ struct s_hot {
+ type1 field1;
+ };
+ struct c_cold {
+ type2 field2;
+ };
+ s_hot *v_hot;
+ s_cold *v_cold;
+
+ TODO: This pass can be extended to more fields, and other alogrothims
+ like reordering.
+
+ This pass operate in four stages:
+ 1. All of the field accesses, declarations (struct types and pointers
+ to that type) and struct types are scanned and recorded. This includes
+ global declarations. Also record all allocation and freeing sites;
+ this is needed for the rewriting phase.
+
+ FIXME: If there is a top-level inline-asm, the pass immediately returns.
+
+ 2. Prune out the types which are considered escaping.
+ Examples of types which are considered escaping:
+ a. A declaration has been marked as having the attribute used or
+ has user defined alignment (type too).
+ b. Accesses are via a BIT_FIELD_REF.
+ FIXME: Handle VECTOR_TYPE for this case.
+ c. The "allocation" site is not a known builtin function.
+ d. Casting to/from an integer.
+
+ 3. Analyze the types for which optimization to do.
+ a. Split the fields into two different structs.
+ (FIXME: two field case handled only)
+ Look at all structs which contain two fields, if one of the fields
+ is hotter then split it and put it on the rewritting for accesses.
+ Allocations and freeing are marked to split into two functions;
+ all uses of that type will now be considered as two.
+ b. Reorder fields hottest to the coldest. TODO: Implement.
+
+ 4. Rewrite each access and allocation and free whichis marked as
+ rewriting.
+
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic-core.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "vec.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "gimple-iterator.h"
+#include "cfg.h"
+#include "ssa.h"
+#include "tree-dfa.h"
+#include "fold-const.h"
+#include "tree-inline.h"
+#include "stor-layout.h"
+#include "tree-into-ssa.h"
+#include "tree-cfg.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-prop.h"
+#include "ipa-struct-reorg.h"
+#include "tree-eh.h"
+#include "bitmap.h"
+#include "tree-ssa-live.h" /* For remove_unused_locals. */
+#include "ipa-param-manipulation.h"
+#include "gimplify-me.h"
+
+namespace {
+
+using namespace struct_reorg;
+
+#define VOID_POINTER_P(type) \
+ (POINTER_TYPE_P (type) && VOID_TYPE_P (TREE_TYPE (type)))
+
+/* Return true iff TYPE is stdarg va_list type. */
+
+static inline bool
+is_va_list_type (tree type)
+{
+ return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node);
+}
+
+static const char *
+get_type_name (tree type)
+{
+ const char *tname = NULL;
+
+ if (type == NULL)
+ return NULL;
+
+ if (TYPE_NAME (type) != NULL)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ tname = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else if (DECL_NAME (TYPE_NAME (type)) != NULL)
+ tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ return tname;
+}
+
+/* Return the inner most type for arrays and pointers of TYPE. */
+
+static tree
+inner_type (tree type)
+{
+ while (POINTER_TYPE_P (type)
+ || TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+ return type;
+}
+
+/* Return true if TYPE is a type which struct reorg should handled. */
+
+static bool
+handled_type (tree type)
+{
+ type = inner_type (type);
+ if (TREE_CODE (type) == RECORD_TYPE)
+ return !is_va_list_type (type);
+ return false;
+}
+
+/* The gimplify_buildN API is moved to tree-vect-generic.c locally
+ at commit b972e036f40c12b106f9070c3e8adea0eb8a45fa.
+
+ The gimplify_buildN API is copied from gcc 10 implementation.
+*/
+
+/* Build a binary operation and gimplify it. Emit code before GSI.
+ Return the gimple_val holding the result. */
+
+static tree
+gimplify_build2 (gimple_stmt_iterator *gsi, enum tree_code code,
+ tree type, tree a, tree b)
+{
+ tree ret;
+
+ ret = fold_build2_loc (gimple_location (gsi_stmt (*gsi)), code, type, a, b);
+ return force_gimple_operand_gsi (gsi, ret, true, NULL, true,
+ GSI_SAME_STMT);
+}
+
+/* Build a unary operation and gimplify it. Emit code before GSI.
+ Return the gimple_val holding the result. */
+
+static tree
+gimplify_build1 (gimple_stmt_iterator *gsi, enum tree_code code, tree type,
+ tree a)
+{
+ tree ret;
+
+ ret = fold_build1_loc (gimple_location (gsi_stmt (*gsi)), code, type, a);
+ return force_gimple_operand_gsi (gsi, ret, true, NULL, true,
+ GSI_SAME_STMT);
+}
+
+} // anon namespace
+
+
+namespace struct_reorg {
+
+/* Constructor of srfunction. */
+
+srfunction::srfunction (cgraph_node *n)
+ : node (n),
+ old (NULL),
+ newnode (NULL),
+ newf (NULL)
+{}
+
+/* Add an ARG to the list of arguments for the function. */
+
+void
+srfunction::add_arg (srdecl *arg)
+{
+ args.safe_push (arg);
+}
+
+/* Dump the SRFUNCTION to the file FILE. */
+
+void
+srfunction::dump (FILE *file)
+{
+ if (node)
+ {
+ fprintf (file, "function : ");
+ print_generic_expr (file, node->decl);
+ fprintf (file, " with arguments: ");
+ for (unsigned i = 0; i < args.length (); i++)
+ {
+ if (i == 0)
+ fprintf (file, "\n ");
+ else
+ fprintf (file, "\n, ");
+ args[i]->dump (file);
+ }
+
+ fprintf (file, "\nuses globals: ");
+ for (unsigned i = 0; i < globals.length (); i++)
+ {
+ fprintf (file, "\n ");
+ globals[i]->dump (file);
+ }
+
+ fprintf (file, "\ndecls: ");
+ }
+ else
+ fprintf (file, "globals : ");
+
+ for (unsigned i = 0; i < decls.length (); i++)
+ {
+ fprintf (file, "\n ");
+ decls[i]->dump (file);
+ }
+}
+
+/* Simple dump the SRFUNCTION to the file FILE;
+ used so it is not recusive. */
+
+void
+srfunction::simple_dump (FILE *file)
+{
+ print_generic_expr (file, node->decl);
+}
+
+/* Constructor of FIELD. */
+
+srfield::srfield (tree field, srtype *base)
+ : offset (int_byte_position (field)),
+ fieldtype (TREE_TYPE (field)),
+ fielddecl (field),
+ base (base),
+ type (NULL),
+ clusternum (0)
+{
+ for (int i = 0; i < max_split; i++)
+ newfield[i] = NULL_TREE;
+}
+
+/* Constructor of TYPE. */
+
+srtype::srtype (tree type)
+ : type (type),
+ chain_type (false),
+ escapes (does_not_escape),
+ visited (false)
+{
+ for (int i = 0; i < max_split; i++)
+ newtype[i] = NULL_TREE;
+
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ if (DECL_BIT_FIELD (field))
+ {
+ escapes = escape_bitfields;
+ continue;
+ }
+ else if (!DECL_SIZE (field)
+ || TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
+ {
+ escapes = escape_variable_sized_array;
+ break;
+ }
+ srfield *t = new srfield (field, this);
+ fields.safe_push (t);
+ }
+ }
+}
+
+/* Mark the type as escaping type E at statement STMT. */
+
+void
+srtype::mark_escape (escape_type e, gimple *stmt)
+{
+ /* Once the type has escaped, it should never
+ change back to non escaping. */
+ gcc_assert (e != does_not_escape);
+ if (has_escaped ())
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nO type: ");
+ simple_dump (dump_file);
+ fprintf (dump_file, " has already escaped.");
+ fprintf (dump_file, " old = \"%s\" ",
+ escape_type_string[escapes - 1]);
+ fprintf (dump_file, " new = \"%s\"\n", escape_type_string[e - 1]);
+ if (stmt)
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ return;
+ }
+ escapes = e;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nN type: ");
+ simple_dump (dump_file);
+ fprintf (dump_file, " new = \"%s\"\n", escape_reason ());
+ if (stmt)
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+}
+
+/* Add FIELD to the list of fields that use this type. */
+
+void
+srtype::add_field_site (srfield *field)
+{
+ field_sites.safe_push (field);
+}
+
+/* Constructor of DECL. */
+
+srdecl::srdecl (srtype *tp, tree decl, int argnum)
+ : type (tp),
+ decl (decl),
+ func (NULL_TREE),
+ argumentnum (argnum),
+ visited (false)
+{
+ if (TREE_CODE (decl) == SSA_NAME)
+ func = current_function_decl;
+ else if (!is_global_var (decl))
+ func = DECL_CONTEXT (decl);
+ for (int i = 0; i < max_split; i++)
+ newdecl[i] = NULL_TREE;
+}
+
+/* Find DECL in the function. */
+
+srdecl *
+srfunction::find_decl (tree decl)
+{
+ for (unsigned i = 0; i < decls.length (); i++)
+ if (decls[i]->decl == decl)
+ return decls[i];
+ return NULL;
+}
+
+/* Record DECL of the TYPE with argument num ARG. */
+
+srdecl *
+srfunction::record_decl (srtype *type, tree decl, int arg)
+{
+ // Search for the decl to see if it is already there.
+ srdecl *decl1 = find_decl (decl);
+
+ if (decl1)
+ return decl1;
+
+ gcc_assert (type);
+
+ decl1 = new srdecl (type, decl, arg);
+ decls.safe_push (decl1);
+ return decl1;
+}
+
+/* Find the field at OFF offset. */
+
+srfield *
+srtype::find_field (unsigned HOST_WIDE_INT off)
+{
+ unsigned int i;
+ srfield *field;
+
+ /* FIXME: handle array/struct field inside the current struct. */
+ /* NOTE This does not need to be fixed to handle libquatumn. */
+ FOR_EACH_VEC_ELT (fields, i, field)
+ {
+ if (off == field->offset)
+ return field;
+ }
+ return NULL;
+}
+
+/* Add the function FN to the list of functions if it
+ is there not already. */
+
+void
+srtype::add_function (srfunction *fn)
+{
+ unsigned decluid;
+ unsigned i;
+ decluid = DECL_UID (fn->node->decl);
+
+ srfunction *fn1;
+ // Search for the decl to see if it is already there.
+ FOR_EACH_VEC_ELT (functions, i, fn1)
+ {
+ if (DECL_UID (fn1->node->decl) == decluid)
+ return;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Recording new function: %u.\n", decluid);
+
+ functions.safe_push (fn);
+}
+
+/* Dump out the type structure to FILE. */
+
+void
+srtype::dump (FILE *f)
+{
+ unsigned int i;
+ srfield *field;
+ srfunction *fn;
+ sraccess *access;
+
+ if (chain_type)
+ fprintf (f, "chain decl ");
+
+ fprintf (f, "type : ");
+ print_generic_expr (f, type);
+ fprintf (f, "(%d) { ", TYPE_UID (type));
+ if (escapes != does_not_escape)
+ fprintf (f, " escapes = \"%s\"\n", escape_reason ());
+ fprintf (f, " fields = { ");
+ FOR_EACH_VEC_ELT (fields, i, field)
+ {
+ if (i == 0)
+ fprintf (f, "\n ");
+ else
+ fprintf (f, "\n, ");
+ field->dump (f);
+ }
+ fprintf (f, " }\n ");
+ fprintf (f, "\n accesses = {");
+ FOR_EACH_VEC_ELT (accesses, i, access)
+ {
+ fprintf (f, "\n");
+ access->dump (f);
+ }
+ fprintf (f, " }\n ");
+ fprintf (f, "\n functions = {");
+ FOR_EACH_VEC_ELT (functions, i, fn)
+ {
+ fprintf (f, " \n");
+ fn->simple_dump (f);
+ }
+ fprintf (f, "\n }\n");
+ fprintf (f, "\n field_sites = {");
+ FOR_EACH_VEC_ELT (field_sites, i, field)
+ {
+ fprintf (f, " \n");
+ field->simple_dump (f);
+ }
+ fprintf (f, "\n }\n");
+ fprintf (f, "}\n");
+}
+
+/* A simplified dump out the type structure to FILE. */
+
+void
+srtype::simple_dump (FILE *f)
+{
+ print_generic_expr (f, type);
+}
+
+/* Analyze the type and decide what to be done with it. */
+
+void
+srtype::analyze (void)
+{
+ /* Chain decl types can't be split
+ so don't try. */
+ if (chain_type)
+ return;
+
+ /* If there is only one field then there is nothing
+ to be done. */
+ if (fields.length () == 1)
+ return;
+
+ /* For now we unconditionally split only structures with 2 fields
+ into 2 different structures. In future we intend to add profile
+ info and/or static heuristics to differentiate splitting process. */
+ if (fields.length () == 2)
+ fields[1]->clusternum = 1;
+
+ /* Otherwise we do nothing. */
+ if (fields.length () >= 3)
+ return;
+}
+
+/* Create the new fields for this field. */
+
+void
+srfield::create_new_fields (tree newtype[max_split],
+ tree newfields[max_split],
+ tree newlast[max_split])
+{
+ tree nt[max_split];
+
+ for (unsigned i = 0; i < max_split; i++)
+ nt[i] = NULL;
+
+ if (type == NULL)
+ nt[0] = fieldtype;
+ else
+ memcpy (nt, type->newtype, sizeof (type->newtype));
+
+ for (unsigned i = 0; i < max_split && nt[i] != NULL; i++)
+ {
+ tree field = make_node (FIELD_DECL);
+ if (nt[1] != NULL && DECL_NAME (fielddecl))
+ {
+ const char *tname = IDENTIFIER_POINTER (DECL_NAME (fielddecl));
+ char id[10];
+ char *name;
+
+ sprintf (id, "%d", i);
+ name = concat (tname, ".reorg.", id, NULL);
+ DECL_NAME (field) = get_identifier (name);
+ free (name);
+ }
+ else
+ DECL_NAME (field) = DECL_NAME (fielddecl);
+
+ TREE_TYPE (field) = reconstruct_complex_type (
+ TREE_TYPE (fielddecl), nt[i]);
+ DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (fielddecl);
+ SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl));
+ DECL_USER_ALIGN (field) = DECL_USER_ALIGN (fielddecl);
+ TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (fielddecl);
+ DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (fielddecl);
+ TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (fielddecl);
+ DECL_CONTEXT (field) = newtype[clusternum];
+
+ if (newfields[clusternum] == NULL)
+ newfields[clusternum] = newlast[clusternum] = field;
+ else
+ {
+ DECL_CHAIN (newlast[clusternum]) = field;
+ newlast[clusternum] = field;
+ }
+ newfield[i] = field;
+ }
+}
+
+/* Create the new TYPE corresponding to THIS type. */
+
+bool
+srtype::create_new_type (void)
+{
+ /* If the type has been visited,
+ then return if a new type was
+ created or not. */
+ if (visited)
+ return has_new_type ();
+
+ visited = true;
+
+ if (escapes != does_not_escape)
+ {
+ newtype[0] = type;
+ return false;
+ }
+
+ bool createnewtype = false;
+ unsigned maxclusters = 0;
+
+ /* Create a new type for each field. */
+ for (unsigned i = 0; i < fields.length (); i++)
+ {
+ srfield *field = fields[i];
+ if (field->type)
+ createnewtype |= field->type->create_new_type ();
+ if (field->clusternum > maxclusters)
+ maxclusters = field->clusternum;
+ }
+
+ /* If the fields' types did have a change or
+ we are not splitting the struct into two clusters,
+ then just return false and don't change the type. */
+ if (!createnewtype && maxclusters == 0)
+ {
+ newtype[0] = type;
+ return false;
+ }
+
+ /* Should have at most max_split clusters. */
+ gcc_assert (maxclusters < max_split);
+
+ tree newfields[max_split];
+ tree newlast[max_split];
+
+ maxclusters++;
+
+ const char *tname = NULL;
+
+ if (TYPE_NAME (type) != NULL)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ tname = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else if (DECL_NAME (TYPE_NAME (type)) != NULL)
+ tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+
+ for (unsigned i = 0; i < maxclusters; i++)
+ {
+ newfields[i] = NULL_TREE;
+ newlast[i] = NULL_TREE;
+ newtype[i] = make_node (RECORD_TYPE);
+
+ char *name = NULL;
+ char id[10];
+ sprintf (id, "%d", i);
+ if (tname)
+ {
+ name = concat (tname, ".reorg.", id, NULL);
+ TYPE_NAME (newtype[i]) = get_identifier (name);
+ free (name);
+ }
+ }
+
+ for (unsigned i = 0; i < fields.length (); i++)
+ {
+ srfield *f = fields[i];
+ f->create_new_fields (newtype, newfields, newlast);
+ }
+
+ /* No reason to warn about these structs since the warning would
+ have happened already. */
+ int save_warn_padded = warn_padded;
+ warn_padded = 0;
+
+ for (unsigned i = 0; i < maxclusters; i++)
+ {
+ TYPE_FIELDS (newtype[i]) = newfields[i];
+ layout_type (newtype[i]);
+ }
+
+ warn_padded = save_warn_padded;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Created %d types:\n", maxclusters);
+ for (unsigned i = 0; i < maxclusters; i++)
+ {
+ print_generic_expr (dump_file, newtype[i]);
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ return true;
+}
+
+/* Helper function to copy some attributes from ORIG_DECL to the NEW_DECL. */
+
+static inline void
+copy_var_attributes (tree new_decl, tree orig_decl)
+{
+ DECL_ARTIFICIAL (new_decl) = 1;
+ DECL_EXTERNAL (new_decl) = DECL_EXTERNAL (orig_decl);
+ TREE_STATIC (new_decl) = TREE_STATIC (orig_decl);
+ TREE_PUBLIC (new_decl) = TREE_PUBLIC (orig_decl);
+ TREE_USED (new_decl) = TREE_USED (orig_decl);
+ DECL_CONTEXT (new_decl) = DECL_CONTEXT (orig_decl);
+ TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (orig_decl);
+ TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (orig_decl);
+ TREE_READONLY (new_decl) = TREE_READONLY (orig_decl);
+ if (is_global_var (orig_decl))
+ set_decl_tls_model (new_decl, DECL_TLS_MODEL (orig_decl));
+}
+
+/* Create all of the new decls (SSA_NAMES included) for THIS function. */
+
+void
+srfunction::create_new_decls (void)
+{
+ /* If this function has been cloned, we don't need to
+ create the new decls. */
+ if (newnode)
+ return;
+
+ if (node)
+ set_cfun (DECL_STRUCT_FUNCTION (node->decl));
+
+ for (unsigned i = 0; i < decls.length (); i++)
+ {
+ srdecl *decl = decls[i];
+ srtype *type = decl->type;
+ /* If the type of the decl does not change,
+ then don't create a new decl. */
+ if (!type->has_new_type ())
+ {
+ decl->newdecl[0] = decl->decl;
+ continue;
+ }
+
+ /* Handle SSA_NAMEs. */
+ if (TREE_CODE (decl->decl) == SSA_NAME)
+ {
+ tree newtype1[max_split];
+ tree inner = SSA_NAME_VAR (decl->decl);
+ tree newinner[max_split];
+ memset (newinner, 0, sizeof (newinner));
+ for (unsigned j = 0; j < max_split && type->newtype[j]; j++)
+ newtype1[j] = reconstruct_complex_type (TREE_TYPE (decls[i]->decl),
+ type->newtype[j]);
+ if (inner)
+ {
+ srdecl *in = find_decl (inner);
+ gcc_assert (in);
+ memcpy (newinner, in->newdecl, sizeof (newinner));
+ }
+ tree od = decls[i]->decl;
+ /* Create the new ssa names and copy some attributes
+ from the old one. */
+ for (unsigned j = 0; j < max_split && type->newtype[j]; j++)
+ {
+ tree nd = make_ssa_name (newinner[j] ? newinner[j]
+ : newtype1[j]);
+ decl->newdecl[j] = nd;
+ /* If the old decl was a default definition,
+ handle it specially. */
+ if (SSA_NAME_IS_DEFAULT_DEF (od))
+ {
+ SSA_NAME_IS_DEFAULT_DEF (nd) = true;
+ SSA_NAME_DEF_STMT (nd) = gimple_build_nop ();
+
+ /* Set the default definition for the ssaname if needed. */
+ if (inner)
+ {
+ gcc_assert (newinner[j]);
+ set_ssa_default_def (cfun, newinner[j], nd);
+ }
+ }
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (nd)
+ = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (od);
+ statistics_counter_event (cfun, "Create new ssa_name", 1);
+ }
+ }
+ else if (TREE_CODE (decls[i]->decl) == VAR_DECL)
+ {
+ tree orig_var = decl->decl;
+ const char *tname = NULL;
+ if (DECL_NAME (orig_var))
+ tname = IDENTIFIER_POINTER (DECL_NAME (orig_var));
+ for (unsigned j = 0; j < max_split && type->newtype[j]; j++)
+ {
+ tree new_name = NULL;
+ char *name = NULL;
+ char id[10];
+ sprintf (id, "%d", j);
+ if (tname)
+ {
+ name = concat (tname, ".reorg.", id, NULL);
+ new_name = get_identifier (name);
+ free (name);
+ }
+ tree newtype1 = reconstruct_complex_type (TREE_TYPE (orig_var),
+ type->newtype[j]);
+ decl->newdecl[j] = build_decl (DECL_SOURCE_LOCATION (orig_var),
+ VAR_DECL, new_name, newtype1);
+ copy_var_attributes (decl->newdecl[j], orig_var);
+ if (!is_global_var (orig_var))
+ add_local_decl (cfun, decl->newdecl[j]);
+ else
+ varpool_node::add (decl->newdecl[j]);
+ statistics_counter_event (cfun, "Create new var decl", 1);
+ }
+ }
+ /* Paramater decls are already handled in create_new_functions. */
+ else if (TREE_CODE (decls[i]->decl) == PARM_DECL)
+ ;
+ else
+ internal_error ("Unhandled declaration type stored");
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Created New decls for decl:\n");
+ fprintf (dump_file, "\n");
+ decls[i]->dump (dump_file);
+ fprintf (dump_file, "\n");
+ for (unsigned j = 0; j < max_split && decls[i]->newdecl[j]; j++)
+ {
+ print_generic_expr (dump_file, decls[i]->newdecl[j]);
+ fprintf (dump_file, "\n");
+ }
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ set_cfun (NULL);
+}
+
+/* Dump out the field structure to FILE. */
+
+void
+srfield::dump (FILE *f)
+{
+ fprintf (f, "field (%d) { ", DECL_UID (fielddecl));
+ fprintf (f, "base = ");
+ base->simple_dump (f);
+ fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset);
+ fprintf (f, ", type = ");
+ print_generic_expr (f, fieldtype);
+ if (type)
+ {
+ fprintf (f, "( srtype = ");
+ type->simple_dump (f);
+ fprintf (f, ")");
+ }
+ fprintf (f, "\n}\n");
+}
+
+/* A simplified dump out the field structure to FILE. */
+
+void
+srfield::simple_dump (FILE *f)
+{
+ fprintf (f, "field (%d)", DECL_UID (fielddecl));
+}
+
+/* Dump out the access structure to FILE. */
+
+void
+sraccess::dump (FILE *f)
+{
+ fprintf (f, "access { ");
+ fprintf (f, "type = '(");
+ type->simple_dump (f);
+ fprintf (f, ")'");
+ if (field)
+ {
+ fprintf (f, ", field = '(");
+ field->simple_dump (f);
+ fprintf (f, ")'");
+ }
+ else
+ fprintf (f, ", whole type");
+ fprintf (f, " in function: %s/%d", node->name (), node->order);
+ fprintf (f, ", stmt:\n");
+ print_gimple_stmt (f, stmt, 0);
+ fprintf (f, "\n }\n");
+}
+
+/* Dump out the decl structure to FILE. */
+
+void
+srdecl::dump (FILE *file)
+{
+ if (!func)
+ fprintf (file, "global ");
+ if (argumentnum != -1)
+ fprintf (file, "argument(%d) ", argumentnum);
+ fprintf (file, "decl: ");
+ print_generic_expr (file, decl);
+ fprintf (file, " type: ");
+ type->simple_dump (file);
+}
+
+} // namespace struct_reorg
+
+
+namespace {
+
+struct ipa_struct_reorg
+{
+public:
+ // Constructors
+ ipa_struct_reorg (void)
+ : current_function (NULL),
+ done_recording (false)
+ {}
+
+ // Public methods
+ unsigned execute (void);
+ void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL);
+private:
+ // Fields
+ auto_vec_del<srtype> types;
+ auto_vec_del<srfunction> functions;
+ srglobal globals;
+ srfunction *current_function;
+
+ bool done_recording;
+
+ // Private methods
+ void dump_types (FILE *f);
+ void dump_types_escaped (FILE *f);
+ void dump_functions (FILE *f);
+ void record_accesses (void);
+ void detect_cycles (void);
+ bool walk_field_for_cycles (srtype *);
+ void prune_escaped_types (void);
+ void propagate_escape (void);
+ void analyze_types (void);
+ void clear_visited (void);
+ bool create_new_types (void);
+ void restore_field_type (void);
+ void create_new_decls (void);
+ srdecl *find_decl (tree);
+ void create_new_functions (void);
+ void create_new_args (cgraph_node *new_node);
+ unsigned rewrite_functions (void);
+ srdecl *record_var (tree decl,
+ escape_type escapes = does_not_escape,
+ int arg = -1);
+ srfunction *record_function (cgraph_node *node);
+ srfunction *find_function (cgraph_node *node);
+ srtype *record_type (tree type);
+ void process_union (tree type);
+ srtype *find_type (tree type);
+ void maybe_record_stmt (cgraph_node *, gimple *);
+ void maybe_record_assign (cgraph_node *, gassign *);
+ void maybe_record_call (cgraph_node *, gcall *);
+ void maybe_record_allocation_site (cgraph_node *, gimple *);
+ void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt);
+ void mark_expr_escape (tree, escape_type, gimple *stmt);
+ tree allocate_size (srtype *t, gimple *stmt);
+
+ void mark_decls_in_as_not_needed (tree fn);
+
+ bool rewrite_stmt (gimple *, gimple_stmt_iterator *);
+ bool rewrite_assign (gassign *, gimple_stmt_iterator *);
+ bool rewrite_call (gcall *, gimple_stmt_iterator *);
+ bool rewrite_cond (gcond *, gimple_stmt_iterator *);
+ bool rewrite_debug (gimple *, gimple_stmt_iterator *);
+ bool rewrite_phi (gphi *);
+ bool rewrite_expr (tree expr,
+ tree newexpr[max_split],
+ bool ignore_missing_decl = false);
+ bool rewrite_lhs_rhs (tree lhs, tree rhs, tree newlhs[max_split],
+ tree newrhs[max_split]);
+ bool get_type_field (tree expr, tree &base, bool &indirect,
+ srtype *&type, srfield *&field,
+ bool &realpart, bool &imagpart,
+ bool &address, bool should_create = false,
+ bool can_escape = false);
+ bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t);
+
+ void check_definition (srdecl *decl, vec<srdecl *> &);
+ void check_uses (srdecl *decl, vec<srdecl *> &);
+ void check_use (srdecl *decl, gimple *stmt, vec<srdecl *> &);
+ void check_type_and_push (tree newdecl, srtype *type,
+ vec<srdecl *> &worklist, gimple *stmt);
+ void check_other_side (srdecl *decl, tree other, gimple *stmt,
+ vec<srdecl *> &worklist);
+
+ void find_vars (gimple *stmt);
+ void find_var (tree expr, gimple *stmt);
+ void mark_types_asm (gasm *astmt);
+
+ bool has_rewritten_type (srfunction *);
+ void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt);
+};
+
+/* Dump all of the recorded types to file F. */
+
+void
+ipa_struct_reorg::dump_types (FILE *f)
+{
+ unsigned i;
+ srtype *type;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ type->dump (f);
+ }
+ fprintf (f, "\n");
+}
+
+/* Dump all of the recorded types to file F. */
+
+void
+ipa_struct_reorg::dump_types_escaped (FILE *f)
+{
+ unsigned i;
+ srtype *type;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ if (type->has_escaped ())
+ {
+ type->simple_dump (f);
+ fprintf (f, " has escaped: \"%s\"\n", type->escape_reason ());
+ }
+ }
+ fprintf (f, "\n");
+}
+
+/* Dump all of the record functions to file F. */
+
+void
+ipa_struct_reorg::dump_functions (FILE *f)
+{
+ unsigned i;
+ srfunction *fn;
+
+ fprintf (f, "\n\n");
+ globals.dump (f);
+ fprintf (f, "\n\n");
+ FOR_EACH_VEC_ELT (functions, i, fn)
+ {
+ fn->dump (f);
+ fprintf (f, "\n");
+ }
+ fprintf (f, "\n\n");
+}
+
+/* Find the recorded srtype corresponding to TYPE. */
+
+srtype *
+ipa_struct_reorg::find_type (tree type)
+{
+ unsigned i;
+ /* Get the main variant as we are going
+ to find that type only. */
+ type = TYPE_MAIN_VARIANT (type);
+
+ srtype *type1;
+ // Search for the type to see if it is already there.
+ FOR_EACH_VEC_ELT (types, i, type1)
+ {
+ if (types_compatible_p (type1->type, type))
+ return type1;
+ }
+ return NULL;
+}
+
+/* Is TYPE a volatile type or one which points
+ to a volatile type. */
+
+static bool
+isvolatile_type (tree type)
+{
+ if (TYPE_VOLATILE (type))
+ return true;
+ while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+ {
+ type = TREE_TYPE (type);
+ if (TYPE_VOLATILE (type))
+ return true;
+ }
+ return false;
+}
+
+/* Is TYPE an array type or points to an array type. */
+
+static bool
+isarraytype (tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return true;
+ while (POINTER_TYPE_P (type))
+ {
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return true;
+ }
+ return false;
+}
+
+/* Is TYPE a pointer to another pointer. */
+
+static bool
+isptrptr (tree type)
+{
+ bool firstptr = false;
+ while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (POINTER_TYPE_P (type))
+ {
+ if (firstptr)
+ return true;
+ firstptr = true;
+ }
+ type = TREE_TYPE (type);
+ }
+ return false;
+}
+
+/* Return the escape type which corresponds to if
+ this is an volatile type, an array type or a pointer
+ to a pointer type. */
+
+static escape_type
+escape_type_volatile_array_or_ptrptr (tree type)
+{
+ if (isvolatile_type (type))
+ return escape_volatile;
+ if (isarraytype (type))
+ return escape_array;
+ if (isptrptr (type))
+ return escape_ptr_ptr;
+ return does_not_escape;
+}
+
+/* Record TYPE if not already recorded. */
+
+srtype *
+ipa_struct_reorg::record_type (tree type)
+{
+ unsigned typeuid;
+
+ /* Get the main variant as we are going
+ to record that type only. */
+ type = TYPE_MAIN_VARIANT (type);
+ typeuid = TYPE_UID (type);
+
+ srtype *type1;
+
+ type1 = find_type (type);
+ if (type1)
+ return type1;
+
+ /* If already done recording just return NULL. */
+ if (done_recording)
+ return NULL;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Recording new type: %u.\n", typeuid);
+
+ type1 = new srtype (type);
+ types.safe_push (type1);
+
+ /* If the type has an user alignment set,
+ that means the user most likely already setup the type. */
+ if (TYPE_USER_ALIGN (type))
+ type1->mark_escape (escape_user_alignment, NULL);
+
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ tree t = TREE_TYPE (field);
+ process_union (t);
+ if (TREE_CODE (inner_type (t)) == UNION_TYPE
+ || TREE_CODE (inner_type (t)) == QUAL_UNION_TYPE)
+ type1->mark_escape (escape_union, NULL);
+ if (isvolatile_type (t))
+ type1->mark_escape (escape_volatile, NULL);
+ escape_type e = escape_type_volatile_array_or_ptrptr (t);
+ if (e != does_not_escape)
+ type1->mark_escape (e, NULL);
+ if (handled_type (t))
+ {
+ srtype *t1 = record_type (inner_type (t));
+ srfield *f = type1->find_field (int_byte_position (field));
+ /* We might have an variable sized type which
+ we don't set the handle. */
+ if (f)
+ {
+ f->type = t1;
+ t1->add_field_site (f);
+ }
+ if (t1 == type1)
+ type1->mark_escape (escape_rescusive_type, NULL);
+ }
+ }
+ }
+
+ return type1;
+}
+
+/* Mark TYPE as escaping with ESCAPES as the reason. */
+
+void
+ipa_struct_reorg::mark_type_as_escape (tree type,
+ escape_type escapes,
+ gimple *stmt)
+{
+ if (handled_type (type))
+ {
+ srtype *stype = record_type (inner_type (type));
+
+ if (!stype)
+ return;
+
+ stype->mark_escape (escapes, stmt);
+ }
+}
+
+/* Maybe process the union of type TYPE, such that marking all of the fields'
+ types as being escaping. */
+
+void
+ipa_struct_reorg::process_union (tree type)
+{
+ static hash_set<tree> unions_recorded;
+
+ type = inner_type (type);
+ if (TREE_CODE (type) != UNION_TYPE
+ && TREE_CODE (type) != QUAL_UNION_TYPE)
+ return;
+
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* We already processed this type. */
+ if (unions_recorded.add (type))
+ return;
+
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ mark_type_as_escape (TREE_TYPE (field), escape_union);
+ process_union (TREE_TYPE (field));
+ }
+ }
+}
+
+/* Used by record_var function as a callback to walk_tree.
+ Mark the type as escaping if it has expressions which
+ cannot be converted for global initializations. */
+
+static tree
+record_init_types (tree *tp, int *walk_subtrees, void *data)
+{
+ ipa_struct_reorg *c = (ipa_struct_reorg *)data;
+ switch (TREE_CODE (*tp))
+ {
+ CASE_CONVERT:
+ case COMPONENT_REF:
+ case VIEW_CONVERT_EXPR:
+ case ARRAY_REF:
+ {
+ tree typeouter = TREE_TYPE (*tp);
+ tree typeinner = TREE_TYPE (TREE_OPERAND (*tp, 0));
+ c->mark_type_as_escape (typeouter, escape_via_global_init);
+ c->mark_type_as_escape (typeinner, escape_via_global_init);
+ break;
+ }
+ case INTEGER_CST:
+ if (!integer_zerop (*tp))
+ c->mark_type_as_escape (TREE_TYPE (*tp), escape_via_global_init);
+ break;
+ case VAR_DECL:
+ case PARM_DECL:
+ case FIELD_DECL:
+ c->mark_type_as_escape (TREE_TYPE (*tp), escape_via_global_init);
+ *walk_subtrees = false;
+ break;
+ default:
+ *walk_subtrees = true;
+ break;
+ }
+ return NULL_TREE;
+}
+
+/* Record var DECL; optionally specify the escape reason and the argument
+ number in a function. */
+
+srdecl *
+ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
+{
+ srtype *type;
+ srdecl *sd = NULL;
+
+ process_union (TREE_TYPE (decl));
+
+ if (handled_type (TREE_TYPE (decl)))
+ {
+ type = record_type (inner_type (TREE_TYPE (decl)));
+ escape_type e;
+
+ if (done_recording && !type)
+ return NULL;
+
+ gcc_assert (type);
+ if (TREE_CODE (decl) == VAR_DECL && is_global_var (decl))
+ sd = globals.record_decl (type, decl, arg);
+ else
+ {
+ gcc_assert (current_function);
+ sd = current_function->record_decl (type, decl, arg);
+ }
+
+ /* If the variable has the "used" attribute,
+ then treat the type as escaping. */
+ if (escapes != does_not_escape)
+ e = escapes;
+ else if (TREE_CODE (decl) != SSA_NAME && DECL_PRESERVE_P (decl))
+ e = escape_marked_as_used;
+ else if (TREE_THIS_VOLATILE (decl))
+ e = escape_volatile;
+ else if (TREE_CODE (decl) != SSA_NAME && DECL_USER_ALIGN (decl))
+ e = escape_user_alignment;
+ else if (TREE_CODE (decl) != SSA_NAME && TREE_STATIC (decl)
+ && TREE_PUBLIC (decl))
+ e = escape_via_global_var;
+ /* We don't have an initlizer. */
+ else if (TREE_CODE (decl) != SSA_NAME
+ && DECL_INITIAL (decl) == error_mark_node)
+ e = escape_via_global_var;
+ else
+ e = escape_type_volatile_array_or_ptrptr (TREE_TYPE (decl));
+
+ if (e != does_not_escape)
+ type->mark_escape (e, NULL);
+ }
+
+ /* Record the initial usage of variables as types escapes. */
+ if (TREE_CODE (decl) != SSA_NAME && TREE_STATIC (decl)
+ && DECL_INITIAL (decl))
+ {
+ walk_tree_without_duplicates (&DECL_INITIAL (decl),
+ record_init_types, this);
+ if (!integer_zerop (DECL_INITIAL (decl))
+ && DECL_INITIAL (decl) != error_mark_node)
+ mark_type_as_escape (TREE_TYPE (decl), escape_via_global_init);
+ }
+ return sd;
+}
+
+/* Find void* ssa_names which are used inside MEM[] or if we have &a.c,
+ mark the type as escaping. */
+
+void
+ipa_struct_reorg::find_var (tree expr, gimple *stmt)
+{
+ /* If we have VCE<a> mark the outer type as escaping and the inner one
+ Also mark the inner most operand. */
+ if (TREE_CODE (expr) == VIEW_CONVERT_EXPR)
+ {
+ mark_type_as_escape (TREE_TYPE (expr), escape_vce, stmt);
+ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (expr, 0)),
+ escape_vce, stmt);
+ }
+
+ /* If we have &b.c then we need to mark the type of b
+ as escaping as tracking a will be hard. */
+ if (TREE_CODE (expr) == ADDR_EXPR
+ || TREE_CODE (expr) == VIEW_CONVERT_EXPR)
+ {
+ tree r = TREE_OPERAND (expr, 0);
+ if (handled_component_p (r)
+ || TREE_CODE (r) == MEM_REF)
+ {
+ while (handled_component_p (r)
+ || TREE_CODE (r) == MEM_REF)
+ {
+ if (TREE_CODE (r) == VIEW_CONVERT_EXPR)
+ {
+ mark_type_as_escape (TREE_TYPE (r), escape_vce, stmt);
+ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 0)),
+ escape_vce, stmt);
+ }
+ if (TREE_CODE (r) == MEM_REF)
+ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)),
+ escape_addr, stmt);
+ r = TREE_OPERAND (r, 0);
+ }
+ mark_expr_escape (r, escape_addr, stmt);
+ }
+ }
+
+ tree base;
+ bool indirect;
+ srtype *type;
+ srfield *field;
+ bool realpart, imagpart, address;
+ get_type_field (expr, base, indirect, type, field,
+ realpart, imagpart, address, true, true);
+}
+
+void
+ipa_struct_reorg::find_vars (gimple *stmt)
+{
+ gasm *astmt;
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_ASSIGN:
+ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS
+ || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ find_var (gimple_assign_lhs (stmt), stmt);
+ find_var (gimple_assign_rhs1 (stmt), stmt);
+ if (TREE_CODE (lhs) == SSA_NAME
+ && VOID_POINTER_P (TREE_TYPE (lhs))
+ && handled_type (TREE_TYPE (rhs)))
+ {
+ srtype *t = find_type (inner_type (TREE_TYPE (rhs)));
+ srdecl *d = find_decl (lhs);
+ if (!d && t)
+ current_function->record_decl (t, lhs, -1);
+ }
+ if (TREE_CODE (rhs) == SSA_NAME
+ && VOID_POINTER_P (TREE_TYPE (rhs))
+ && handled_type (TREE_TYPE (lhs)))
+ {
+ srtype *t = find_type (inner_type (TREE_TYPE (lhs)));
+ srdecl *d = find_decl (rhs);
+ if (!d && t)
+ current_function->record_decl (t, rhs, -1);
+ }
+ }
+ break;
+
+ case GIMPLE_CALL:
+ if (gimple_call_lhs (stmt))
+ find_var (gimple_call_lhs (stmt), stmt);
+
+ if (gimple_call_chain (stmt))
+ find_var (gimple_call_chain (stmt), stmt);
+
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
+ find_var (gimple_call_arg (stmt, i), stmt);
+ break;
+
+ case GIMPLE_ASM:
+ astmt = as_a <gasm *> (stmt);
+ for (unsigned i = 0; i < gimple_asm_ninputs (astmt); i++)
+ find_var (TREE_VALUE (gimple_asm_input_op (astmt, i)), stmt);
+ for (unsigned i = 0; i < gimple_asm_noutputs (astmt); i++)
+ find_var (TREE_VALUE (gimple_asm_output_op (astmt, i)), stmt);
+ mark_types_asm (astmt);
+ break;
+
+ case GIMPLE_RETURN:
+ {
+ tree expr = gimple_return_retval (as_a <greturn *> (stmt));
+ if (expr)
+ find_var (expr, stmt);
+ /* return &a; should mark the type of a as escaping
+ through a return. */
+ if (expr && TREE_CODE (expr) == ADDR_EXPR)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ srdecl *d = find_decl (expr);
+ if (d)
+ d->type->mark_escape (escape_return, stmt);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Maybe record access of statement for further analaysis. */
+
+void
+ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt)
+{
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_ASSIGN:
+ maybe_record_assign (node, as_a <gassign *> (stmt));
+ break;
+ case GIMPLE_CALL:
+ maybe_record_call (node, as_a <gcall *> (stmt));
+ break;
+ case GIMPLE_DEBUG:
+ break;
+ case GIMPLE_GOTO:
+ case GIMPLE_SWITCH:
+ break;
+ default:
+ break;
+ }
+}
+
+/* This function checks whether ARG is a result of multiplication
+ of some number by STRUCT_SIZE. If yes, the function returns true
+ and this number is filled into NUM. */
+
+static bool
+is_result_of_mult (tree arg, tree *num, tree struct_size)
+{
+ if (!struct_size
+ || TREE_CODE (struct_size) != INTEGER_CST
+ || integer_zerop (struct_size))
+ return false;
+
+ /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */
+ if (TREE_CODE (arg) == INTEGER_CST)
+ {
+ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg, struct_size)))
+ {
+ *num = size_binop (FLOOR_DIV_EXPR, arg, struct_size);
+ return true;
+ }
+ return false;
+ }
+ gimple *size_def_stmt = SSA_NAME_DEF_STMT (arg);
+
+ /* If the allocation statement was of the form
+ D.2229_10 = <alloc_func> (D.2228_9);
+ then size_def_stmt can be D.2228_9 = num.3_8 * 8; */
+
+ while (size_def_stmt && is_gimple_assign (size_def_stmt))
+ {
+ tree lhs = gimple_assign_lhs (size_def_stmt);
+
+ /* We expect temporary here. */
+ if (!is_gimple_reg (lhs))
+ return false;
+
+ // FIXME: this should handle SHIFT also.
+ if (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR)
+ {
+ tree num1, num2;
+ tree arg0 = gimple_assign_rhs1 (size_def_stmt);
+ tree arg1 = gimple_assign_rhs2 (size_def_stmt);
+ if (!is_result_of_mult (arg0, &num1, struct_size))
+ return false;
+ if (!is_result_of_mult (arg1, &num2, struct_size))
+ return false;
+ *num = size_binop (PLUS_EXPR, num1, num2);
+ return true;
+ }
+ else if (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR)
+ {
+ tree arg0 = gimple_assign_rhs1 (size_def_stmt);
+ tree arg1 = gimple_assign_rhs2 (size_def_stmt);
+ tree num1;
+
+ if (is_result_of_mult (arg0, &num1, struct_size))
+ {
+ *num = size_binop (MULT_EXPR, arg1, num1);
+ return true;
+ }
+ if (is_result_of_mult (arg1, &num1, struct_size))
+ {
+ *num = size_binop (MULT_EXPR, arg0, num1);
+ return true;
+ }
+
+ *num = NULL_TREE;
+ return false;
+ }
+ else if (gimple_assign_rhs_code (size_def_stmt) == SSA_NAME)
+ {
+ arg = gimple_assign_rhs1 (size_def_stmt);
+ size_def_stmt = SSA_NAME_DEF_STMT (arg);
+ }
+ else
+ {
+ *num = NULL_TREE;
+ return false;
+ }
+ }
+
+ *num = NULL_TREE;
+ return false;
+}
+
+/* Return TRUE if STMT is an allocation statement that is handled. */
+
+static bool
+handled_allocation_stmt (gimple *stmt)
+{
+ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
+ return true;
+ return false;
+}
+
+/* Returns the allocated size / T size for STMT. That is the number of
+ elements in the array allocated. */
+
+tree
+ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
+{
+ if (!stmt
+ || gimple_code (stmt) != GIMPLE_CALL
+ || !handled_allocation_stmt (stmt))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nNot a allocate statment:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ return NULL;
+ }
+
+ if (type->has_escaped ())
+ return NULL;
+
+ tree struct_size = TYPE_SIZE_UNIT (type->type);
+
+ tree size = gimple_call_arg (stmt, 0);
+
+ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC))
+ size = gimple_call_arg (stmt, 1);
+ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
+ {
+ tree arg1;
+ arg1 = gimple_call_arg (stmt, 1);
+ /* Check that second argument is a constant equal to
+ the size of structure. */
+ if (operand_equal_p (arg1, struct_size, 0))
+ return size;
+ /* Check that first argument is a constant equal to
+ the size of structure. */
+ if (operand_equal_p (size, struct_size, 0))
+ return arg1;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ncalloc the correct size:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ return NULL;
+ }
+
+ tree num;
+ if (!is_result_of_mult (size, &num, struct_size))
+ return NULL;
+
+ return num;
+}
+
+void
+ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
+ gimple *stmt)
+{
+ gcc_assert (TREE_CODE (side) == SSA_NAME || TREE_CODE (side) == ADDR_EXPR);
+ srtype *type = NULL;
+ if (handled_type (TREE_TYPE (other)))
+ type = record_type (inner_type (TREE_TYPE (other)));
+ if (TREE_CODE (side) == ADDR_EXPR)
+ side = TREE_OPERAND (side, 0);
+ srdecl *d = find_decl (side);
+ if (!type)
+ {
+ if (!d)
+ return;
+ if (TREE_CODE (side) == SSA_NAME
+ && VOID_POINTER_P (TREE_TYPE (side)))
+ return;
+ d->type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+
+ if (!d)
+ {
+ if (VOID_POINTER_P (TREE_TYPE (side))
+ && TREE_CODE (side) == SSA_NAME)
+ current_function->record_decl (type, side, -1);
+ else
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ }
+ else if (type != d->type)
+ {
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ d->type->mark_escape (escape_cast_another_ptr, stmt);
+ }
+}
+
+/* Record accesses in an assignment statement STMT. */
+
+void
+ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt)
+{
+ if (gimple_clobber_p (stmt))
+ {
+ record_stmt_expr (gimple_assign_lhs (stmt), node, stmt);
+ return;
+ }
+
+ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree num;
+ if (!handled_type (TREE_TYPE (lhs)))
+ return;
+ /* Check if rhs2 is a multiplication of the size of the type. */
+ if (is_result_of_mult (rhs2, &num,
+ TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)))))
+ {
+ record_stmt_expr (lhs, node, stmt);
+ record_stmt_expr (rhs1, node, stmt);
+ }
+ else
+ {
+ mark_expr_escape (lhs, escape_non_multiply_size, stmt);
+ mark_expr_escape (rhs1, escape_non_multiply_size, stmt);
+ }
+ return;
+ }
+ /* Copies, References, Taking addresses. */
+ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ /* If we have a = &b.c then we need to mark the type of b
+ as escaping as tracking a will be hard. */
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ {
+ tree r = TREE_OPERAND (rhs, 0);
+ if (handled_component_p (r))
+ {
+ while (handled_component_p (r))
+ r = TREE_OPERAND (r, 0);
+ mark_expr_escape (r, escape_addr, stmt);
+ return;
+ }
+ }
+ if ((TREE_CODE (rhs) == SSA_NAME || TREE_CODE (rhs) == ADDR_EXPR))
+ maybe_mark_or_record_other_side (rhs, lhs, stmt);
+ if (TREE_CODE (lhs) == SSA_NAME)
+ maybe_mark_or_record_other_side (lhs, rhs, stmt);
+ }
+}
+
+static tree
+get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
+ bool &realpart, bool &imagpart,
+ tree &accesstype)
+{
+ offset = 0;
+ realpart = false;
+ imagpart = false;
+ accesstype = NULL_TREE;
+ if (TREE_CODE (e) == REALPART_EXPR)
+ {
+ e = TREE_OPERAND (e, 0);
+ realpart = true;
+ }
+ if (TREE_CODE (e) == IMAGPART_EXPR)
+ {
+ e = TREE_OPERAND (e, 0);
+ imagpart = true;
+ }
+ tree expr = e;
+ while (true)
+ {
+ switch (TREE_CODE (expr))
+ {
+ case COMPONENT_REF:
+ {
+ tree field = TREE_OPERAND (expr, 1);
+ tree field_off = byte_position (field);
+ if (TREE_CODE (field_off) != INTEGER_CST)
+ return NULL;
+ offset += tree_to_shwi (field_off);
+ expr = TREE_OPERAND (expr, 0);
+ accesstype = NULL;
+ break;
+ }
+ case MEM_REF:
+ {
+ tree field_off = TREE_OPERAND (expr, 1);
+ gcc_assert (TREE_CODE (field_off) == INTEGER_CST);
+ /* So we can mark the types as escaping if different. */
+ accesstype = TREE_TYPE (field_off);
+ offset += tree_to_uhwi (field_off);
+ return TREE_OPERAND (expr, 0);
+ }
+ default:
+ return expr;
+ }
+ }
+}
+
+/* Return true if EXPR was accessing the whole type T. */
+
+bool
+ipa_struct_reorg::wholeaccess (tree expr, tree base,
+ tree accesstype, srtype *t)
+{
+ if (expr == base)
+ return true;
+
+ if (TREE_CODE (expr) == ADDR_EXPR && TREE_OPERAND (expr, 0) == base)
+ return true;
+
+ if (!accesstype)
+ return false;
+
+ if (!types_compatible_p (TREE_TYPE (expr), TREE_TYPE (accesstype)))
+ return false;
+
+ if (!handled_type (TREE_TYPE (expr)))
+ return false;
+
+ srtype *other_type = find_type (inner_type (TREE_TYPE (expr)));
+
+ if (t == other_type)
+ return true;
+
+ return false;
+}
+
+bool
+ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
+ srtype *&type, srfield *&field,
+ bool &realpart, bool &imagpart,
+ bool &address, bool should_create,
+ bool can_escape)
+{
+ HOST_WIDE_INT offset;
+ tree accesstype;
+ address = false;
+ bool mark_as_bit_field = false;
+
+ if (TREE_CODE (expr) == BIT_FIELD_REF)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ mark_as_bit_field = true;
+ }
+
+ base = get_ref_base_and_offset (expr, offset, realpart, imagpart,
+ accesstype);
+
+ /* Variable access, unkown type. */
+ if (base == NULL)
+ return false;
+
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ address = true;
+ base = TREE_OPERAND (base, 0);
+ }
+
+ if (offset != 0 && accesstype)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Non zero offset (%d) with MEM.\n", (int)offset);
+ print_generic_expr (dump_file, expr);
+ fprintf (dump_file, "\n");
+ print_generic_expr (dump_file, base);
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ srdecl *d = find_decl (base);
+ srtype *t;
+
+ if (integer_zerop (base))
+ {
+ gcc_assert (!d);
+ if (!accesstype)
+ return false;
+ t = find_type (inner_type (inner_type (accesstype)));
+ if (!t && should_create && handled_type (accesstype))
+ t = record_type (inner_type (accesstype));
+ if (!t)
+ return false;
+ }
+ else if (!d && accesstype)
+ {
+ if (!should_create)
+ return false;
+ if (!handled_type (accesstype))
+ return false;
+ t = find_type (inner_type (inner_type (accesstype)));
+ if (!t)
+ t = record_type (inner_type (accesstype));
+ if (!t || t->has_escaped ())
+ return false;
+ /* If base is not void* mark the type as escaping. */
+ if (!VOID_POINTER_P (TREE_TYPE (base)))
+ {
+ gcc_assert (can_escape);
+ t->mark_escape (escape_cast_another_ptr, NULL);
+ return false;
+ }
+ if (TREE_CODE (base) == SSA_NAME)
+ current_function->record_decl (t, base, -1);
+ }
+ else if (!d)
+ return false;
+ else
+ t = d->type;
+
+ if (t->has_escaped ())
+ return false;
+
+ if (mark_as_bit_field)
+ {
+ gcc_assert (can_escape);
+ t->mark_escape (escape_bitfields, NULL);
+ return false;
+ }
+
+ if (wholeaccess (expr, base, accesstype, t))
+ {
+ field = NULL;
+ type = t;
+ indirect = accesstype != NULL;
+ return true;
+ }
+
+ srfield *f = t->find_field (offset);
+ if (!f)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nunkown field\n");
+ print_generic_expr (dump_file, expr);
+ fprintf (dump_file, "\n");
+ print_generic_expr (dump_file, base);
+ fprintf (dump_file, "\n");
+ }
+ gcc_assert (can_escape);
+ t->mark_escape (escape_unkown_field, NULL);
+ return false;
+ }
+ if (!types_compatible_p (f->fieldtype, TREE_TYPE (expr)))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nfieldtype = ");
+ print_generic_expr (dump_file, f->fieldtype);
+ fprintf (dump_file, "\naccess type = ");
+ print_generic_expr (dump_file, TREE_TYPE (expr));
+ fprintf (dump_file, "original expr = ");
+ print_generic_expr (dump_file, expr);
+ fprintf (dump_file, "\n");
+ }
+ gcc_assert (can_escape);
+ t->mark_escape (escape_unkown_field, NULL);
+ return false;
+ }
+ field = f;
+ type = t;
+ indirect = accesstype != NULL;
+ return true;
+}
+
+/* Mark the type used in EXPR as escaping. */
+
+void
+ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes,
+ gimple *stmt)
+{
+ tree base;
+ bool indirect;
+ srtype *type;
+ srfield *field;
+ bool realpart, imagpart, address;
+ if (!get_type_field (expr, base, indirect, type, field,
+ realpart, imagpart, address))
+ return;
+
+ type->mark_escape (escapes, stmt);
+}
+
+/* Record accesses in a call statement STMT. */
+
+void
+ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt)
+{
+ tree argtype;
+ tree fndecl;
+ escape_type escapes = does_not_escape;
+ bool free_or_realloc = gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+ || gimple_call_builtin_p (stmt, BUILT_IN_REALLOC);
+
+ /* We check allocation sites in a different location. */
+ if (handled_allocation_stmt (stmt))
+ return;
+
+ /* A few cases here:
+ 1) assigned from the lhs
+ 2) Used in argument
+ If a function being called is global (or indirect)
+ then we reject the types as being escaping. */
+
+ if (tree chain = gimple_call_chain (stmt))
+ record_stmt_expr (chain, node, stmt);
+
+ /* Assigned from LHS. */
+ if (tree lhs = gimple_call_lhs (stmt))
+ {
+ /* FIXME: handle return types. */
+ mark_type_as_escape (TREE_TYPE (lhs), escape_return);
+ }
+
+ /* If we have an internal call, just record the stmt. */
+ if (gimple_call_internal_p (stmt))
+ {
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
+ record_stmt_expr (gimple_call_arg (stmt, i), node, stmt);
+ return;
+ }
+
+ fndecl = gimple_call_fndecl (stmt);
+
+ /* If we have an indrect call, just mark the types as escape. */
+ if (!fndecl)
+ escapes = escape_pointer_function;
+ /* Non local functions cause escape except for calls to free
+ and realloc.
+ FIXME: should support function annotations too. */
+ else if (!free_or_realloc
+ && !cgraph_node::local_info_node (fndecl)->local)
+ escapes = escape_external_function;
+ else if (!free_or_realloc
+ && !cgraph_node::local_info_node (fndecl)->can_change_signature)
+ escapes = escape_cannot_change_signature;
+ /* FIXME: we should be able to handle functions in other partitions. */
+ else if (symtab_node::get (fndecl)->in_other_partition)
+ escapes = escape_external_function;
+
+ if (escapes != does_not_escape)
+ {
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
+ mark_type_as_escape (TREE_TYPE (gimple_call_arg (stmt, i)),
+ escapes);
+ return;
+ }
+
+ argtype = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
+ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ if (argtype)
+ {
+ tree argtypet = TREE_VALUE (argtype);
+ if (!free_or_realloc
+ && VOID_POINTER_P (argtypet))
+ mark_type_as_escape (TREE_TYPE (arg), escape_cast_void);
+ else
+ record_stmt_expr (arg, node, stmt);
+ }
+ else
+ mark_type_as_escape (TREE_TYPE (arg), escape_var_arg_function);
+
+ argtype = argtype ? TREE_CHAIN (argtype) : NULL_TREE;
+ }
+}
+
+void
+ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt)
+{
+ tree base;
+ bool indirect;
+ srtype *type;
+ srfield *field;
+ bool realpart, imagpart, address;
+ if (!get_type_field (expr, base, indirect, type, field,
+ realpart, imagpart, address))
+ return;
+
+ if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg))
+ type->mark_escape (escape_non_optimize, stmt);
+
+ /* Record it. */
+ type->add_access (new sraccess (stmt, node, type, field));
+}
+
+/* Find function corresponding to NODE. */
+
+srfunction *
+ipa_struct_reorg::find_function (cgraph_node *node)
+{
+ for (unsigned i = 0; i < functions.length (); i++)
+ if (functions[i]->node == node)
+ return functions[i];
+ return NULL;
+}
+
+void
+ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type,
+ vec<srdecl *> &worklist,
+ gimple *stmt)
+{
+ if (integer_zerop (newdecl))
+ return;
+
+ if (TREE_CODE (newdecl) == ADDR_EXPR)
+ {
+ srdecl *d = find_decl (TREE_OPERAND (newdecl, 0));
+ if (!d)
+ {
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+ if (d->type == type)
+ return;
+
+ srtype *type1 = d->type;
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ type1->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+
+ srdecl *d = find_decl (newdecl);
+ if (!d)
+ {
+ if (TREE_CODE (newdecl) == INTEGER_CST)
+ {
+ type->mark_escape (escape_int_const, stmt);
+ return;
+ }
+ /* If we have a non void* or a decl (which is hard to track),
+ then mark the type as escaping. */
+ if (!VOID_POINTER_P (TREE_TYPE (newdecl))
+ || DECL_P (newdecl))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nunkown decl: ");
+ print_generic_expr (dump_file, newdecl);
+ fprintf (dump_file, " in type:\n");
+ print_generic_expr (dump_file, TREE_TYPE (newdecl));
+ fprintf (dump_file, "\n");
+ }
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+ /* At this point there should only be unkown void* ssa names. */
+ gcc_assert (TREE_CODE (newdecl) == SSA_NAME);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nrecording unkown decl: ");
+ print_generic_expr (dump_file, newdecl);
+ fprintf (dump_file, " as type:\n");
+ type->simple_dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+ d = current_function->record_decl (type, newdecl, -1);
+ worklist.safe_push (d);
+ return;
+ }
+
+ /* Only add to the worklist if the decl is a SSA_NAME. */
+ if (TREE_CODE (newdecl) == SSA_NAME)
+ worklist.safe_push (d);
+ if (d->type == type)
+ return;
+
+ srtype *type1 = d->type;
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ type1->mark_escape (escape_cast_another_ptr, stmt);
+}
+
+/*
+ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl)
+ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and
+ check to make sure the addition was a multiple of the size.
+ check the pointer type too.
+ b) If the name is sourced from an allocation check the allocation
+ i) Add SSA_NAME (void*) to the worklist if allocated from realloc
+ c) if the name is from a param, make sure the param type was of the
+ original type
+ d) if the name is from a cast/assignment, make sure it is used as that
+ type or void*
+ i) If void* then push the ssa_name into worklist
+*/
+void
+ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
+{
+ tree ssa_name = decl->decl;
+ srtype *type = decl->type;
+
+ /*
+ c) if the name is from a param, make sure the param type was of the
+ original type.
+ */
+ if (SSA_NAME_IS_DEFAULT_DEF (ssa_name))
+ {
+ tree var = SSA_NAME_VAR (ssa_name);
+ if (var
+ && TREE_CODE (var) == PARM_DECL
+ && VOID_POINTER_P (TREE_TYPE (ssa_name)))
+ type->mark_escape (escape_cast_void, NULL);
+ return;
+ }
+ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name);
+
+ /*
+ b) If the name is sourced from an allocation check the allocation
+ i) Add SSA_NAME (void*) to the worklist if allocated from realloc
+ */
+ if (gimple_code (stmt) == GIMPLE_CALL)
+ {
+ /* For realloc, check the type of the argument. */
+ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
+ check_type_and_push (gimple_call_arg (stmt, 0), type, worklist, stmt);
+
+ if (!handled_allocation_stmt (stmt)
+ || !allocate_size (type, stmt))
+ type->mark_escape (escape_return, stmt);
+ return;
+ }
+ /* If the SSA_NAME is sourced from an inline-asm,
+ just mark the type as escaping. */
+ if (gimple_code (stmt) == GIMPLE_ASM)
+ {
+ type->mark_escape (escape_inline_asm, stmt);
+ return;
+ }
+
+ /* If the SSA_NAME is sourced from a PHI check add
+ each name to the worklist and check to make sure
+ they are used correctly. */
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ {
+ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
+ check_type_and_push (gimple_phi_arg_def (stmt, i),
+ type, worklist, stmt);
+ return;
+ }
+
+ gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+ /*
+ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and
+ check to make sure the addition was a multiple of the size.
+ check the pointer type too.
+ */
+
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree num;
+ if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type)))
+ type->mark_escape (escape_non_multiply_size, stmt);
+
+ if (TREE_CODE (rhs) == SSA_NAME)
+ check_type_and_push (rhs, type, worklist, stmt);
+ return;
+ }
+
+ /* Casts between pointers and integer are escaping. */
+ if (gimple_assign_cast_p (stmt))
+ {
+ type->mark_escape (escape_cast_int, stmt);
+ return;
+ }
+
+ /*
+ d) if the name is from a cast/assignment, make sure it is used as that
+ type or void*
+ i) If void* then push the ssa_name into worklist
+ */
+ gcc_assert (gimple_assign_single_p (stmt));
+ check_other_side (decl, rhs, stmt, worklist);
+}
+
+/* Mark the types used by the inline-asm as escaping.
+ It is unkown what happens inside an inline-asm. */
+
+void
+ipa_struct_reorg::mark_types_asm (gasm *astmt)
+{
+ for (unsigned i = 0; i < gimple_asm_ninputs (astmt); i++)
+ {
+ tree v = TREE_VALUE (gimple_asm_input_op (astmt, i));
+ /* If we have &b, just strip the & here. */
+ if (TREE_CODE (v) == ADDR_EXPR)
+ v = TREE_OPERAND (v, 0);
+ mark_expr_escape (v, escape_inline_asm, astmt);
+ }
+ for (unsigned i = 0; i < gimple_asm_noutputs (astmt); i++)
+ {
+ tree v = TREE_VALUE (gimple_asm_output_op (astmt, i));
+ /* If we have &b, just strip the & here. */
+ if (TREE_CODE (v) == ADDR_EXPR)
+ v = TREE_OPERAND (v, 0);
+ mark_expr_escape (v, escape_inline_asm, astmt);
+ }
+}
+
+void
+ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt,
+ vec<srdecl *> &worklist)
+{
+ srtype *type = decl->type;
+
+ if (TREE_CODE (other) == SSA_NAME
+ || DECL_P (other)
+ || TREE_CODE (other) == INTEGER_CST)
+ {
+ check_type_and_push (other, type, worklist, stmt);
+ return;
+ }
+
+ tree t = TREE_TYPE (other);
+ if (!handled_type (t))
+ {
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+
+ srtype *t1 = find_type (inner_type (t));
+ if (t1 == type)
+ {
+ tree base;
+ bool indirect;
+ srtype *type1;
+ srfield *field;
+ bool realpart, imagpart, address;
+ if (!get_type_field (other, base, indirect, type1, field,
+ realpart, imagpart, address))
+ type->mark_escape (escape_cast_another_ptr, stmt);
+
+ return;
+ }
+
+ if (t1)
+ t1->mark_escape (escape_cast_another_ptr, stmt);
+
+ type->mark_escape (escape_cast_another_ptr, stmt);
+}
+
+void
+ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
+ vec<srdecl *> &worklist)
+{
+ srtype *type = decl->type;
+
+ if (gimple_code (stmt) == GIMPLE_RETURN)
+ {
+ type->mark_escape (escape_return, stmt);
+ return;
+ }
+ /* If the SSA_NAME PHI check and add the src to the worklist and
+ check to make sure they are used correctly. */
+ if (gimple_code (stmt) == GIMPLE_PHI)
+ {
+ check_type_and_push (gimple_phi_result (stmt), type, worklist, stmt);
+ return;
+ }
+
+ if (gimple_code (stmt) == GIMPLE_ASM)
+ {
+ mark_types_asm (as_a <gasm *> (stmt));
+ return;
+ }
+
+ if (gimple_code (stmt) == GIMPLE_COND)
+ {
+ tree rhs1 = gimple_cond_lhs (stmt);
+ tree rhs2 = gimple_cond_rhs (stmt);
+ tree orhs = rhs1;
+ if (gimple_cond_code (stmt) != EQ_EXPR
+ && gimple_cond_code (stmt) != NE_EXPR)
+ {
+ mark_expr_escape (rhs1, escape_non_eq, stmt);
+ mark_expr_escape (rhs2, escape_non_eq, stmt);
+ }
+ if (rhs1 == decl->decl)
+ orhs = rhs2;
+ if (integer_zerop (orhs))
+ return;
+ if (TREE_CODE (orhs) != SSA_NAME)
+ mark_expr_escape (rhs1, escape_non_eq, stmt);
+ check_type_and_push (orhs, type, worklist, stmt);
+ return;
+ }
+
+ /* Casts between pointers and integer are escaping. */
+ if (gimple_assign_cast_p (stmt))
+ {
+ type->mark_escape (escape_cast_int, stmt);
+ return;
+ }
+
+ /* We might have a_1 = ptr_2 == ptr_3; */
+ if (is_gimple_assign (stmt)
+ && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree orhs = rhs1;
+ if (gimple_assign_rhs_code (stmt) != EQ_EXPR
+ && gimple_assign_rhs_code (stmt) != NE_EXPR)
+ {
+ mark_expr_escape (rhs1, escape_non_eq, stmt);
+ mark_expr_escape (rhs2, escape_non_eq, stmt);
+ }
+ if (rhs1 == decl->decl)
+ orhs = rhs2;
+ if (integer_zerop (orhs))
+ return;
+ if (TREE_CODE (orhs) != SSA_NAME)
+ mark_expr_escape (rhs1, escape_non_eq, stmt);
+ check_type_and_push (orhs, type, worklist, stmt);
+ return;
+ }
+
+ if (gimple_assign_single_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ /* Check if we have a_1 = b_2; that a_1 is in the correct type. */
+ if (decl->decl == rhs)
+ {
+ check_other_side (decl, lhs, stmt, worklist);
+ return;
+ }
+ }
+
+ if (is_gimple_assign (stmt)
+ && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ tree num;
+ check_other_side (decl, lhs, stmt, worklist);
+ if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type)))
+ type->mark_escape (escape_non_multiply_size, stmt);
+ }
+}
+
+/*
+ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl)
+ d) if the name is from a cast/assignment, make sure it is used as that
+ type or void*
+ i) If void* then push the ssa_name into worklist
+ e) if used in conditional check the other side
+ i) If the conditional is non NE/EQ then mark the type as non rejecting
+ f) Check if the use in a Pointer PLUS EXPR Is used by mulitplication
+ of its size
+ */
+void
+ipa_struct_reorg::check_uses (srdecl *decl, vec<srdecl *> &worklist)
+{
+ tree ssa_name = decl->decl;
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa_name)
+ {
+ gimple *stmt = USE_STMT (use_p);
+
+ if (is_gimple_debug (stmt))
+ continue;
+
+ check_use (decl, stmt, worklist);
+ }
+}
+
+/* Record function corresponding to NODE. */
+
+srfunction *
+ipa_struct_reorg::record_function (cgraph_node *node)
+{
+ function *fn;
+ tree parm, var;
+ unsigned int i;
+ srfunction *sfn;
+ escape_type escapes = does_not_escape;
+
+ sfn = new srfunction (node);
+ functions.safe_push (sfn);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "\nRecording accesses and types from function: %s/%u\n",
+ node->name (), node->order);
+
+ /* Nodes without a body are not interesting. Especially do not
+ visit clones at this point for now - we get duplicate decls
+ there for inline clones at least. */
+ if (!node->has_gimple_body_p () || node->inlined_to)
+ return sfn;
+
+ node->get_body ();
+ fn = DECL_STRUCT_FUNCTION (node->decl);
+
+ if (!fn)
+ return sfn;
+
+ current_function = sfn;
+
+ if (DECL_PRESERVE_P (node->decl))
+ escapes = escape_marked_as_used;
+ else if (!node->local)
+ escapes = escape_visible_function;
+ else if (!node->can_change_signature)
+ escapes = escape_cannot_change_signature;
+ else if (!tree_versionable_function_p (node->decl))
+ escapes = escape_noclonable_function;
+ else if (!opt_for_fn (node->decl, flag_ipa_struct_reorg))
+ escapes = escape_non_optimize;
+
+ basic_block bb;
+ gimple_stmt_iterator si;
+
+ /* Record the static chain decl. */
+ if (fn->static_chain_decl)
+ {
+ srdecl *sd = record_var (fn->static_chain_decl,
+ escapes, -2);
+ if (sd)
+ {
+ /* Specify that this type is used by the static
+ chain so it cannot be split. */
+ sd->type->chain_type = true;
+ sfn->add_arg (sd);
+ sd->type->add_function (sfn);
+ }
+ }
+
+ /* Record the arguments. */
+ for (parm = DECL_ARGUMENTS (node->decl), i = 0;
+ parm;
+ parm = DECL_CHAIN (parm), i++)
+ {
+ srdecl *sd = record_var (parm, escapes, i);
+ if (sd)
+ {
+ sfn->add_arg (sd);
+ sd->type->add_function (sfn);
+ }
+ }
+
+ /* Mark the return type as escaping. */
+ {
+ tree return_type = TREE_TYPE (TREE_TYPE (node->decl));
+ mark_type_as_escape (return_type, escape_return, NULL);
+ }
+
+ /* If the cfg does not exist for the function,
+ don't process the function. */
+ if (!fn->cfg)
+ {
+ current_function = NULL;
+ return sfn;
+ }
+
+ /* The following order is done for recording stage:
+ 0) Record all variables/SSA_NAMES that are of struct type
+ 1) Record MEM_REF/COMPONENT_REFs
+ a) Record SSA_NAMEs (void*) and record that as the accessed type.
+ */
+
+ push_cfun (fn);
+
+ FOR_EACH_LOCAL_DECL (cfun, i, var)
+ {
+ if (TREE_CODE (var) != VAR_DECL)
+ continue;
+
+ record_var (var);
+ }
+
+ for (i = 1; i < num_ssa_names; ++i)
+ {
+ tree name = ssa_name (i);
+ if (!name
+ || has_zero_uses (name)
+ || virtual_operand_p (name))
+ continue;
+
+ record_var (name);
+ }
+
+ /* Find the variables which are used via MEM_REF and are void* types. */
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+ {
+ gimple *stmt = gsi_stmt (si);
+ find_vars (stmt);
+ }
+ }
+
+ auto_vec<srdecl *> worklist;
+ for (unsigned i = 0; i < current_function->decls.length (); i++)
+ {
+ srdecl *decl = current_function->decls[i];
+ if (TREE_CODE (decl->decl) == SSA_NAME)
+ {
+ decl->visited = false;
+ worklist.safe_push (decl);
+ }
+ }
+
+/*
+ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl)
+ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and
+ check to make sure the addition was a multiple of the size.
+ check the pointer type too.
+ b) If the name is sourced from an allocation check the allocation
+ i) Add SSA_NAME (void*) to the worklist if allocated from realloc
+ c) if the name is from a param, make sure the param type was of the
+ original type
+ d) if the name is used in a cast/assignment, make sure it is used as that
+ type or void*
+ i) If void* then push the ssa_name into worklist
+ e) if used in conditional check the other side
+ i) If the conditional is non NE/EQ then mark the type as non rejecting
+ f) Check if the use in a POinter PLUS EXPR Is used by mulitplication
+ of its size
+*/
+
+ while (!worklist.is_empty ())
+ {
+ srdecl *decl = worklist.pop ();
+ if (decl->visited)
+ continue;
+ decl->visited = true;
+ check_definition (decl, worklist);
+ check_uses (decl, worklist);
+ }
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+ {
+ gimple *stmt = gsi_stmt (si);
+ maybe_record_stmt (node, stmt);
+ }
+ }
+
+ pop_cfun ();
+ current_function = NULL;
+ return sfn;
+}
+
+/* Record all accesses for all types including global variables. */
+
+void
+ipa_struct_reorg::record_accesses (void)
+{
+ varpool_node *var;
+ cgraph_node *cnode;
+
+ /* Record global (non-auto) variables first. */
+ FOR_EACH_VARIABLE (var)
+ {
+ if (!var->real_symbol_p ())
+ continue;
+
+ /* Record all variables including the accesses inside a variable. */
+ escape_type escapes = does_not_escape;
+ if (var->externally_visible || !var->definition)
+ escapes = escape_via_global_var;
+ if (var->in_other_partition)
+ escapes = escape_via_global_var;
+ if (!var->externally_visible && var->definition)
+ var->get_constructor ();
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Recording global variable: ");
+ print_generic_expr (dump_file, var->decl);
+ fprintf (dump_file, "\n");
+ }
+ record_var (var->decl, escapes);
+ }
+
+ FOR_EACH_FUNCTION (cnode)
+ {
+ if (!cnode->real_symbol_p ())
+ continue;
+
+ /* Record accesses inside a function. */
+ if (cnode->definition)
+ record_function (cnode);
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "all types (before pruning):\n");
+ dump_types (dump_file);
+ fprintf (dump_file, "all functions (before pruning):\n");
+ dump_functions (dump_file);
+ }
+ done_recording = true;
+}
+
+/* A helper function to detect cycles (recusive) types.
+ Return TRUE if TYPE was a rescusive type. */
+
+bool
+ipa_struct_reorg::walk_field_for_cycles (srtype *type)
+{
+ unsigned i;
+ srfield *field;
+
+ type->visited = true;
+ if (type->escaped_rescusive ())
+ return true;
+
+ if (type->has_escaped ())
+ return false;
+
+ FOR_EACH_VEC_ELT (type->fields, i, field)
+ {
+ if (!field->type)
+ ;
+ else if (field->type->visited
+ || walk_field_for_cycles (field->type))
+ {
+ type->mark_escape (escape_rescusive_type, NULL);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Clear visited on all types. */
+
+void
+ipa_struct_reorg::clear_visited (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ types[i]->visited = false;
+}
+
+/* Detect recusive types and mark them as escaping. */
+
+void
+ipa_struct_reorg::detect_cycles (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ if (types[i]->has_escaped ())
+ continue;
+
+ clear_visited ();
+ walk_field_for_cycles (types[i]);
+ }
+}
+
+/* Propagate escaping to depdenent types. */
+
+void
+ipa_struct_reorg::propagate_escape (void)
+{
+ unsigned i;
+ srtype *type;
+ bool changed = false;
+
+ do
+ {
+ changed = false;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ for (tree field = TYPE_FIELDS (type->type);
+ field;
+ field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL
+ && handled_type (TREE_TYPE (field)))
+ {
+ tree t = inner_type (TREE_TYPE (field));
+ srtype *type1 = find_type (t);
+ if (!type1)
+ continue;
+ if (type1->has_escaped ()
+ && !type->has_escaped ())
+ {
+ type->mark_escape (escape_dependent_type_escapes, NULL);
+ changed = true;
+ }
+ if (type->has_escaped ()
+ && !type1->has_escaped ())
+ {
+ type1->mark_escape (escape_dependent_type_escapes, NULL);
+ changed = true;
+ }
+ }
+ }
+ }
+ } while (changed);
+}
+
+/* Prune the escaped types and their decls from what was recorded. */
+
+void
+ipa_struct_reorg::prune_escaped_types (void)
+{
+ detect_cycles ();
+ propagate_escape ();
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "all types (after prop but before pruning):\n");
+ dump_types (dump_file);
+ fprintf (dump_file, "all functions (after prop but before pruning):\n");
+ dump_functions (dump_file);
+ }
+
+ if (dump_file)
+ dump_types_escaped (dump_file);
+
+ /* Prune the function arguments which escape
+ and functions which have no types as arguments. */
+ for (unsigned i = 0; i < functions.length ();)
+ {
+ srfunction *function = functions[i];
+
+ /* Prune function arguments of types that escape. */
+ for (unsigned j = 0; j < function->args.length ();)
+ {
+ if (function->args[j]->type->has_escaped ())
+ function->args.ordered_remove (j);
+ else
+ j++;
+ }
+
+ /* Prune global variables that the function uses of types
+ that escape. */
+ for (unsigned j = 0; j < function->globals.length ();)
+ {
+ if (function->globals[j]->type->has_escaped ())
+ function->globals.ordered_remove (j);
+ else
+ j++;
+ }
+
+ /* Prune variables that the function uses of types that escape. */
+ for (unsigned j = 0; j < function->decls.length ();)
+ {
+ srdecl *decl = function->decls[j];
+ if (decl->type->has_escaped ())
+ {
+ function->decls.ordered_remove (j);
+ delete decl;
+ }
+ else
+ j++;
+ }
+
+ /* Prune functions which don't refer to any variables any more. */
+ if (function->args.is_empty ()
+ && function->decls.is_empty ()
+ && function->globals.is_empty ())
+ {
+ delete function;
+ functions.ordered_remove (i);
+ }
+ else
+ i++;
+ }
+
+ /* Prune globals of types that escape, all references to those decls
+ will have been removed in the first loop. */
+ for (unsigned j = 0; j < globals.decls.length ();)
+ {
+ srdecl *decl = globals.decls[j];
+ if (decl->type->has_escaped ())
+ {
+ globals.decls.ordered_remove (j);
+ delete decl;
+ }
+ else
+ j++;
+ }
+
+ /* Prune types that escape, all references to those types
+ will have been removed in the above loops. */
+ for (unsigned i = 0; i < types.length ();)
+ {
+ srtype *type = types[i];
+ if (type->has_escaped ())
+ {
+ /* All references to this type should have been removed now. */
+ delete type;
+ types.ordered_remove (i);
+ }
+ else
+ i++;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "all types (after pruning):\n");
+ dump_types (dump_file);
+ fprintf (dump_file, "all functions (after pruning):\n");
+ dump_functions (dump_file);
+ }
+}
+
+/* Analyze all of the types. */
+
+void
+ipa_struct_reorg::analyze_types (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ if (!types[i]->has_escaped ())
+ types[i]->analyze ();
+ }
+}
+
+/* When struct A has a struct B member, B's type info
+ is not stored in
+ TYPE_FIELDS (TREE_TYPE (TYPE_FIELDS (typeA)))
+ Try to restore B's type information. */
+
+void
+ipa_struct_reorg::restore_field_type (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ for (unsigned j = 0; j < types[i]->fields.length (); j++)
+ {
+ srfield *field = types[i]->fields[j];
+ if (TREE_CODE (inner_type (field->fieldtype)) == RECORD_TYPE)
+ {
+ /* If field type has TYPE_FIELDS information,
+ we do not need to do this. */
+ if (TYPE_FIELDS (field->type->type) != NULL)
+ continue;
+ for (unsigned k = 0; k < types.length (); k++)
+ {
+ if (i == k)
+ continue;
+ const char *type1 = get_type_name (field->type->type);
+ const char *type2 = get_type_name (types[k]->type);
+ if (type1 == NULL || type2 == NULL)
+ continue;
+ if (type1 == type2
+ && TYPE_FIELDS (types[k]->type))
+ field->type = types[k];
+ }
+ }
+ }
+ }
+}
+
+/* Create all new types we want to create. */
+
+bool
+ipa_struct_reorg::create_new_types (void)
+{
+ int newtypes = 0;
+ clear_visited ();
+ for (unsigned i = 0; i < types.length (); i++)
+ newtypes += types[i]->create_new_type ();
+
+ if (dump_file)
+ {
+ if (newtypes)
+ fprintf (dump_file, "\nNumber of structures to transform is %d\n",
+ newtypes);
+ else
+ fprintf (dump_file, "\nNo structures to transform.\n");
+ }
+
+ return newtypes != 0;
+}
+
+/* Create all the new decls except for the new arguments
+ which create_new_functions would have created. */
+
+void
+ipa_struct_reorg::create_new_decls (void)
+{
+ globals.create_new_decls ();
+ for (unsigned i = 0; i < functions.length (); i++)
+ functions[i]->create_new_decls ();
+}
+
+/* Create the new arguments for the function corresponding to NODE. */
+
+void
+ipa_struct_reorg::create_new_args (cgraph_node *new_node)
+{
+ tree decl = new_node->decl;
+ auto_vec<tree> params;
+ push_function_arg_decls (&params, decl);
+ vec<ipa_adjusted_param, va_gc> *adjs = NULL;
+ vec_safe_reserve (adjs, params.length ());
+ for (unsigned i = 0; i < params.length (); i++)
+ {
+ struct ipa_adjusted_param adj;
+ tree parm = params[i];
+ memset (&adj, 0, sizeof (adj));
+ adj.base_index = i;
+ adj.prev_clone_index = i;
+ srtype *t = find_type (inner_type (TREE_TYPE (parm)));
+ if (!t
+ || t->has_escaped ()
+ || !t->has_new_type ())
+ {
+ adj.op = IPA_PARAM_OP_COPY;
+ vec_safe_push (adjs, adj);
+ continue;
+ }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Creating a new argument for: ");
+ print_generic_expr (dump_file, params[i]);
+ fprintf (dump_file, " in function: ");
+ print_generic_expr (dump_file, decl);
+ fprintf (dump_file, "\n");
+ }
+ adj.op = IPA_PARAM_OP_NEW;
+ adj.param_prefix_index = IPA_PARAM_PREFIX_REORG;
+ for (unsigned j = 0; j < max_split && t->newtype[j]; j++)
+ {
+ adj.type = reconstruct_complex_type (TREE_TYPE (parm),
+ t->newtype[j]);
+ vec_safe_push (adjs, adj);
+ }
+ }
+ ipa_param_body_adjustments *adjustments
+ = new ipa_param_body_adjustments (adjs, decl);
+ adjustments->modify_formal_parameters ();
+ auto_vec<tree> new_params;
+ push_function_arg_decls (&new_params, decl);
+ unsigned veclen = vec_safe_length (adjs);
+ for (unsigned i = 0; i < veclen; i++)
+ {
+ if ((*adjs)[i].op != IPA_PARAM_OP_NEW)
+ continue;
+ tree decl = params[(*adjs)[i].base_index];
+ srdecl *d = find_decl (decl);
+ if (!d)
+ continue;
+ unsigned j = 0;
+ while (j < max_split && d->newdecl[j])
+ j++;
+ d->newdecl[j] = new_params[i];
+ }
+
+ function *fn = DECL_STRUCT_FUNCTION (decl);
+
+ if (!fn->static_chain_decl)
+ return;
+ srdecl *chain = find_decl (fn->static_chain_decl);
+ if (!chain)
+ return;
+
+ srtype *type = chain->type;
+ tree orig_var = chain->decl;
+ const char *tname = NULL;
+ if (DECL_NAME (orig_var))
+ tname = IDENTIFIER_POINTER (DECL_NAME (orig_var));
+ gcc_assert (!type->newtype[1]);
+ tree new_name = NULL;
+ char *name = NULL;
+ if (tname)
+ {
+ name = concat (tname, ".reorg.0", NULL);
+ new_name = get_identifier (name);
+ free (name);
+ }
+ tree newtype1 = reconstruct_complex_type (TREE_TYPE (orig_var),
+ type->newtype[0]);
+ chain->newdecl[0] = build_decl (DECL_SOURCE_LOCATION (orig_var),
+ PARM_DECL, new_name, newtype1);
+ copy_var_attributes (chain->newdecl[0], orig_var);
+ fn->static_chain_decl = chain->newdecl[0];
+}
+
+/* Find the refered DECL in the current function or globals.
+ If this is a global decl, record that as being used
+ in the current function. */
+
+srdecl *
+ipa_struct_reorg::find_decl (tree decl)
+{
+ srdecl *d;
+ d = globals.find_decl (decl);
+ if (d)
+ {
+ /* Record the global usage in the current function. */
+ if (!done_recording && current_function)
+ {
+ bool add = true;
+ /* No reason to add it to the current function if it is
+ already recorded as such. */
+ for (unsigned i = 0; i < current_function->globals.length (); i++)
+ {
+ if (current_function->globals[i] == d)
+ {
+ add = false;
+ break;
+ }
+ }
+ if (add)
+ current_function->globals.safe_push (d);
+ }
+ return d;
+ }
+ if (current_function)
+ return current_function->find_decl (decl);
+ return NULL;
+}
+
+/* Create new function clones for the cases where the arguments
+ need to be changed. */
+
+void
+ipa_struct_reorg::create_new_functions (void)
+{
+ for (unsigned i = 0; i < functions.length (); i++)
+ {
+ srfunction *f = functions[i];
+ bool anyargchanges = false;
+ cgraph_node *new_node;
+ cgraph_node *node = f->node;
+ int newargs = 0;
+ if (f->old)
+ continue;
+
+ if (f->args.length () == 0)
+ continue;
+
+ for (unsigned j = 0; j < f->args.length (); j++)
+ {
+ srdecl *d = f->args[j];
+ srtype *t = d->type;
+ if (t->has_new_type ())
+ {
+ newargs += t->newtype[1] != NULL;
+ anyargchanges = true;
+ }
+ }
+ if (!anyargchanges)
+ continue;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Creating a clone of function: ");
+ f->simple_dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+ statistics_counter_event (NULL, "Create new function", 1);
+ new_node = node->create_version_clone_with_body (vNULL, NULL,
+ NULL, NULL, NULL,
+ "struct_reorg");
+ new_node->can_change_signature = node->can_change_signature;
+ new_node->make_local ();
+ f->newnode = new_node;
+ srfunction *n = record_function (new_node);
+ current_function = n;
+ n->old = f;
+ f->newf = n;
+ /* Create New arguments. */
+ create_new_args (new_node);
+ current_function = NULL;
+ }
+}
+
+bool
+ipa_struct_reorg::rewrite_lhs_rhs (tree lhs, tree rhs,
+ tree newlhs[max_split],
+ tree newrhs[max_split])
+{
+ bool l = rewrite_expr (lhs, newlhs);
+ bool r = rewrite_expr (rhs, newrhs);
+
+ /* Handle NULL pointer specially. */
+ if (l && !r && integer_zerop (rhs))
+ {
+ r = true;
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ newrhs[i] = fold_convert (TREE_TYPE (newlhs[i]), rhs);
+ }
+
+ return l || r;
+}
+
+bool
+ipa_struct_reorg::rewrite_expr (tree expr,
+ tree newexpr[max_split],
+ bool ignore_missing_decl)
+{
+ tree base;
+ bool indirect;
+ srtype *t;
+ srfield *f;
+ bool realpart, imagpart;
+ bool address;
+
+ tree newbase[max_split];
+ memset (newexpr, 0, sizeof (tree[max_split]));
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ srtype *t = find_type (TREE_TYPE (expr));
+ if (!t)
+ return false;
+ gcc_assert (CONSTRUCTOR_NELTS (expr) == 0);
+ if (!t->has_new_type ())
+ return false;
+ for (unsigned i = 0; i < max_split && t->newtype[i]; i++)
+ newexpr[i] = build_constructor (t->newtype[i], NULL);
+ return true;
+ }
+
+ if (!get_type_field (expr, base, indirect, t, f,
+ realpart, imagpart, address))
+ return false;
+
+ /* If the type is not changed, then just return false. */
+ if (!t->has_new_type ())
+ return false;
+
+ /* NULL pointer handling is "special". */
+ if (integer_zerop (base))
+ {
+ gcc_assert (indirect && !address);
+ for (unsigned i = 0; i < max_split && t->newtype[i]; i++)
+ {
+ tree newtype1 = reconstruct_complex_type (TREE_TYPE (base),
+ t->newtype[i]);
+ newbase[i] = fold_convert (newtype1, base);
+ }
+ }
+ else
+ {
+ srdecl *d = find_decl (base);
+
+ if (!d && dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Can't find decl:\n");
+ print_generic_expr (dump_file, base);
+ fprintf (dump_file, "\ntype:\n");
+ t->dump (dump_file);
+ }
+ if (!d && ignore_missing_decl)
+ return true;
+ gcc_assert (d);
+ memcpy (newbase, d->newdecl, sizeof (d->newdecl));
+ }
+
+ if (f == NULL)
+ {
+ memcpy (newexpr, newbase, sizeof (newbase));
+ for (unsigned i = 0; i < max_split && newexpr[i]; i++)
+ {
+ if (address)
+ newexpr[i] = build_fold_addr_expr (newexpr[i]);
+ if (indirect)
+ newexpr[i] = build_simple_mem_ref (newexpr[i]);
+ if (imagpart)
+ newexpr[i] = build1 (IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (newexpr[i])),
+ newexpr[i]);
+ if (realpart)
+ newexpr[i] = build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (newexpr[i])),
+ newexpr[i]);
+ }
+ return true;
+ }
+
+ tree newdecl = newbase[f->clusternum];
+ for (unsigned i = 0; i < max_split && f->newfield[i]; i++)
+ {
+ tree newbase1 = newdecl;
+ if (address)
+ newbase1 = build_fold_addr_expr (newbase1);
+ if (indirect)
+ newbase1 = build_simple_mem_ref (newbase1);
+ newexpr[i] = build3 (COMPONENT_REF, TREE_TYPE (f->newfield[i]),
+ newbase1, f->newfield[i], NULL_TREE);
+ if (imagpart)
+ newexpr[i] = build1 (IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (newexpr[i])),
+ newexpr[i]);
+ if (realpart)
+ newexpr[i] = build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (newexpr[i])),
+ newexpr[i]);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "cluster: %d. decl = ", (int)f->clusternum);
+ print_generic_expr (dump_file, newbase1);
+ fprintf (dump_file, "\nnewexpr = ");
+ print_generic_expr (dump_file, newexpr[i]);
+ fprintf (dump_file, "\n");
+ }
+ }
+ return true;
+}
+
+bool
+ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+{
+ bool remove = false;
+ if (gimple_clobber_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree newlhs[max_split];
+ if (!rewrite_expr (lhs, newlhs))
+ return false;
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ {
+ tree clobber = build_constructor (TREE_TYPE (newlhs[i]), NULL);
+ TREE_THIS_VOLATILE (clobber) = true;
+ gimple *newstmt = gimple_build_assign (newlhs[i], clobber);
+ gsi_insert_before (gsi, newstmt, GSI_SAME_STMT);
+ remove = true;
+ }
+ return remove;
+ }
+
+ if (gimple_assign_rhs_code (stmt) == EQ_EXPR
+ || gimple_assign_rhs_code (stmt) == NE_EXPR)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree newrhs1[max_split];
+ tree newrhs2[max_split];
+ tree_code rhs_code = gimple_assign_rhs_code (stmt);
+ tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR;
+ if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2))
+ return false;
+ tree newexpr = NULL_TREE;
+ for (unsigned i = 0; i < max_split && newrhs1[i]; i++)
+ {
+ tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node,
+ newrhs1[i], newrhs2[i]);
+ if (!newexpr)
+ newexpr = expr;
+ else
+ newexpr = gimplify_build2 (gsi, code, boolean_type_node,
+ newexpr, expr);
+ }
+
+ if (newexpr)
+ {
+ newexpr = fold_convert (TREE_TYPE (gimple_assign_lhs (stmt)),
+ newexpr);
+ gimple_assign_set_rhs_from_tree (gsi, newexpr);
+ update_stmt (stmt);
+ }
+ return false;
+ }
+
+ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree newlhs[max_split];
+ tree newrhs[max_split];
+
+ if (!rewrite_lhs_rhs (lhs, rhs1, newlhs, newrhs))
+ return false;
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)));
+ tree num;
+ /* Check if rhs2 is a multiplication of the size of the type. */
+ if (!is_result_of_mult (rhs2, &num, size))
+ internal_error (
+ "The rhs of pointer is not a multiplicate and it slips through");
+
+ num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num);
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ {
+ gimple *new_stmt;
+
+ tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i])));
+ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize);
+ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR,
+ newrhs[i], newsize);
+ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+ remove = true;
+ }
+ return remove;
+ }
+ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "rewriting statement:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ tree newlhs[max_split];
+ tree newrhs[max_split];
+ if (!rewrite_lhs_rhs (lhs, rhs, newlhs, newrhs))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nDid nothing to statement.\n");
+ return false;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nreplaced with:\n");
+ for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++)
+ {
+ gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs,
+ newrhs[i] ? newrhs[i] : rhs);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ print_gimple_stmt (dump_file, newstmt, 0);
+ fprintf (dump_file, "\n");
+ }
+ gsi_insert_before (gsi, newstmt, GSI_SAME_STMT);
+ remove = true;
+ }
+ return remove;
+ }
+
+ return remove;
+}
+
+/* Rewrite function call statement STMT. Return TRUE if the statement
+ is to be removed. */
+
+bool
+ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
+{
+ /* Handled allocation calls are handled seperately from normal
+ function calls. */
+ if (handled_allocation_stmt (stmt))
+ {
+ tree lhs = gimple_call_lhs (stmt);
+ tree newrhs1[max_split];
+ srdecl *decl = find_decl (lhs);
+ if (!decl || !decl->type)
+ return false;
+ srtype *type = decl->type;
+ tree num = allocate_size (type, stmt);
+ gcc_assert (num);
+ memset (newrhs1, 0, sizeof (newrhs1));
+
+ /* The realloc call needs to have its first argument rewritten. */
+ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
+ {
+ tree rhs1 = gimple_call_arg (stmt, 0);
+ if (integer_zerop (rhs1))
+ {
+ for (unsigned i = 0; i < max_split; i++)
+ newrhs1[i] = rhs1;
+ }
+ else if (!rewrite_expr (rhs1, newrhs1))
+ internal_error ("Rewrite failed for realloc");
+ }
+
+ /* Go through each new lhs. */
+ for (unsigned i = 0; i < max_split && decl->newdecl[i]; i++)
+ {
+ tree newsize = TYPE_SIZE_UNIT (type->type);
+ gimple *g;
+ /* Every allocation except for calloc needs
+ the size multiplied out. */
+ if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
+ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize);
+
+ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA))
+ g = gimple_build_call (gimple_call_fndecl (stmt),
+ 1, newsize);
+ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
+ g = gimple_build_call (gimple_call_fndecl (stmt),
+ 2, num, newsize);
+ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
+ g = gimple_build_call (gimple_call_fndecl (stmt),
+ 2, newrhs1[i], newsize);
+ else
+ gcc_assert (false);
+ gimple_call_set_lhs (g, decl->newdecl[i]);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ }
+ return true;
+ }
+
+ /* The function call free needs to be handled special. */
+ if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ {
+ tree expr = gimple_call_arg (stmt, 0);
+ tree newexpr[max_split];
+ if (!rewrite_expr (expr, newexpr))
+ return false;
+
+ if (newexpr[1] == NULL)
+ {
+ gimple_call_set_arg (stmt, 0, newexpr[0]);
+ update_stmt (stmt);
+ return false;
+ }
+
+ for (unsigned i = 0; i < max_split && newexpr[i]; i++)
+ {
+ gimple *g = gimple_build_call (gimple_call_fndecl (stmt),
+ 1, newexpr[i]);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ }
+ return true;
+ }
+
+ /* Otherwise, look up the function to see if we have cloned it
+ and rewrite the arguments. */
+ tree fndecl = gimple_call_fndecl (stmt);
+
+ /* Indirect calls are already marked as escaping so ignore. */
+ if (!fndecl)
+ return false;
+
+ cgraph_node *node = cgraph_node::get (fndecl);
+ gcc_assert (node);
+ srfunction *f = find_function (node);
+
+ /* Did not find the function or had not cloned it return saying don't
+ change the function call. */
+ if (!f || !f->newf)
+ return false;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Changing arguments for function call :\n");
+ print_gimple_expr (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ /* Move over to the new function. */
+ f = f->newf;
+
+ tree chain = gimple_call_chain (stmt);
+ unsigned nargs = gimple_call_num_args (stmt);
+ auto_vec<tree> vargs (nargs);
+
+ if (chain)
+ {
+ tree newchains[max_split];
+ if (rewrite_expr (chain, newchains))
+ {
+ /* Chain decl's type cannot be split and but it can change. */
+ gcc_assert (newchains[1] == NULL);
+ chain = newchains[0];
+ }
+ }
+
+ for (unsigned i = 0; i < nargs; i++)
+ vargs.quick_push (gimple_call_arg (stmt, i));
+
+ int extraargs = 0;
+
+ for (unsigned i = 0; i < f->args.length (); i++)
+ {
+ srdecl *d = f->args[i];
+ if (d->argumentnum == -2)
+ continue;
+ gcc_assert (d->argumentnum != -1);
+ tree arg = vargs[d->argumentnum + extraargs];
+ tree newargs[max_split];
+ if (!rewrite_expr (arg, newargs))
+ continue;
+
+ /* If this ARG has a replacement handle the replacement. */
+ for (unsigned j = 0; j < max_split && d->newdecl[j]; j++)
+ {
+ gcc_assert (newargs[j]);
+ /* If this is the first replacement of the arugment,
+ then just replace it. */
+ if (j == 0)
+ vargs[d->argumentnum + extraargs] = newargs[j];
+ else
+ {
+ /* More than one replacement,
+ we need to insert into the array. */
+ extraargs++;
+ vargs.safe_insert (d->argumentnum + extraargs, newargs[j]);
+ }
+ }
+ }
+
+ gcall *new_stmt;
+
+ new_stmt = gimple_build_call_vec (f->node->decl, vargs);
+
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gimple_call_copy_flags (new_stmt, stmt);
+ gimple_call_set_chain (new_stmt, chain);
+
+ gimple_set_modified (new_stmt, true);
+
+ if (gimple_vdef (new_stmt)
+ && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+
+ gsi_replace (gsi, new_stmt, false);
+
+ /* We need to defer cleaning EH info on the new statement to
+ fixup-cfg. We may not have dominator information at this point
+ and thus would end up with unreachable blocks and have no way
+ to communicate that we need to run CFG cleanup then. */
+ int lp_nr = lookup_stmt_eh_lp (stmt);
+ if (lp_nr != 0)
+ {
+ remove_stmt_from_eh_lp (stmt);
+ add_stmt_to_eh_lp (new_stmt, lp_nr);
+ }
+
+ return false;
+}
+
+/* Rewrite the conditional statement STMT. Return TRUE if the
+ old statement is to be removed. */
+
+bool
+ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi)
+{
+ tree_code rhs_code = gimple_cond_code (stmt);
+
+ /* Handle only equals or not equals conditionals. */
+ if (rhs_code != EQ_EXPR
+ && rhs_code != NE_EXPR)
+ return false;
+ tree rhs1 = gimple_cond_lhs (stmt);
+ tree rhs2 = gimple_cond_rhs (stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "COND: Rewriting\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ print_generic_expr (dump_file, rhs1);
+ fprintf (dump_file, "\n");
+ print_generic_expr (dump_file, rhs2);
+ fprintf (dump_file, "\n");
+ }
+
+ tree newrhs1[max_split];
+ tree newrhs2[max_split];
+ tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR;
+ if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nDid nothing to statement.\n");
+ return false;
+ }
+
+ tree newexpr = NULL_TREE;
+ for (unsigned i = 0; i < max_split && newrhs1[i]; i++)
+ {
+ tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node,
+ newrhs1[i], newrhs2[i]);
+ if (!newexpr)
+ newexpr = expr;
+ else
+ newexpr = gimplify_build2 (gsi, code, boolean_type_node,
+ newexpr, expr);
+ }
+
+ if (newexpr)
+ {
+ gimple_cond_set_lhs (stmt, newexpr);
+ gimple_cond_set_rhs (stmt, boolean_true_node);
+ update_stmt (stmt);
+ }
+ return false;
+}
+
+/* Rewrite debug statments if possible. Return TRUE if the statement
+ should be removed. */
+
+bool
+ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *)
+{
+ bool remove = false;
+ if (gimple_debug_bind_p (stmt))
+ {
+ tree var = gimple_debug_bind_get_var (stmt);
+ tree newvar[max_split];
+ if (rewrite_expr (var, newvar, true))
+ remove = true;
+ if (gimple_debug_bind_has_value_p (stmt))
+ {
+ var = gimple_debug_bind_get_value (stmt);
+ if (TREE_CODE (var) == POINTER_PLUS_EXPR)
+ var = TREE_OPERAND (var, 0);
+ if (rewrite_expr (var, newvar, true))
+ remove = true;
+ }
+ }
+ else if (gimple_debug_source_bind_p (stmt))
+ {
+ tree var = gimple_debug_source_bind_get_var (stmt);
+ tree newvar[max_split];
+ if (rewrite_expr (var, newvar, true))
+ remove = true;
+ var = gimple_debug_source_bind_get_value (stmt);
+ if (TREE_CODE (var) == POINTER_PLUS_EXPR)
+ var = TREE_OPERAND (var, 0);
+ if (rewrite_expr (var, newvar, true))
+ remove = true;
+ }
+
+ return remove;
+}
+
+/* Rewrite PHI nodes, return true if the PHI was replaced. */
+
+bool
+ipa_struct_reorg::rewrite_phi (gphi *phi)
+{
+ tree newlhs[max_split];
+ gphi *newphi[max_split];
+ tree result = gimple_phi_result (phi);
+ gphi_iterator gsi;
+
+ memset (newphi, 0, sizeof (newphi));
+
+ if (!rewrite_expr (result, newlhs))
+ return false;
+
+ if (newlhs[0] == NULL)
+ return false;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nrewriting PHI:");
+ print_gimple_stmt (dump_file, phi, 0);
+ }
+
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ newphi[i] = create_phi_node (newlhs[i], gimple_bb (phi));
+
+ for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
+ {
+ tree newrhs[max_split];
+ phi_arg_d rhs = *gimple_phi_arg (phi, i);
+ rewrite_expr (rhs.def, newrhs);
+ for (unsigned j = 0; j < max_split && newlhs[j]; j++)
+ {
+ SET_PHI_ARG_DEF (newphi[j], i, newrhs[j]);
+ gimple_phi_arg_set_location (newphi[j], i, rhs.locus);
+ update_stmt (newphi[j]);
+ }
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ninto\n:");
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ {
+ print_gimple_stmt (dump_file, newphi[i], 0);
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ gsi = gsi_for_phi (phi);
+ remove_phi_node (&gsi, false);
+
+ return true;
+}
+
+/* Rewrite gimple statement STMT, return true if the STATEMENT
+ is to be removed. */
+
+bool
+ipa_struct_reorg::rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi)
+{
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_ASSIGN:
+ return rewrite_assign (as_a <gassign *> (stmt), gsi);
+ case GIMPLE_CALL:
+ return rewrite_call (as_a <gcall *> (stmt), gsi);
+ case GIMPLE_COND:
+ return rewrite_cond (as_a <gcond *> (stmt), gsi);
+ break;
+ case GIMPLE_GOTO:
+ case GIMPLE_SWITCH:
+ break;
+ case GIMPLE_DEBUG:
+ case GIMPLE_ASM:
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Does the function F uses any decl which has changed. */
+
+bool
+ipa_struct_reorg::has_rewritten_type (srfunction *f)
+{
+ for (unsigned i = 0; i < f->decls.length (); i++)
+ {
+ srdecl *d = f->decls[i];
+ if (d->newdecl[0] != d->decl)
+ return true;
+ }
+
+ for (unsigned i = 0; i < f->globals.length (); i++)
+ {
+ srdecl *d = f->globals[i];
+ if (d->newdecl[0] != d->decl)
+ return true;
+ }
+ return false;
+}
+
+/* Rewrite the functions if needed, return
+ the TODOs requested. */
+
+unsigned
+ipa_struct_reorg::rewrite_functions (void)
+{
+ unsigned retval = 0;
+
+ restore_field_type ();
+ /* Create new types, if we did not create any new types,
+ then don't rewrite any accesses. */
+ if (!create_new_types ())
+ return 0;
+
+ if (functions.length ())
+ {
+ retval = TODO_remove_functions;
+ create_new_functions ();
+ }
+
+ create_new_decls ();
+
+ for (unsigned i = 0; i < functions.length (); i++)
+ {
+ srfunction *f = functions[i];
+ if (f->newnode)
+ continue;
+
+ /* Function uses no rewriten types so don't cause a rewrite. */
+ if (!has_rewritten_type (f))
+ continue;
+
+ cgraph_node *node = f->node;
+ basic_block bb;
+
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ current_function = f;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nBefore rewrite:\n");
+ dump_function_to_file (current_function_decl, dump_file,
+ dump_flags | TDF_VOPS);
+ }
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si);)
+ {
+ if (rewrite_phi (si.phi ()))
+ si = gsi_start_phis (bb);
+ else
+ gsi_next (&si);
+ }
+
+ for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);)
+ {
+ gimple *stmt = gsi_stmt (si);
+ if (rewrite_stmt (stmt, &si))
+ gsi_remove (&si, true);
+ else
+ gsi_next (&si);
+ }
+ }
+
+ /* Debug statements need to happen after all other statements
+ have changed. */
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);)
+ {
+ gimple *stmt = gsi_stmt (si);
+ if (gimple_code (stmt) == GIMPLE_DEBUG
+ && rewrite_debug (stmt, &si))
+ gsi_remove (&si, true);
+ else
+ gsi_next (&si);
+ }
+ }
+
+ /* Release the old SSA_NAMES for old arguments. */
+ if (f->old)
+ {
+ for (unsigned i = 0; i < f->args.length (); i++)
+ {
+ srdecl *d = f->args[i];
+ if (d->newdecl[0] != d->decl)
+ {
+ tree ssa_name = ssa_default_def (cfun, d->decl);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Found ");
+ print_generic_expr (dump_file, ssa_name);
+ fprintf (dump_file, " to be released.\n");
+ }
+ release_ssa_name (ssa_name);
+ }
+ }
+ }
+
+ update_ssa (TODO_update_ssa_only_virtuals);
+
+ if (flag_tree_pta)
+ compute_may_aliases ();
+
+ remove_unused_locals ();
+
+ cgraph_edge::rebuild_edges ();
+
+ free_dominance_info (CDI_DOMINATORS);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nAfter rewrite:\n");
+ dump_function_to_file (current_function_decl, dump_file,
+ dump_flags | TDF_VOPS);
+ }
+
+ pop_cfun ();
+ current_function = NULL;
+ }
+
+ return retval | TODO_verify_all;
+}
+
+unsigned int
+ipa_struct_reorg::execute (void)
+{
+ /* FIXME: If there is a top-level inline-asm,
+ the pass immediately returns. */
+ if (symtab->first_asm_symbol ())
+ return 0;
+ record_accesses ();
+ prune_escaped_types ();
+ analyze_types ();
+
+ return rewrite_functions ();
+}
+
+const pass_data pass_data_ipa_struct_reorg =
+{
+ SIMPLE_IPA_PASS, // type
+ "struct_reorg", // name
+ OPTGROUP_NONE, // optinfo_flags
+ TV_IPA_STRUCT_REORG, // tv_id
+ 0, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // todo_flags_start
+ 0, // todo_flags_finish
+};
+
+class pass_ipa_struct_reorg : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_struct_reorg (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_struct_reorg, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *);
+ virtual unsigned int execute (function *)
+ {
+ return ipa_struct_reorg ().execute ();
+ }
+
+}; // class pass_ipa_struct_reorg
+
+bool
+pass_ipa_struct_reorg::gate (function *)
+{
+ return (optimize
+ && flag_ipa_struct_reorg
+ /* Don't bother doing anything if the program has errors. */
+ && !seen_error ());
+}
+
+} // anon namespace
+
+
+simple_ipa_opt_pass *
+make_pass_ipa_struct_reorg (gcc::context *ctxt)
+{
+ return new pass_ipa_struct_reorg (ctxt);
+}
\ No newline at end of file
diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
new file mode 100644
index 000000000..a58794070
--- /dev/null
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
@@ -0,0 +1,235 @@
+/* Struct-reorg optimizations.
+ Copyright (C) 2016-2023 Free Software Foundation, Inc.
+ Contributed by Andrew Pinski <apinski@cavium.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/>. */
+
+#ifndef IPA_STRUCT_REORG_H
+#define IPA_STRUCT_REORG_H
+
+namespace struct_reorg {
+
+const int max_split = 2;
+
+template <typename type>
+struct auto_vec_del : auto_vec<type *>
+{
+ ~auto_vec_del ();
+};
+
+template <typename T>
+auto_vec_del<T>::~auto_vec_del (void)
+{
+ unsigned i;
+ T *t;
+ FOR_EACH_VEC_ELT (*this, i, t)
+ {
+ delete t;
+ }
+}
+
+enum escape_type
+{
+ does_not_escape,
+#define DEF_ESCAPE(ENUM, TEXT) ENUM,
+#include "escapes.def"
+ escape_max_escape
+};
+
+const char *escape_type_string[escape_max_escape - 1] =
+{
+#define DEF_ESCAPE(ENUM, TEXT) TEXT,
+#include "escapes.def"
+};
+
+struct srfield;
+struct srtype;
+struct sraccess;
+struct srdecl;
+struct srfunction;
+
+struct srfunction
+{
+ cgraph_node *node;
+ auto_vec<srdecl *> args;
+ auto_vec<srdecl *> globals;
+ auto_vec_del<srdecl> decls;
+ srdecl *record_decl (srtype *, tree, int arg);
+
+ srfunction *old;
+ cgraph_node *newnode;
+ srfunction *newf;
+
+ // Constructors
+ srfunction (cgraph_node *n);
+
+ // Methods
+ void add_arg (srdecl *arg);
+ void dump (FILE *file);
+ void simple_dump (FILE *file);
+
+ bool check_args (void);
+ void create_new_decls (void);
+ srdecl *find_decl (tree);
+};
+
+struct srglobal : private srfunction
+{
+ srglobal ()
+ : srfunction (NULL)
+ {}
+
+ using srfunction::dump;
+ using srfunction::create_new_decls;
+ using srfunction::find_decl;
+ using srfunction::record_decl;
+ using srfunction::decls;
+};
+
+struct srtype
+{
+ tree type;
+ auto_vec_del<srfield> fields;
+
+ // array of fields that use this type.
+ auto_vec<srfield *> field_sites;
+
+ // array of functions which use directly the type
+ auto_vec<srfunction *> functions;
+
+ auto_vec_del<sraccess> accesses;
+ bool chain_type;
+
+private:
+ escape_type escapes;
+
+public:
+ tree newtype[max_split];
+ bool visited;
+
+ // Constructors
+ srtype (tree type);
+
+ // Methods
+ void dump (FILE *file);
+ void simple_dump (FILE *file);
+ void add_function (srfunction *);
+ void add_access (sraccess *a)
+ {
+ accesses.safe_push (a);
+ }
+ void add_field_site (srfield *);
+
+ srfield *find_field (unsigned HOST_WIDE_INT offset);
+
+ bool create_new_type (void);
+ void analyze (void);
+ void mark_escape (escape_type, gimple *stmt);
+ bool has_escaped (void)
+ {
+ return escapes != does_not_escape;
+ }
+ const char *escape_reason (void)
+ {
+ if (!has_escaped ())
+ return NULL;
+ return escape_type_string[escapes - 1];
+ }
+ bool escaped_rescusive (void)
+ {
+ return escapes == escape_rescusive_type;
+ }
+ bool has_new_type (void)
+ {
+ return newtype[0] && newtype[0] != type;
+ }
+};
+
+struct srfield
+{
+ unsigned HOST_WIDE_INT offset;
+ tree fieldtype;
+ tree fielddecl;
+ srtype *base;
+ srtype *type;
+
+ unsigned clusternum;
+
+ tree newfield[max_split];
+
+ // Constructors
+ srfield (tree field, srtype *base);
+
+ // Methods
+ void dump (FILE *file);
+ void simple_dump (FILE *file);
+
+ void create_new_fields (tree newtype[max_split],
+ tree newfields[max_split],
+ tree newlast[max_split]);
+};
+
+struct sraccess
+{
+ gimple *stmt;
+ cgraph_node *node;
+
+ srtype *type;
+ // NULL field means the whole type is accessed
+ srfield *field;
+
+ // Constructors
+ sraccess (gimple *s, cgraph_node *n, srtype *t, srfield *f = NULL)
+ : stmt (s),
+ node (n),
+ type (t),
+ field (f)
+ {}
+
+ // Methods
+ void dump (FILE *file);
+};
+
+struct srdecl
+{
+ srtype *type;
+ tree decl;
+ tree func;
+ /* -1 : not an argument
+ -2 : static chain
+ */
+ int argumentnum;
+
+ bool visited;
+
+ tree newdecl[max_split];
+
+ // Constructors
+ srdecl (srtype *type, tree decl, int argumentnum = -1);
+
+ // Methods
+ void dump (FILE *file);
+ bool has_new_decl (void)
+ {
+ return newdecl[0] && newdecl[0] != decl;
+ }
+};
+
+
+} // namespace struct_reorg
+
+#endif
diff --git a/gcc/params.opt b/gcc/params.opt
index e0ff9e210..1ddf1343f 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -865,6 +865,10 @@ Enum(parloops_schedule_type) String(runtime) Value(PARLOOPS_SCHEDULE_RUNTIME)
Common Joined UInteger Var(param_partial_inlining_entry_probability) Init(70) Optimization IntegerRange(0, 100) Param
Maximum probability of the entry BB of split region (in percent relative to entry BB of the function) to make partial inlining happen.
+-param=struct-reorg-cold-struct-ratio=
+Common Joined UInteger Var(param_struct_reorg_cold_struct_ratio) Init(10) IntegerRange(0, 100) Param Optimization
+The threshold ratio between current and hottest structure counts.
+
-param=predictable-branch-outcome=
Common Joined UInteger Var(param_predictable_branch_outcome) Init(2) IntegerRange(0, 50) Param Optimization
Maximal estimated outcome of branch considered predictable.
diff --git a/gcc/passes.def b/gcc/passes.def
index 375d3d62d..1c1658c4a 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -177,6 +177,8 @@ along with GCC; see the file COPYING3. If not see
compiled unit. */
INSERT_PASSES_AFTER (all_late_ipa_passes)
NEXT_PASS (pass_ipa_pta);
+ /* FIXME: this should be a normal IP pass. */
+ NEXT_PASS (pass_ipa_struct_reorg);
NEXT_PASS (pass_omp_simd_clone);
TERMINATE_PASS_LIST (all_late_ipa_passes)
diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
new file mode 100644
index 000000000..43913104e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
@@ -0,0 +1,35 @@
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+load_lib torture-options.exp
+
+# Initialize `dg'.
+dg-init
+torture-init
+
+set STRUCT_REORG_TORTURE_OPTIONS [list \
+ { -O3 } \
+ { -Ofast } ]
+
+set-torture-options $STRUCT_REORG_TORTURE_OPTIONS {{}}
+
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+
+# All done.
+torture-finish
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
new file mode 100644
index 000000000..6565fe8dd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" }
+
+struct a
+{
+ int t, t1;
+};
+
+static struct a *b;
+
+void *xmalloc(int);
+
+
+void f(void)
+{
+ b = xmalloc (sizeof(*b));
+}
+
+int g(void)
+{
+ return b->t;
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c
new file mode 100644
index 000000000..44babd35b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c
@@ -0,0 +1,29 @@
+// { dg-do run }
+
+#include <assert.h>
+
+struct a
+{
+ int t;
+ int t1;
+};
+
+__attribute__((noinline)) int f(int i, int j)
+{
+ struct a *t;
+ struct a t1 = {i, j};
+ t = &t1;
+ auto int g(void) __attribute__((noinline));
+ int g(void)
+ {
+ return t->t + t->t1;
+ }
+ return g();
+}
+
+int main()
+{
+ assert (f(1, 2) == 3);
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
new file mode 100644
index 000000000..5864ad46f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" }
+
+#include <stdlib.h>
+typedef struct {
+ long laststart_offset;
+ unsigned regnum;
+} compile_stack_elt_t;
+typedef struct {
+ compile_stack_elt_t *stack;
+ unsigned size;
+} compile_stack_type;
+void f (const char *p, const char *pend, int c)
+{
+ compile_stack_type compile_stack;
+ while (p != pend)
+ if (c)
+ compile_stack.stack = realloc (compile_stack.stack,
+ (compile_stack.size << 1)
+ * sizeof (compile_stack_elt_t));
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c
new file mode 100644
index 000000000..e5a8a6c84
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+struct S
+{
+ int b;
+ int *c;
+};
+static int d, e;
+
+static struct S s;
+
+static int *
+__attribute__((noinline, const))
+foo (void)
+{
+ return &s.b;
+}
+
+int *
+__attribute__((noinline))
+bar (int **f)
+{
+ s.c = &d;
+ *f = &e;
+ /* As nothing ever takes the address of any int * field in struct S,
+ the write to *f can't alias with the s.c field. */
+ return s.c;
+}
+
+int
+__attribute__((noinline))
+baz (int *x)
+{
+ s.b = 1;
+ *x = 4;
+ /* Function foo takes address of an int field in struct S,
+ so *x can alias with the s.b field (and it does in this testcase). */
+ return s.b;
+}
+
+int
+__attribute__((noinline))
+t (void)
+{
+ int *f = (int *) 0;
+ return 10 * (bar (&f) != &d) + baz (foo ());
+}
+
+int
+main (void)
+{
+ if (t () != 4)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c
new file mode 100644
index 000000000..733413a94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#define N 1000
+str_t A[N];
+
+int
+main ()
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ {
+ A[i].a = 0;
+ }
+
+ for (i = 0; i < N; i++)
+ if (A[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c
new file mode 100644
index 000000000..0ef686e74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+str_t *p;
+
+int
+main ()
+{
+ int i, sum;
+
+ p = malloc (N * sizeof (str_t));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ p[i].b = i;
+
+ for (i = 0; i < N; i++)
+ p[i].a = p[i].b + 1;
+
+ for (i = 0; i < N; i++)
+ if (p[i].a != p[i].b + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c
new file mode 100644
index 000000000..23a53be53
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i;
+ str_t A[N];
+
+ for (i = 0; i < N; i++)
+ {
+ A[i].a = 0;
+ }
+
+ for (i = 0; i < N; i++)
+ if (A[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c
new file mode 100644
index 000000000..0cbb172f2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i, sum;
+
+ str_t * p = malloc (N * sizeof (str_t));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ p[i].b = i;
+
+ for (i = 0; i < N; i++)
+ p[i].a = p[i].b + 1;
+
+ for (i = 0; i < N; i++)
+ if (p[i].a != p[i].b + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c
new file mode 100644
index 000000000..f900b1349
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int b;
+}str_t;
+
+#define N 3
+
+str_t str;
+
+int
+main ()
+{
+ int i;
+ int res = 1<<(1<<N);
+ str.a = 2;
+
+ for (i = 0; i < N; i++)
+ str.a = str.a * str.a;
+
+ if (str.a != res)
+ abort ();
+
+ /* POSIX ignores all but the 8 low-order bits, but other
+ environments may not. */
+ return (str.a & 255);
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c
new file mode 100644
index 000000000..13b4cdc70
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+
+typedef struct
+{
+ int a;
+ float b;
+}str_t1;
+
+typedef struct
+{
+ int c;
+ float d;
+}str_t2;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 16000
+#define N 1000
+#else
+#define N (STACK_SIZE/16)
+#endif
+#else
+#define N 1000
+#endif
+
+str_t1 *p1;
+str_t2 *p2;
+int num;
+
+void
+foo (void)
+{
+ int i;
+
+ for (i=0; i < num; i++)
+ p2[i].c = 2;
+}
+
+int
+main ()
+{
+ int i, r;
+
+ r = rand ();
+ num = r > N ? N : r;
+ p1 = malloc (num * sizeof (str_t1));
+ p2 = malloc (num * sizeof (str_t2));
+
+ if (p1 == NULL || p2 == NULL)
+ return 0;
+
+ for (i = 0; i < num; i++)
+ p1[i].a = 1;
+
+ foo ();
+
+ for (i = 0; i < num; i++)
+ if (p1[i].a != 1 || p2[i].c != 2)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c
new file mode 100644
index 000000000..dcc545964
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int b;
+}str_t1;
+
+typedef struct
+{
+ float a;
+ float b;
+}str_t2;
+
+#define N1 1000
+#define N2 100
+str_t1 A1[N1];
+str_t2 A2[N2];
+
+int
+main ()
+{
+ int i;
+
+ for (i = 0; i < N1; i++)
+ A1[i].a = 0;
+
+ for (i = 0; i < N2; i++)
+ A2[i].a = 0;
+
+ for (i = 0; i < N1; i++)
+ if (A1[i].a != 0)
+ abort ();
+
+ for (i = 0; i < N2; i++)
+ if (A2[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Arrays are not handled. */
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c
new file mode 100644
index 000000000..6d6375fc1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct basic
+{
+ int a;
+ int b[10];
+} type_struct;
+
+type_struct *str1;
+
+int main()
+{
+ int i;
+
+ str1 = malloc (10 * sizeof (type_struct));
+
+ for (i=0; i<=9; i++)
+ str1[i].a = str1[i].b[0];
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c
new file mode 100644
index 000000000..9d3213408
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i;
+ str_t A[N];
+ str_t *p = A;
+
+ for (i = 0; i < N; i++)
+ p[i].a = 0;
+
+ for (i = 0; i < N; i++)
+ if (p[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c
new file mode 100644
index 000000000..d79992a53
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+
+typedef struct test_struct
+{
+ int a;
+ int b;
+} type_struct;
+
+typedef type_struct **struct_pointer2;
+
+struct_pointer2 str1;
+
+int main()
+{
+ int i, j;
+
+ str1 = malloc (2 * sizeof (type_struct *));
+
+ for (i = 0; i <= 1; i++)
+ str1[i] = malloc (2 * sizeof (type_struct));
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c
new file mode 100644
index 000000000..ee9b0d765
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+
+struct S { int a; struct V *b; };
+typedef struct { int c; } T;
+typedef struct { int d; int e; } U;
+
+void *
+fn (void *x)
+{
+ return x;
+}
+
+int
+foo (struct S *s)
+{
+ T x;
+
+ T y = *(T *)fn (&x);
+ return y.c;
+}
+
+int
+bar (struct S *s)
+{
+ U x;
+
+ U y = *(U *)fn (&x);
+ return y.d + s->a;
+}
+
+int
+main ()
+{
+ struct S s;
+
+ foo(&s) + bar (&s);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c
new file mode 100644
index 000000000..9ebb2b4cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+struct str
+{
+ int a;
+ float b;
+};
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+foo (struct str * p_str)
+{
+ static int sum = 0;
+
+ sum = sum + p_str->a;
+ return sum;
+}
+
+int
+main ()
+{
+ int i, sum;
+ struct str * p = malloc (N * sizeof (struct str));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ sum = foo (p+i);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
+
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c
new file mode 100644
index 000000000..d0dce8b53
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fno-ipa-sra" } */
+
+#include <stdlib.h>
+
+struct A {
+ int d;
+ int d1;
+};
+
+struct A a;
+
+struct A *foo () __attribute__((noinline));
+struct A *foo ()
+{
+ a.d = 5;
+ return &a;
+}
+
+int
+main ()
+{
+ a.d = 0;
+ foo ();
+
+ if (a.d != 5)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "has escaped. .Type escapes via a return" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c
new file mode 100644
index 000000000..71167182d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fno-ipa-sra" } */
+
+#include <stdlib.h>
+
+struct A {
+ int d;
+};
+
+struct A a;
+
+struct A foo () __attribute__((noinline));
+struct A foo ()
+{
+ a.d = 5;
+ return a;
+}
+
+int
+main ()
+{
+ a.d = 0;
+ foo ();
+
+ if (a.d != 5)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "has escaped: \"Type escapes via a return" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c
new file mode 100644
index 000000000..74fa11f39
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int b;
+}str_t;
+
+#define N 2
+
+str_t A[2] = {{1,1},{2,2}};
+
+int
+main ()
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ A[i].b = A[i].a;
+
+ for (i = 0; i < N; i++)
+ if (A[i].b != A[i].a)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c
new file mode 100644
index 000000000..60d2466e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#define N 1000
+
+typedef struct
+{
+ str_t A[N];
+ int c;
+}str_with_substr_t;
+
+str_with_substr_t a;
+
+int
+main ()
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a.A[i].b = 0;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c
new file mode 100644
index 000000000..baf617816
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 16000
+#define N 1000
+#else
+#define N (STACK_SIZE/16)
+#endif
+#else
+#define N 1000
+#endif
+
+typedef struct
+{
+ str_t * sub_str;
+ int c;
+}str_with_substr_t;
+
+int foo;
+
+int
+main (void)
+{
+ int i;
+ str_with_substr_t A[N];
+ str_t a[N];
+
+ for (i=0; i < N; i++)
+ A[i].sub_str = &(a[i]);
+
+ for (i=0; i < N; i++)
+ A[i].sub_str->a = 5;
+
+ foo = A[56].sub_str->a;
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "has escaped...Type is used in an array" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c
new file mode 100644
index 000000000..33fce3b23
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+
+typedef struct
+{
+ str_t sub_str;
+ int c;
+}str_with_substr_t;
+
+int
+main ()
+{
+ int i;
+ str_with_substr_t A[N];
+
+ for (i = 0; i < N; i++)
+ A[i].sub_str.a = 5;
+
+ for (i = 0; i < N; i++)
+ if (A[i].sub_str.a != 5)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "has escaped...Type is used in an array" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c
new file mode 100644
index 000000000..1c5a3aa15
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#define N 1000
+str_t A[N];
+
+int
+main ()
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ {
+ A[i].a = 0;
+ }
+
+ for (i = 0; i < N; i++)
+ if (A[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c
new file mode 100644
index 000000000..a0d1467fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+str_t *p;
+
+int
+main ()
+{
+ int i, sum;
+
+ p = malloc (N * sizeof (str_t));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ p[i].b = i;
+
+ for (i = 0; i < N; i++)
+ p[i].b = p[i].a + 1;
+
+ for (i = 0; i < N; i++)
+ if (p[i].b != p[i].a + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c
new file mode 100644
index 000000000..6c24e1c8b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i;
+ str_t A[N];
+
+ for (i = 0; i < N; i++)
+ {
+ A[i].a = 0;
+ }
+
+ for (i = 0; i < N; i++)
+ if (A[i].a != 0)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c
new file mode 100644
index 000000000..8f2f8143f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i, sum;
+
+ str_t * p = malloc (N * sizeof (str_t));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ p[i].b = i;
+
+ for (i = 0; i < N; i++)
+ p[i].b = p[i].a + 1;
+
+ for (i = 0; i < N; i++)
+ if (p[i].b != p[i].a + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c
new file mode 100644
index 000000000..98bf01a6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ long i, num;
+
+ num = rand();
+ num = num > N ? N : num;
+ str_t * p = malloc (num * sizeof (str_t));
+
+ if (p == 0)
+ return 0;
+
+ for (i = 1; i <= num; i++)
+ p[i-1].b = i;
+
+ for (i = 1; i <= num; i++)
+ p[i-1].a = p[i-1].b + 1;
+
+ for (i = 0; i < num; i++)
+ if (p[i].a != p[i].b + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c
new file mode 100644
index 000000000..66b0f967c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 8000
+#define N 1000
+#else
+#define N (STACK_SIZE/8)
+#endif
+#else
+#define N 1000
+#endif
+
+int
+main ()
+{
+ int i, num;
+
+ num = rand();
+ num = num > N ? N : num;
+ str_t * p = malloc (num * sizeof (str_t));
+
+ if (p == 0)
+ return 0;
+
+ for (i = 0; i < num; i++)
+ p[i].b = i;
+
+ for (i = 0; i < num; i++)
+ p[i].a = p[i].b + 1;
+
+ for (i = 0; i < num; i++)
+ if (p[i].a != p[i].b + 1)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c
new file mode 100644
index 000000000..d28bcfb02
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ float b;
+ int c;
+ float d;
+}str_t;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 1600
+#define N 100
+#else
+#define N (STACK_SIZE/16)
+#endif
+#else
+#define N 100
+#endif
+
+int
+main ()
+{
+ int i;
+ str_t *p = malloc (N * sizeof (str_t));
+ if (p == NULL)
+ return 0;
+ for (i = 0; i < N; i++)
+ p[i].a = 5;
+
+ for (i = 0; i < N; i++)
+ if (p[i].a != 5)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Two more fields structure is not splitted. */
+/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c
new file mode 100644
index 000000000..37a6a43a8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int b;
+}str_t;
+
+#define N 3
+
+str_t str;
+
+int
+main ()
+{
+ int i;
+ int res = 1<<(1<<N);
+ str.a = 2;
+
+ for (i = 0; i < N; i++)
+ str.a = str.a * str.a;
+
+ if (str.a != res)
+ abort ();
+
+ /* POSIX ignores all but the 8 low-order bits, but other
+ environments may not. */
+ return (str.a & 255);
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c
new file mode 100644
index 000000000..ca9a8efcf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int b;
+}str_t;
+
+#define N 3
+
+int
+main ()
+{
+ int i;
+ int res = 1<<(1<<N);
+ str_t str;
+
+ str.a = 2;
+
+ for (i = 0; i < N; i++)
+ str.a = str.a * str.a;
+
+ if (str.a != res)
+ abort ();
+
+ /* POSIX ignores all but the 8 low-order bits, but other
+ environments may not. */
+ return (str.a & 255);
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c
new file mode 100644
index 000000000..baa95bddf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+typedef struct
+{
+ int a;
+ int *b;
+}str_t;
+
+#define N 3
+
+str_t *p;
+
+int
+main ()
+{
+ str_t str;
+ int i;
+ int res = 1 << (1 << N);
+ p = &str;
+ str.a = 2;
+
+ p->b = &(p->a);
+
+ for (i=0; i < N; i++)
+ p->a = *(p->b)*(*(p->b));
+
+ if (p->a != res)
+ abort ();
+
+ /* POSIX ignores all but the 8 low-order bits, but other
+ environments may not. */
+ return (p->a & 255);
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "has escaped...Type escapes a cast to a different" "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c
new file mode 100644
index 000000000..cba92e995
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-do run } */
+
+#include <stdlib.h>
+
+typedef struct
+{
+ int a;
+ float b;
+}str_t1;
+
+typedef struct
+{
+ int c;
+ float d;
+}str_t2;
+
+#ifdef STACK_SIZE
+#if STACK_SIZE > 16000
+#define N 1000
+#else
+#define N (STACK_SIZE/16)
+#endif
+#else
+#define N 1000
+#endif
+
+str_t1 *p1;
+str_t2 *p2;
+int num;
+
+void
+foo (void)
+{
+ int i;
+
+ for (i=0; i < num; i++)
+ p2[i].c = 2;
+}
+
+int
+main ()
+{
+ int i, r;
+
+ r = rand ();
+ num = r > N ? N : r;
+ p1 = malloc (num * sizeof (str_t1));
+ p2 = malloc (num * sizeof (str_t2));
+
+ if (p1 == NULL || p2 == NULL)
+ return 0;
+
+ for (i = 0; i < num; i++)
+ p1[i].a = 1;
+
+ foo ();
+
+ for (i = 0; i < num; i++)
+ if (p1[i].a != 1 || p2[i].c != 2)
+ abort ();
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 2dae5e1c7..366118126 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -80,6 +80,7 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp")
DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics")
DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting")
DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats")
+DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization")
DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations")
DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression")
DEFTIMEVAR (TV_IPA_LTO_COMPRESS , "lto stream compression")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 606d1d60b..ec7be874c 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -526,6 +526,7 @@ extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt);
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化