加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0021-StructReorderFields-Structure-reorder-fields.patch 163.95 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739
From 6997c9ad8985f6f0bfc16cdb46e7386af299a226 Mon Sep 17 00:00:00 2001
From: h00564365 <huangxiaoquan1@huawei.com>
Date: Mon, 31 Jul 2023 22:01:56 +0800
Subject: [PATCH 21/22] [StructReorderFields] Structure reorder fields
Introduce structure fields reordering optimization, that change
fields ordering of C-like structures in order to better utilize spatial
locality.
---
gcc/common.opt | 4 +
gcc/doc/invoke.texi | 1 +
gcc/gimple-ssa-warn-access.cc | 2 +-
gcc/ipa-free-lang-data.cc | 4 +-
gcc/ipa-struct-reorg/escapes.def | 3 +
gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 2545 +++++++++++++----
gcc/ipa-struct-reorg/ipa-struct-reorg.h | 14 +-
gcc/passes.def | 1 +
gcc/symbol-summary.h | 4 +-
.../struct/rf_DTE_struct_instance_field.c | 75 +
gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c | 94 +
.../gcc.dg/struct/rf_check_ptr_layers_bug.c | 24 +
.../gcc.dg/struct/rf_create_fields_bug.c | 82 +
.../gcc.dg/struct/rf_create_new_func_bug.c | 56 +
.../gcc.dg/struct/rf_ele_minus_verify.c | 60 +
.../gcc.dg/struct/rf_escape_by_base.c | 83 +
.../gcc.dg/struct/rf_external_func_types.c | 69 +
gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c | 72 +
.../gcc.dg/struct/rf_mem_ref_offset.c | 58 +
.../struct/rf_mul_layer_ptr_record_bug.c | 30 +
.../gcc.dg/struct/rf_pass_conflict.c | 109 +
gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c | 87 +
gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c | 71 +
.../gcc.dg/struct/rf_ptr_negate_expr.c | 55 +
gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c | 34 +
gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c | 55 +
gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c | 58 +
.../gcc.dg/struct/rf_rescusive_type.c | 57 +
.../struct/rf_rewrite_assign_more_cmp.c | 65 +
.../gcc.dg/struct/rf_rewrite_cond_bug.c | 72 +
.../gcc.dg/struct/rf_rewrite_cond_more_cmp.c | 58 +
.../gcc.dg/struct/rf_rewrite_phi_bug.c | 81 +
gcc/testsuite/gcc.dg/struct/rf_shwi.c | 23 +
gcc/testsuite/gcc.dg/struct/rf_visible_func.c | 92 +
.../gcc.dg/struct/rf_void_ptr_param_func.c | 54 +
gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 15 +-
gcc/testsuite/gcc.dg/struct/struct_reorg-1.c | 8 +-
gcc/testsuite/gcc.dg/struct/struct_reorg-3.c | 9 +-
gcc/timevar.def | 1 +
gcc/tree-pass.h | 1 +
40 files changed, 3796 insertions(+), 490 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_external_func_types.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_shwi.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_visible_func.c
create mode 100644 gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c
diff --git a/gcc/common.opt b/gcc/common.opt
index 0c7bd2f6c..98169de7c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1954,6 +1954,10 @@ fipa-matrix-reorg
Common Ignore
Does nothing. Preserved for backward compatibility.
+fipa-reorder-fields
+Common Var(flag_ipa_reorder_fields) Init(0) Optimization
+Perform structure fields reorder optimizations.
+
fipa-struct-reorg
Common Var(flag_ipa_struct_reorg) Init(0) Optimization
Perform structure layout optimizations.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3485cc8af..2b376e0e9 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-reorder-fields @gol
-fipa-struct-reorg @gol
-fipa-reference -fipa-reference-addressable @gol
-fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} @gol
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index a24645783..7f5c92c96 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2198,7 +2198,7 @@ pass_waccess::gate (function *)
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)
+ if (flag_ipa_struct_reorg || flag_ipa_reorder_fields)
return false;
return (warn_free_nonheap_object
diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc
index 5450be9fe..a88381ddb 100644
--- a/gcc/ipa-free-lang-data.cc
+++ b/gcc/ipa-free-lang-data.cc
@@ -105,7 +105,7 @@ fld_simplified_type_name (tree type)
/* Simplify type will cause that struct A and struct A within
struct B are different type pointers, so skip it in structure
optimizations. */
- if (flag_ipa_struct_reorg)
+ if (flag_ipa_struct_reorg || flag_ipa_reorder_fields)
return TYPE_NAME (type);
if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL)
@@ -349,7 +349,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld)
/* Simplify type will cause that struct A and struct A within
struct B are different type pointers, so skip it in structure
optimizations. */
- if (flag_ipa_struct_reorg)
+ if (flag_ipa_struct_reorg || flag_ipa_reorder_fields)
return t;
if (POINTER_TYPE_P (t))
return fld_incomplete_type_of (t, fld);
diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def
index d825eb3e6..996a09bac 100644
--- a/gcc/ipa-struct-reorg/escapes.def
+++ b/gcc/ipa-struct-reorg/escapes.def
@@ -58,5 +58,8 @@ DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled
DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]")
DEF_ESCAPE (escape_separate_instance, "Type escapes via a separate instance")
DEF_ESCAPE (escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt")
+DEF_ESCAPE (escape_via_orig_escape, "Type escapes via a original escape type")
+DEF_ESCAPE (escape_instance_field, "Type escapes via a field of instance")
+DEF_ESCAPE (escape_via_empty_no_orig, "Type escapes via empty and no original")
#undef DEF_ESCAPE
diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
index 9f790b28b..3e5f9538b 100644
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
@@ -207,50 +207,88 @@ lang_c_p (void)
if (!language_string)
return false;
- if (strcmp (language_string, "GNU GIMPLE") == 0)
+ if (lang_GNU_C ())
+ return true;
+ else if (strcmp (language_string, "GNU GIMPLE") == 0) // For LTO check
{
unsigned i = 0;
- tree t = NULL;
- const char *unit_string = NULL;
+ tree t = NULL_TREE;
FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t)
{
- unit_string = TRANSLATION_UNIT_LANGUAGE (t);
- if (!unit_string
- || (strncmp (unit_string, "GNU C", 5) != 0)
- || (!ISDIGIT (unit_string[5])))
+ language_string = TRANSLATION_UNIT_LANGUAGE (t);
+ if (language_string == NULL
+ || strncmp (language_string, "GNU C", 5)
+ || (language_string[5] != '\0'
+ && !(ISDIGIT (language_string[5]))))
return false;
}
return true;
}
- else if (strncmp (language_string, "GNU C", 5) == 0
- && ISDIGIT (language_string[5]))
- return true;
-
return false;
}
+/* Get the number of pointer layers. */
+
+int
+get_ptr_layers (tree expr)
+{
+ int layers = 0;
+ while (POINTER_TYPE_P (expr) || TREE_CODE (expr) == ARRAY_TYPE)
+ {
+ layers++;
+ expr = TREE_TYPE (expr);
+ }
+ return layers;
+}
+
+/* Comparison pointer layers. */
+
+bool
+cmp_ptr_layers (tree a, tree b)
+{
+ return get_ptr_layers (a) == get_ptr_layers (b);
+}
+
+/* Return true if the ssa_name comes from the void* parameter. */
+
+bool
+is_from_void_ptr_parm (tree ssa_name)
+{
+ gcc_assert (TREE_CODE (ssa_name) == SSA_NAME);
+ tree var = SSA_NAME_VAR (ssa_name);
+ return (var && TREE_CODE (var) == PARM_DECL
+ && VOID_POINTER_P (TREE_TYPE (ssa_name)));
+}
+
enum srmode
{
NORMAL = 0,
- COMPLETE_STRUCT_RELAYOUT
+ COMPLETE_STRUCT_RELAYOUT,
+ STRUCT_REORDER_FIELDS
};
-static bool is_result_of_mult (tree, tree *, tree);
+static bool is_result_of_mult (tree arg, tree *num, tree struct_size);
+static bool isptrptr (tree type);
-} // anon namespace
+srmode current_mode;
+} // anon namespace
namespace struct_reorg {
+hash_map <tree, auto_vec <tree>> fields_to_finish;
+
/* Constructor of srfunction. */
srfunction::srfunction (cgraph_node *n)
: node (n),
old (NULL),
newnode (NULL),
- newf (NULL)
-{}
+ newf (NULL),
+ is_safe_func (false)
+{
+}
/* Add an ARG to the list of arguments for the function. */
@@ -400,12 +438,13 @@ srtype::add_field_site (srfield *field)
/* Constructor of DECL. */
-srdecl::srdecl (srtype *tp, tree decl, int argnum)
+srdecl::srdecl (srtype *tp, tree decl, int argnum, tree orig_type)
: type (tp),
decl (decl),
func (NULL_TREE),
argumentnum (argnum),
- visited (false)
+ visited (false),
+ orig_type (orig_type)
{
if (TREE_CODE (decl) == SSA_NAME)
func = current_function_decl;
@@ -429,17 +468,23 @@ srfunction::find_decl (tree decl)
/* Record DECL of the TYPE with argument num ARG. */
srdecl *
-srfunction::record_decl (srtype *type, tree decl, int arg)
+srfunction::record_decl (srtype *type, tree decl, int arg, tree orig_type)
{
// Search for the decl to see if it is already there.
srdecl *decl1 = find_decl (decl);
if (decl1)
- return decl1;
+ {
+ /* Added the orig_type information. */
+ if (!decl1->orig_type && orig_type && isptrptr (orig_type))
+ decl1->orig_type = orig_type;
+ return decl1;
+ }
gcc_assert (type);
- decl1 = new srdecl (type, decl, arg);
+ orig_type = isptrptr (TREE_TYPE (decl)) ? TREE_TYPE (decl) : orig_type;
+ decl1 = new srdecl (type, decl, arg, isptrptr (orig_type) ? orig_type : NULL);
decls.safe_push (decl1);
return decl1;
}
@@ -503,31 +548,21 @@ srtype::dump (FILE *f)
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 = { ");
+ fprintf (f, "escapes = \"%s\"", escape_reason ());
+ fprintf (f, "\nfields = {\n");
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 = {");
+ field->dump (f);
+ fprintf (f, "}\n ");
+
+ fprintf (f, "\naccesses = {\n");
FOR_EACH_VEC_ELT (accesses, i, access)
- {
- fprintf (f, "\n");
- access->dump (f);
- }
- fprintf (f, " }\n ");
- fprintf (f, "\n functions = {");
+ access->dump (f);
+ fprintf (f, "}\n ");
+
+ fprintf (f, "\nfunctions = {\n");
FOR_EACH_VEC_ELT (functions, i, fn)
- {
- fprintf (f, " \n");
- fn->simple_dump (f);
- }
- fprintf (f, "\n }\n");
+ fn->simple_dump (f);
+ fprintf (f, "}\n");
fprintf (f, "}\n");
}
@@ -537,6 +572,8 @@ void
srtype::simple_dump (FILE *f)
{
print_generic_expr (f, type);
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ fprintf (f, "(%d)", TYPE_UID (type));
}
/* Analyze the type and decide what to be done with it. */
@@ -572,6 +609,12 @@ srfield::create_new_fields (tree newtype[max_split],
tree newfields[max_split],
tree newlast[max_split])
{
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ create_new_reorder_fields (newtype, newfields, newlast);
+ return;
+ }
+
tree nt[max_split];
for (unsigned i = 0; i < max_split; i++)
@@ -620,6 +663,104 @@ srfield::create_new_fields (tree newtype[max_split],
}
}
+/* Reorder fields. */
+
+void
+srfield::reorder_fields (tree newfields[max_split], tree newlast[max_split],
+ tree &field)
+{
+ /* Reorder fields in descending.
+ newfields: always stores the first member of the chain
+ and with the largest size.
+ field: indicates the node to be inserted. */
+ if (newfields[clusternum] == NULL)
+ {
+ newfields[clusternum] = field;
+ newlast[clusternum] = field;
+ }
+ else
+ {
+ tree tmp = newfields[clusternum];
+ if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field)))
+ > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (tmp))))
+ {
+ DECL_CHAIN (field) = tmp;
+ newfields[clusternum] = field;
+ }
+ else
+ {
+ while (DECL_CHAIN (tmp)
+ && (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field)))
+ <= tree_to_uhwi (
+ TYPE_SIZE (TREE_TYPE (DECL_CHAIN (tmp))))))
+ tmp = DECL_CHAIN (tmp);
+
+ /* Now tmp size > field size
+ insert field: tmp -> xx ==> tmp -> field -> xx. */
+ DECL_CHAIN (field) = DECL_CHAIN (tmp); // field -> xx
+ DECL_CHAIN (tmp) = field; // tmp -> field
+ }
+ }
+}
+
+/* Create the new reorder fields for this field.
+ newtype[max_split]: srtype's member variable,
+ newfields[max_split]: created by create_new_type func,
+ newlast[max_split]: created by create_new_type func. */
+
+void
+srfield::create_new_reorder_fields (tree newtype[max_split],
+ tree newfields[max_split],
+ tree newlast[max_split])
+{
+ /* newtype, corresponding to newtype[max_split] in srtype. */
+ tree nt = NULL_TREE;
+ if (type == NULL)
+ /* Common var. */
+ nt = fieldtype;
+ else
+ {
+ /* RECORD_TYPE var. */
+ if (type->has_escaped ())
+ nt = type->type;
+ else
+ nt = type->newtype[0];
+ }
+ tree field = make_node (FIELD_DECL);
+
+ /* Used for recursive types.
+ fields_to_finish: hase_map in the format of "type: {fieldA, fieldB}",
+ key : indicates the original type,
+ vaule: filed that need to be updated to newtype. */
+ if (nt == NULL)
+ {
+ nt = make_node (RECORD_TYPE);
+ auto_vec <tree> &fields
+ = fields_to_finish.get_or_insert (inner_type (type->type));
+ fields.safe_push (field);
+ }
+
+ DECL_NAME (field) = DECL_NAME (fielddecl);
+ if (type == NULL)
+ /* Common members do not need to reconstruct.
+ Otherwise, int* -> int** or void* -> void**. */
+ TREE_TYPE (field) = nt;
+ else
+ TREE_TYPE (field) = reconstruct_complex_type (TREE_TYPE (fielddecl), nt);
+ 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];
+
+ reorder_fields (newfields, newlast, field);
+
+ /* srfield member variable, which stores the new field decl. */
+ newfield[0] = field;
+}
+
/* Create the new TYPE corresponding to THIS type. */
bool
@@ -655,7 +796,8 @@ srtype::create_new_type (void)
/* 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)
+ if (!createnewtype && maxclusters == 0
+ && current_mode != STRUCT_REORDER_FIELDS)
{
newtype[0] = type;
return false;
@@ -664,6 +806,7 @@ srtype::create_new_type (void)
/* Should have at most max_split clusters. */
gcc_assert (maxclusters < max_split);
+ /* Record the first member of the field chain. */
tree newfields[max_split];
tree newlast[max_split];
@@ -682,7 +825,8 @@ srtype::create_new_type (void)
sprintf (id, "%d", i);
if (tname)
{
- name = concat (tname, ".reorg.", id, NULL);
+ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS
+ ? ".reorder." : ".reorg.", id, NULL);
TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION,
TYPE_DECL,
get_identifier (name),
@@ -718,6 +862,7 @@ srtype::create_new_type (void)
for (unsigned i = 0; i < maxclusters; i++)
{
print_generic_expr (dump_file, newtype[i]);
+ fprintf (dump_file, "(%d)", TYPE_UID (newtype[i]));
fprintf (dump_file, "\n");
}
}
@@ -776,8 +921,12 @@ srfunction::create_new_decls (void)
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]);
+ {
+ newtype1[j] = reconstruct_complex_type (
+ isptrptr (decls[i]->orig_type) ? decls[i]->orig_type
+ : TREE_TYPE (decls[i]->decl),
+ type->newtype[j]);
+ }
if (inner)
{
srdecl *in = find_decl (inner);
@@ -825,7 +974,8 @@ srfunction::create_new_decls (void)
sprintf (id, "%d", j);
if (tname)
{
- name = concat (tname, ".reorg.", id, NULL);
+ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS
+ ? ".reorder." : ".reorg.", id, NULL);
new_name = get_identifier (name);
free (name);
}
@@ -850,7 +1000,6 @@ srfunction::create_new_decls (void)
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++)
@@ -876,7 +1025,7 @@ srfield::dump (FILE *f)
fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset);
fprintf (f, ", type = ");
print_generic_expr (f, fieldtype);
- fprintf (f, "\n}\n");
+ fprintf (f, "}\n");
}
/* A simplified dump out the field structure to FILE. */
@@ -908,7 +1057,7 @@ sraccess::dump (FILE *f)
fprintf (f, " in function: %s/%d", node->name (), node->order);
fprintf (f, ", stmt:\n");
print_gimple_stmt (f, stmt, 0);
- fprintf (f, "\n }\n");
+ fprintf (f, "}\n");
}
/* Dump out the decl structure to FILE. */
@@ -1023,8 +1172,7 @@ public:
// Constructors
ipa_struct_reorg (void)
: current_function (NULL),
- done_recording (false),
- current_mode (NORMAL)
+ done_recording (false)
{}
// Fields
@@ -1032,9 +1180,10 @@ public:
auto_vec_del<srfunction> functions;
srglobal globals;
srfunction *current_function;
+ hash_set <cgraph_node *> safe_functions;
+ auto_vec<srtype *> ext_func_types;
bool done_recording;
- srmode current_mode;
// Methods
unsigned execute (enum srmode mode);
@@ -1042,6 +1191,7 @@ public:
gimple *stmt = NULL);
void dump_types (FILE *f);
+ void dump_newtypes (FILE *f);
void dump_types_escaped (FILE *f);
void dump_functions (FILE *f);
void record_accesses (void);
@@ -1049,6 +1199,9 @@ public:
bool walk_field_for_cycles (srtype *);
void prune_escaped_types (void);
void propagate_escape (void);
+ void propagate_escape_via_original (void);
+ void propagate_escape_via_empty_with_no_original (void);
+ void propagate_escape_via_ext_func_types (void);
void analyze_types (void);
void clear_visited (void);
bool create_new_types (void);
@@ -1060,8 +1213,11 @@ public:
srdecl *record_var (tree decl,
escape_type escapes = does_not_escape,
int arg = -1);
+ void record_safe_func_with_void_ptr_parm (void);
srfunction *record_function (cgraph_node *node);
srfunction *find_function (cgraph_node *node);
+ void record_field_type (tree field, srtype *base_srtype);
+ void record_struct_field_types (tree base_type, srtype *base_srtype);
srtype *record_type (tree type);
void process_union (tree type);
srtype *find_type (tree type);
@@ -1072,7 +1228,7 @@ public:
void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt);
void mark_expr_escape (tree, escape_type, gimple *stmt);
bool handled_allocation_stmt (gimple *stmt);
- tree allocate_size (srtype *t, gimple *stmt);
+ tree allocate_size (srtype *t, srdecl *decl, gimple *stmt);
void mark_decls_in_as_not_needed (tree fn);
@@ -1087,21 +1243,23 @@ public:
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 get_type_field (tree expr, tree &base, bool &indirect, srtype *&type,
+ srfield *&field, bool &realpart, bool &imagpart,
+ bool &address, bool &escape_from_base,
+ bool should_create = false, bool can_escape = false);
bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t);
void check_alloc_num (gimple *stmt, srtype *type);
+ void check_definition_assign (srdecl *decl, vec<srdecl *> &worklist);
+ void check_definition_call (srdecl *decl, vec<srdecl *> &worklist);
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,
+ void check_type_and_push (tree newdecl, srdecl *decl,
vec<srdecl *> &worklist, gimple *stmt);
void check_other_side (srdecl *decl, tree other, gimple *stmt,
vec<srdecl *> &worklist);
+ void check_ptr_layers (tree a_expr, tree b_expr, gimple *stmt);
void find_vars (gimple *stmt);
void find_var (tree expr, gimple *stmt);
@@ -1703,9 +1861,42 @@ ipa_struct_reorg::dump_types (FILE *f)
srtype *type;
FOR_EACH_VEC_ELT (types, i, type)
{
+ fprintf (f, "======= the %dth type: ======\n", i);
type->dump (f);
+ fprintf (f, "\n");
+ }
+}
+
+/* Dump all of the created newtypes to file F. */
+
+void
+ipa_struct_reorg::dump_newtypes (FILE *f)
+{
+ unsigned i = 0;
+ srtype *type = NULL;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ if (type->has_escaped ())
+ continue;
+ fprintf (f, "======= the %dth newtype: ======\n", i);
+ fprintf (f, "type : ");
+ print_generic_expr (f, type->newtype[0]);
+ fprintf (f, "(%d) ", TYPE_UID (type->newtype[0]));
+ fprintf (f, "{ ");
+ fprintf (f, "\nfields = {\n");
+
+ for (tree field = TYPE_FIELDS (TYPE_MAIN_VARIANT (type->newtype[0]));
+ field; field = DECL_CHAIN (field))
+ {
+ fprintf (f, "field (%d) ", DECL_UID (field));
+ fprintf (f, "{");
+ fprintf (f, "type = ");
+ print_generic_expr (f, TREE_TYPE (field));
+ fprintf (f, "}\n");
+ }
+ fprintf (f, "}\n ");
+ fprintf (f, "\n");
}
- fprintf (f, "\n");
}
/* Dump all of the recorded types to file F. */
@@ -1803,6 +1994,8 @@ isarraytype (tree type)
static bool
isptrptr (tree type)
{
+ if (type == NULL)
+ return false;
bool firstptr = false;
while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
{
@@ -1817,154 +2010,740 @@ isptrptr (tree 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. */
+/* Adding node to map and stack. */
-static escape_type
-escape_type_volatile_array_or_ptrptr (tree type)
+bool
+add_node (tree node, int layers, hash_map <tree, int> &map,
+ auto_vec <tree> &stack)
{
- if (isvolatile_type (type))
- return escape_volatile;
- if (isarraytype (type))
- return escape_array;
- if (isptrptr (type))
- return escape_ptr_ptr;
- return does_not_escape;
+ if (TREE_CODE (node) != SSA_NAME)
+ return false;
+ if (map.get (node) == NULL)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " ");
+ fprintf (dump_file, "add node: \t\t");
+ print_generic_expr (dump_file, node);
+ fprintf (dump_file, ",\t\tptr layers: %d: \n", layers);
+ }
+ map.put (node, layers);
+ stack.safe_push (node);
+ }
+ else if (*map.get (node) != layers)
+ return false;
+ return true;
}
-/* Record TYPE if not already recorded. */
+/* Check the number of pointer layers of the gimple phi in definition. */
-srtype *
-ipa_struct_reorg::record_type (tree type)
+bool
+check_def_phi (tree def_node, hash_map <tree, int> &ptr_layers)
{
- unsigned typeuid;
-
- /* Get the main variant as we are going
- to record that type only. */
- type = TYPE_MAIN_VARIANT (type);
- typeuid = TYPE_UID (type);
+ bool res = true;
+ gimple *def_stmt = SSA_NAME_DEF_STMT (def_node);
+ for (unsigned j = 0; j < gimple_phi_num_args (def_stmt); j++)
+ {
+ tree phi_node = gimple_phi_arg_def (def_stmt, j);
+ if (integer_zerop (phi_node))
+ continue;
+ if (ptr_layers.get (phi_node) == NULL)
+ return false;
+ res &= *ptr_layers.get (def_node) == *ptr_layers.get (phi_node);
+ }
+ return res;
+}
- srtype *type1;
+/* Check the number of pointer layers of the gimple assign in definition. */
- type1 = find_type (type);
- if (type1)
- return type1;
+bool
+check_def_assign (tree def_node, hash_map <tree, int> &ptr_layers)
+{
+ bool res = true;
+ gimple *def_stmt = SSA_NAME_DEF_STMT (def_node);
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (def_stmt);
+ tree_code rhs_code = gimple_assign_rhs_code (def_stmt);
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ tree rhs1_base = TREE_CODE (rhs1) == MEM_REF ? TREE_OPERAND (rhs1, 0) : rhs1;
+ if (ptr_layers.get (rhs1_base) == NULL)
+ return false;
+ if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS)
+ {
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1);
+ else if (TREE_CODE (rhs1) == MEM_REF)
+ res = *ptr_layers.get (def_node)
+ == *ptr_layers.get (TREE_OPERAND (rhs1, 0));
+ else
+ {
+ return false;
+ }
+ }
+ else if (rhs_class == GIMPLE_BINARY_RHS)
+ {
+ if (rhs_code == POINTER_PLUS_EXPR)
+ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1);
+ else if (rhs_code == BIT_AND_EXPR)
+ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1);
+ else
+ return false;
+ }
+ else
+ return false;
+ return res;
+}
- /* If already done recording just return NULL. */
- if (done_recording)
- return NULL;
+/* Check node definition. */
+bool
+check_node_def (hash_map <tree, int> &ptr_layers)
+{
+ bool res = true;
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))
+ fprintf (dump_file, "\n======== check node definition ========\n");
+ for (unsigned i = 1; i < num_ssa_names; ++i)
{
- if (TREE_CODE (field) == FIELD_DECL)
+ tree name = ssa_name (i);
+ if (name && ptr_layers.get (name) != NULL)
{
- 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 && current_mode != COMPLETE_STRUCT_RELAYOUT)
- type1->mark_escape (escape_rescusive_type, NULL);
- }
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+ if (dump_file && (dump_flags & TDF_DETAILS)
+ && gimple_code (def_stmt) != GIMPLE_DEBUG)
+ print_gimple_stmt (dump_file, def_stmt, 0);
+
+ if (gimple_code (def_stmt) == GIMPLE_PHI)
+ res = check_def_phi (name, ptr_layers);
+ else if (gimple_code (def_stmt) == GIMPLE_ASSIGN)
+ res = check_def_assign (name, ptr_layers);
+ else if (gimple_code (def_stmt) == GIMPLE_NOP)
+ continue;
+ else
+ return false;
}
}
+ return res;
+}
- return type1;
+/* Check pointer usage. */
+
+bool
+check_record_ptr_usage (gimple *use_stmt, tree &current_node,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack)
+{
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
+ tree rhs1 = gimple_assign_rhs1 (use_stmt);
+ tree lhs = gimple_assign_lhs (use_stmt);
+ if (rhs_class != GIMPLE_SINGLE_RHS
+ || (TREE_CODE (rhs1) != COMPONENT_REF && TREE_CODE (rhs1) != SSA_NAME)
+ || (TREE_CODE (lhs) != MEM_REF && TREE_CODE (lhs) != SSA_NAME))
+ return false;
+
+ bool res = true;
+ /* MEM[(long int *)a_1] = _1; (record).
+ If lhs is ssa_name, lhs cannot be the current node.
+ _2 = _1->flow; (No record). */
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ {
+ tree tmp = (rhs1 != current_node) ? rhs1 : lhs;
+ if (TREE_CODE (tmp) == MEM_REF)
+ res = add_node (TREE_OPERAND (tmp, 0),
+ *ptr_layers.get (current_node) + 1,
+ ptr_layers, ssa_name_stack);
+ else
+ res = add_node (tmp, *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+ }
+ else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == COMPONENT_REF)
+ res = !(POINTER_TYPE_P (TREE_TYPE (rhs1)));
+ else
+ res = false;
+ return res;
}
-/* Mark TYPE as escaping with ESCAPES as the reason. */
+/* Check and record a single node. */
-void
-ipa_struct_reorg::mark_type_as_escape (tree type,
- escape_type escapes,
- gimple *stmt)
+bool
+check_record_single_node (gimple *use_stmt, tree &current_node,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack)
{
- if (handled_type (type))
- {
- srtype *stype = record_type (inner_type (type));
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
+ tree rhs1 = gimple_assign_rhs1 (use_stmt);
+ tree lhs = gimple_assign_lhs (use_stmt);
+ gcc_assert (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS);
- if (!stype)
- return;
+ if ((TREE_CODE (rhs1) != SSA_NAME && TREE_CODE (rhs1) != MEM_REF)
+ || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (lhs) != MEM_REF))
+ return false;
- stype->mark_escape (escapes, stmt);
+ bool res = true;
+ if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == MEM_REF)
+ /* Add such as: _2 = MEM[(struct arc_t * *)_1]. */
+ res = add_node (lhs, *ptr_layers.get (current_node) - 1,
+ ptr_layers, ssa_name_stack);
+ else if (TREE_CODE (lhs) == MEM_REF && TREE_CODE (rhs1) == SSA_NAME)
+ {
+ /* Add such as: MEM[(long int *)a_1] = _1. */
+ if (rhs1 == current_node)
+ res = add_node (TREE_OPERAND (lhs, 0),
+ *ptr_layers.get (current_node) + 1,
+ ptr_layers, ssa_name_stack);
+ else
+ res = add_node (rhs1, *ptr_layers.get (current_node) - 1,
+ ptr_layers, ssa_name_stack);
}
+ else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == SSA_NAME)
+ res = add_node (lhs, *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+ else
+ res = false;
+
+ return res;
}
-/* Maybe process the union of type TYPE, such that marking all of the fields'
- types as being escaping. */
+/* Check and record multiple nodes. */
-void
-ipa_struct_reorg::process_union (tree type)
+bool
+check_record_mult_node (gimple *use_stmt, tree &current_node,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack)
{
- static hash_set<tree> unions_recorded;
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
+ tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
+ tree rhs1 = gimple_assign_rhs1 (use_stmt);
+ tree lhs = gimple_assign_lhs (use_stmt);
+ tree rhs2 = gimple_assign_rhs2 (use_stmt);
+ gcc_assert (rhs_class == GIMPLE_BINARY_RHS);
+
+ if ((rhs_code != POINTER_PLUS_EXPR && rhs_code != POINTER_DIFF_EXPR
+ && rhs_code != BIT_AND_EXPR)
+ || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (rhs1) != SSA_NAME))
+ return false;
- type = inner_type (type);
- if (TREE_CODE (type) != UNION_TYPE
- && TREE_CODE (type) != QUAL_UNION_TYPE)
- return;
+ bool res = true;
+ if (rhs_code == POINTER_PLUS_EXPR)
+ res = add_node (lhs == current_node ? rhs1 : lhs,
+ *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+ else if (rhs_code == POINTER_DIFF_EXPR)
+ res = add_node (rhs1 != current_node ? rhs1 : rhs2,
+ *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+ else if (rhs_code == BIT_AND_EXPR)
+ {
+ if (TREE_CODE (rhs2) != INTEGER_CST)
+ return false;
+ res = add_node (lhs == current_node ? rhs1 : lhs,
+ *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+ }
+ return res;
+}
- type = TYPE_MAIN_VARIANT (type);
+/* Check whether gimple assign is correctly used and record node. */
- /* We already processed this type. */
- if (unions_recorded.add (type))
- return;
+bool
+check_record_assign (tree &current_node, gimple *use_stmt,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack)
+{
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
+ if (*ptr_layers.get (current_node) == 1)
+ return check_record_ptr_usage (use_stmt, current_node,
+ ptr_layers, ssa_name_stack);
+ else if (*ptr_layers.get (current_node) > 1)
+ {
+ if (rhs_class != GIMPLE_BINARY_RHS
+ && rhs_class != GIMPLE_UNARY_RHS
+ && rhs_class != GIMPLE_SINGLE_RHS)
+ return false;
- for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS)
+ return check_record_single_node (use_stmt, current_node,
+ ptr_layers, ssa_name_stack);
+ else if (rhs_class == GIMPLE_BINARY_RHS)
+ return check_record_mult_node (use_stmt, current_node,
+ ptr_layers, ssa_name_stack);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+/* Check whether gimple phi is correctly used and record node. */
+
+bool
+check_record_phi (tree &current_node, gimple *use_stmt,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack)
+{
+ bool res = true;
+ res &= add_node (gimple_phi_result (use_stmt), *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
+
+ for (unsigned i = 0; i < gimple_phi_num_args (use_stmt); i++)
{
- if (TREE_CODE (field) == FIELD_DECL)
- {
- mark_type_as_escape (TREE_TYPE (field), escape_union);
- process_union (TREE_TYPE (field));
- }
+ if (integer_zerop (gimple_phi_arg_def (use_stmt, i)))
+ continue;
+ res &= add_node (gimple_phi_arg_def (use_stmt, i),
+ *ptr_layers.get (current_node),
+ ptr_layers, ssa_name_stack);
}
+ return res;
}
-/* 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. */
+/* Check the use of callee. */
-static tree
-record_init_types (tree *tp, int *walk_subtrees, void *data)
+bool
+check_callee (cgraph_node *node, gimple *stmt,
+ hash_map <tree, int> &ptr_layers, int input_layers)
{
- ipa_struct_reorg *c = (ipa_struct_reorg *)data;
- switch (TREE_CODE (*tp))
+ /* caller main ()
+ { spec_qsort.constprop (_649, _651); }
+ def spec_qsort.constprop (void * a, size_t n)
+ { spec_qsort.constprop (a_1, _139); } */
+ /* In safe functions, only call itself is allowed. */
+ if (node->get_edge (stmt)->callee != node)
+ return false;
+ tree input_node = gimple_call_arg (stmt, 0);
+ if (ptr_layers.get (input_node) == NULL
+ || *ptr_layers.get (input_node) != input_layers)
+ return false;
+ if (SSA_NAME_VAR (input_node) != DECL_ARGUMENTS (node->decl))
+ return false;
+
+ for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
{
- 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);
+ if (ptr_layers.get (gimple_call_arg (stmt, i)) != NULL)
+ return false;
+ }
+ return true;
+}
+
+/* Check the usage of input nodes and related nodes. */
+
+bool
+check_node_use (cgraph_node *node, tree current_node,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack,
+ int input_layers)
+{
+ imm_use_iterator imm_iter;
+ gimple *use_stmt = NULL;
+ bool res = true;
+ /* Use FOR_EACH_IMM_USE_STMT as an indirect edge
+ to search for possible related nodes and push to stack. */
+ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, current_node)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS)
+ && gimple_code (use_stmt) != GIMPLE_DEBUG)
+ {
+ fprintf (dump_file, "%*s", 4, "");
+ print_gimple_stmt (dump_file, use_stmt, 0);
+ }
+ /* For other types of gimple, do not record the node. */
+ if (res)
+ {
+ if (gimple_code (use_stmt) == GIMPLE_PHI)
+ res = check_record_phi (current_node, use_stmt,
+ ptr_layers, ssa_name_stack);
+ else if (gimple_code (use_stmt) == GIMPLE_ASSIGN)
+ res = check_record_assign (current_node, use_stmt,
+ ptr_layers, ssa_name_stack);
+ else if (gimple_code (use_stmt) == GIMPLE_CALL)
+ res = check_callee (node, use_stmt, ptr_layers, input_layers);
+ else if (gimple_code (use_stmt) == GIMPLE_RETURN)
+ res = false;
+ }
+ }
+ return res;
+}
+
+/* Trace the pointer layers of void node. */
+
+bool
+get_void_node_ptr_layers (tree input, int &input_layers)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "input type is void* node\n");
+ imm_use_iterator imm_iter;
+ gimple *use_stmt = NULL;
+ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, input)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ print_gimple_stmt (dump_file, use_stmt, 0);
+ if (gimple_code (use_stmt) == GIMPLE_ASSIGN
+ && gimple_assign_rhs_class (use_stmt) == GIMPLE_SINGLE_RHS)
+ {
+ tree rhs1 = gimple_assign_rhs1 (use_stmt);
+ tree lhs = gimple_assign_lhs (use_stmt);
+ if (TREE_CODE (lhs) == SSA_NAME && handled_type (TREE_TYPE (lhs)))
+ {
+ if (TREE_CODE (rhs1) == MEM_REF)
+ {
+ input_layers = get_ptr_layers (TREE_TYPE (lhs)) + 1;
+ return true;
+ }
+ }
+ }
+ }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "end trace pointer layers of void* node\n");
+ return false;
+}
+
+/* Preparing the First Node for DFS. */
+
+bool
+set_init_node (cgraph_node *node, cgraph_edge *caller,
+ hash_map <tree, int> &ptr_layers,
+ auto_vec <tree> &ssa_name_stack, int &input_layers)
+{
+ /* Set input_layer
+ caller spec_qsort.constprop (_649, _651)
+ |-- Obtains the actual ptr layer
+ from the input node. */
+ caller->caller->get_untransformed_body ();
+ if (caller->call_stmt == NULL
+ || gimple_call_num_args (caller->call_stmt) == 0)
+ return false;
+ tree input = gimple_call_arg (caller->call_stmt, 0);
+ if (!(POINTER_TYPE_P (TREE_TYPE (input))
+ || TREE_CODE (TREE_TYPE (input)) == ARRAY_TYPE))
+ return false;
+ if (handled_type (TREE_TYPE (input)))
+ input_layers = get_ptr_layers (TREE_TYPE (input));
+ else
+ {
+ if (VOID_POINTER_P (TREE_TYPE (input)))
+ {
+ if (!get_void_node_ptr_layers (input, input_layers))
+ return false;
+ }
+ }
+
+ /* Set initial node
+ def spec_qsort.constprop (void * a, size_t n)
+ |-- Find the initial ssa_name
+ from the parameter node. */
+ tree parm = DECL_ARGUMENTS (node->decl);
+ for (unsigned j = 1; j < num_ssa_names; ++j)
+ {
+ tree name = ssa_name (j);
+ if (!name || has_zero_uses (name) || virtual_operand_p (name))
+ continue;
+ if (SSA_NAME_VAR (name) == parm
+ && gimple_code (SSA_NAME_DEF_STMT (name)) == GIMPLE_NOP)
+ {
+ if (!add_node (name, input_layers, ptr_layers, ssa_name_stack))
+ return false;
+ }
+ }
+ return !ssa_name_stack.is_empty ();
+}
+
+/* Check the usage of each call. */
+
+bool
+check_each_call (cgraph_node *node, cgraph_edge *caller)
+{
+ hash_map <tree, int> ptr_layers;
+ auto_vec <tree> ssa_name_stack;
+ int input_layers = 0;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "======== check each call : %s/%u ========\n",
+ node->name (), node->order);
+ if (!set_init_node (node, caller, ptr_layers, ssa_name_stack, input_layers))
+ return false;
+ int i = 0;
+ while (!ssa_name_stack.is_empty ())
+ {
+ tree current_node = ssa_name_stack.pop ();
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ncur node %d: \t", i++);
+ print_generic_expr (dump_file, current_node);
+ fprintf (dump_file, ",\t\tptr layers: %d: \n",
+ *ptr_layers.get (current_node));
+ }
+ if (get_ptr_layers (TREE_TYPE (current_node))
+ > *ptr_layers.get (current_node))
+ return false;
+ if (!check_node_use (node, current_node, ptr_layers, ssa_name_stack,
+ input_layers))
+ return false;
+ }
+
+ if (!check_node_def (ptr_layers))
+ return false;
+ return true;
+}
+
+/* Filter out function: void func (void*, int n),
+ and the function has no static variable, no structure-related variable,
+ and no global variable is used. */
+
+bool
+filter_func (cgraph_node *node)
+{
+ tree parm = DECL_ARGUMENTS (node->decl);
+ if (!(parm && VOID_POINTER_P (TREE_TYPE (parm))
+ && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (node->decl)))))
+ return false;
+
+ for (parm = DECL_CHAIN (parm); parm; parm = DECL_CHAIN (parm))
+ {
+ if (TREE_CODE (TREE_TYPE (parm)) != INTEGER_TYPE)
+ return false;
+ }
+
+ if (DECL_STRUCT_FUNCTION (node->decl)->static_chain_decl)
+ return false;
+
+ tree var = NULL_TREE;
+ unsigned int i = 0;
+ bool res = true;
+ FOR_EACH_LOCAL_DECL (cfun, i, var)
+ {
+ if (TREE_CODE (var) == VAR_DECL && handled_type (TREE_TYPE (var)))
+ res = false;
+ }
+ if (!res)
+ return false;
+
+ for (unsigned j = 1; j < num_ssa_names; ++j)
+ {
+ tree name = ssa_name (j);
+ if (!name || has_zero_uses (name) || virtual_operand_p (name))
+ continue;
+ tree var = SSA_NAME_VAR (name);
+ if (var && TREE_CODE (var) == VAR_DECL && is_global_var (var))
+ return false;
+ }
+ return true;
+}
+
+/* Check whether the function with the void* parameter and uses the input node
+ safely.
+ In these functions only component_ref can be used to dereference the last
+ layer of the input structure pointer. The hack operation pointer offset
+ after type cast cannot be used.
+*/
+
+bool
+is_safe_func_with_void_ptr_parm (cgraph_node *node)
+{
+ if (!filter_func (node))
+ return false;
+
+ /* Distinguish Recursive Callers
+ normal_callers: main ()
+ { spec_qsort.constprop (_649, _651); }
+ definition: spec_qsort.constprop (void * a, size_t n)
+ recursive_callers: { spec_qsort.constprop (a_1, _139); } */
+ auto_vec<cgraph_edge *> callers = node->collect_callers ();
+ auto_vec<cgraph_edge *> normal_callers;
+ for (unsigned i = 0; i < callers.length (); i++)
+ {
+ if (callers[i]->caller != node)
+ normal_callers.safe_push (callers[i]);
+ }
+ if (normal_callers.length () == 0)
+ return false;
+
+ for (unsigned i = 0; i < normal_callers.length (); i++)
+ {
+ if (!check_each_call (node, normal_callers[i]))
+ return false;
+ }
+ return true;
+}
+
+/* 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) && (current_mode != STRUCT_REORDER_FIELDS))
+ return escape_ptr_ptr;
+ return does_not_escape;
+}
+
+/* Record field type. */
+
+void
+ipa_struct_reorg::record_field_type (tree field, srtype *base_srtype)
+{
+ tree field_type = TREE_TYPE (field);
+ /* The uid of the type in the structure is different
+ from that outside the structure. */
+ srtype *field_srtype = record_type (inner_type (field_type));
+ srfield *field_srfield = base_srtype->find_field (int_byte_position (field));
+ /* We might have an variable sized type which we don't set the handle. */
+ if (field_srfield)
+ {
+ field_srfield->type = field_srtype;
+ field_srtype->add_field_site (field_srfield);
+ }
+ if (field_srtype == base_srtype && current_mode != COMPLETE_STRUCT_RELAYOUT
+ && current_mode != STRUCT_REORDER_FIELDS)
+ base_srtype->mark_escape (escape_rescusive_type, NULL);
+ /* Types of non-pointer field are difficult to track the correctness
+ of the rewrite when it used by the escaped type. */
+ if (current_mode == STRUCT_REORDER_FIELDS
+ && TREE_CODE (field_type) == RECORD_TYPE)
+ field_srtype->mark_escape (escape_instance_field, NULL);
+}
+
+/* Record structure all field types. */
+
+void
+ipa_struct_reorg::record_struct_field_types (tree base_type,
+ srtype *base_srtype)
+{
+ for (tree field = TYPE_FIELDS (base_type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ tree field_type = TREE_TYPE (field);
+ process_union (field_type);
+ if (TREE_CODE (inner_type (field_type)) == UNION_TYPE
+ || TREE_CODE (inner_type (field_type)) == QUAL_UNION_TYPE)
+ base_srtype->mark_escape (escape_union, NULL);
+ if (isvolatile_type (field_type))
+ base_srtype->mark_escape (escape_volatile, NULL);
+ escape_type e = escape_type_volatile_array_or_ptrptr (field_type);
+ if (e != does_not_escape)
+ base_srtype->mark_escape (e, NULL);
+ /* Types of non-pointer field are difficult to track the correctness
+ of the rewrite when it used by the escaped type. */
+ if (current_mode == STRUCT_REORDER_FIELDS
+ && TREE_CODE (field_type) == RECORD_TYPE)
+ base_srtype->mark_escape (escape_instance_field, NULL);
+ if (handled_type (field_type))
+ record_field_type (field, base_srtype);
+ }
+ }
+}
+
+/* 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);
+ const char *type_name = get_type_name (type);
+ if (type_name == NULL)
+ fprintf (dump_file, "Recording new type NULL name\n");
+ else
+ fprintf (dump_file, "Recording new type name: %s.\n", type_name);
+ }
+
+ 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);
+
+ record_struct_field_types (type, type1);
+
+ 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;
}
@@ -1996,6 +2775,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
process_union (TREE_TYPE (decl));
+ /* Only the structure type RECORD_TYPE is recorded.
+ Therefore, the void* type is filtered out. */
if (handled_type (TREE_TYPE (decl)))
{
type = record_type (inner_type (TREE_TYPE (decl)));
@@ -2035,7 +2816,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
/* Separate instance is hard to trace in complete struct
relayout optimization. */
- if (current_mode == COMPLETE_STRUCT_RELAYOUT
+ if ((current_mode == COMPLETE_STRUCT_RELAYOUT
+ || current_mode == STRUCT_REORDER_FIELDS)
&& TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
e = escape_separate_instance;
@@ -2078,11 +2860,9 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt)
{
tree r = TREE_OPERAND (expr, 0);
tree orig_type = TREE_TYPE (expr);
- if (handled_component_p (r)
- || TREE_CODE (r) == MEM_REF)
+ if (handled_component_p (r) || TREE_CODE (r) == MEM_REF)
{
- while (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)
{
@@ -2114,8 +2894,10 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt)
srtype *type;
srfield *field;
bool realpart, imagpart, address;
+ bool escape_from_base = false;
+ /* The should_create flag is true, the declaration can be recorded. */
get_type_field (expr, base, indirect, type, field,
- realpart, imagpart, address, true, true);
+ realpart, imagpart, address, escape_from_base, true, true);
}
void
@@ -2132,36 +2914,79 @@ ipa_struct_reorg::find_vars (gimple *stmt)
tree lhs = gimple_assign_lhs (stmt);
tree rhs = gimple_assign_rhs1 (stmt);
find_var (gimple_assign_lhs (stmt), stmt);
+ /* _2 = MEM[(struct arc_t * *)_1];
+ records the right value _1 declaration. */
find_var (gimple_assign_rhs1 (stmt), stmt);
- if (TREE_CODE (lhs) == SSA_NAME
+
+ /* Add a safe func mechanism. */
+ bool l_find = true;
+ bool r_find = true;
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ l_find = !(current_function->is_safe_func
+ && TREE_CODE (lhs) == SSA_NAME
+ && is_from_void_ptr_parm (lhs));
+ r_find = !(current_function->is_safe_func
+ && TREE_CODE (rhs) == SSA_NAME
+ && is_from_void_ptr_parm (rhs));
+ }
+
+ if ((TREE_CODE (lhs) == SSA_NAME)
&& VOID_POINTER_P (TREE_TYPE (lhs))
- && handled_type (TREE_TYPE (rhs)))
+ && handled_type (TREE_TYPE (rhs)) && l_find)
{
srtype *t = find_type (inner_type (TREE_TYPE (rhs)));
srdecl *d = find_decl (lhs);
if (!d && t)
{
- current_function->record_decl (t, lhs, -1);
+ current_function->record_decl (t, lhs, -1,
+ isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL);
tree var = SSA_NAME_VAR (lhs);
if (var && VOID_POINTER_P (TREE_TYPE (var)))
- current_function->record_decl (t, var, -1);
+ current_function->record_decl (t, var, -1,
+ isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL);
}
}
+ /* Find void ssa_name such as:
+ void * _1; struct arc * _2;
+ _2 = _1 + _3; _1 = calloc (100, 40). */
if (TREE_CODE (rhs) == SSA_NAME
&& VOID_POINTER_P (TREE_TYPE (rhs))
- && handled_type (TREE_TYPE (lhs)))
+ && handled_type (TREE_TYPE (lhs)) && r_find)
{
srtype *t = find_type (inner_type (TREE_TYPE (lhs)));
srdecl *d = find_decl (rhs);
if (!d && t)
{
- current_function->record_decl (t, rhs, -1);
+ current_function->record_decl (t, rhs, -1,
+ isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL);
tree var = SSA_NAME_VAR (rhs);
if (var && VOID_POINTER_P (TREE_TYPE (var)))
- current_function->record_decl (t, var, -1);
+ current_function->record_decl (t, var, -1,
+ isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL);
}
}
}
+ else if ((current_mode == STRUCT_REORDER_FIELDS)
+ && (gimple_assign_rhs_code (stmt) == LE_EXPR
+ || gimple_assign_rhs_code (stmt) == LT_EXPR
+ || gimple_assign_rhs_code (stmt) == GE_EXPR
+ || gimple_assign_rhs_code (stmt) == GT_EXPR))
+ {
+ find_var (gimple_assign_lhs (stmt), stmt);
+ find_var (gimple_assign_rhs1 (stmt), stmt);
+ find_var (gimple_assign_rhs2 (stmt), stmt);
+ }
+ /* Find void ssa_name from stmt such as: _2 = _1 - old_arcs_1. */
+ else if ((current_mode == STRUCT_REORDER_FIELDS)
+ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR
+ && types_compatible_p (
+ TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs1 (stmt))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs2 (stmt)))))
+ {
+ find_var (gimple_assign_rhs1 (stmt), stmt);
+ find_var (gimple_assign_rhs2 (stmt), stmt);
+ }
else
{
/* Because we won't handle these stmts in rewrite phase,
@@ -2232,27 +3057,134 @@ ipa_struct_reorg::find_vars (gimple *stmt)
}
}
-/* Maybe record access of statement for further analaysis. */
+/* 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;
+ }
+}
+
+/* Calculate the multiplier. */
+
+static bool
+calculate_mult_num (tree arg, tree *num, tree struct_size)
+{
+ gcc_assert (TREE_CODE (arg) == INTEGER_CST);
+ bool sign = false;
+ HOST_WIDE_INT size = TREE_INT_CST_LOW (arg);
+ if (size < 0)
+ {
+ size = -size;
+ sign = true;
+ }
+ tree arg2 = build_int_cst (TREE_TYPE (arg), size);
+ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size)))
+ {
+ tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size);
+ if (sign)
+ number = build_int_cst (TREE_TYPE (number), -tree_to_shwi (number));
+ *num = number;
+ return true;
+ }
+ return false;
+}
+
+/* Trace and calculate the multiplier of PLUS_EXPR. */
+
+static bool
+trace_calculate_plus (gimple *size_def_stmt, tree *num, tree struct_size)
+{
+ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR);
+
+ tree num1 = NULL_TREE;
+ tree num2 = NULL_TREE;
+ 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) || num1 == NULL_TREE)
+ return false;
+ if (!is_result_of_mult (arg1, &num2, struct_size) || num2 == NULL_TREE)
+ return false;
+ *num = size_binop (PLUS_EXPR, num1, num2);
+ return true;
+}
+
+/* Trace and calculate the multiplier of MULT_EXPR. */
+
+static bool
+trace_calculate_mult (gimple *size_def_stmt, tree *num, tree struct_size)
+{
+ gcc_assert (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 = NULL_TREE;
+
+ if (is_result_of_mult (arg0, &num1, struct_size) && num1 != NULL_TREE)
+ {
+ *num = size_binop (MULT_EXPR, arg1, num1);
+ return true;
+ }
+ if (is_result_of_mult (arg1, &num1, struct_size) && num1 != NULL_TREE)
+ {
+ *num = size_binop (MULT_EXPR, arg0, num1);
+ return true;
+ }
+ *num = NULL_TREE;
+ return false;
+}
+
+/* Trace and calculate the multiplier of NEGATE_EXPR. */
+
+static bool
+trace_calculate_negate (gimple *size_def_stmt, tree *num, tree struct_size)
+{
+ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NEGATE_EXPR);
+
+ /* Support NEGATE_EXPR trace: _3 = -_2; _2 = _1 * 72. */
+ tree num1 = NULL_TREE;
+ tree arg0 = gimple_assign_rhs1 (size_def_stmt);
+ if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE)
+ return false;
+ tree num0 = build_int_cst (TREE_TYPE (num1), -1);
+ *num = size_binop (MULT_EXPR, num0, num1);
+ return true;
+}
+
+/* Trace and calculate the multiplier of POINTER_DIFF_EXPR. */
-void
-ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt)
+static bool
+trace_calculate_diff (gimple *size_def_stmt, tree *num)
{
- switch (gimple_code (stmt))
+ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NOP_EXPR);
+
+ /* Support POINTER_DIFF_EXPR trace:
+ _3 = (long unsigned int) _2; _2 = _1 - old_arcs_1. */
+ tree arg = gimple_assign_rhs1 (size_def_stmt);
+ size_def_stmt = SSA_NAME_DEF_STMT (arg);
+ if (size_def_stmt && is_gimple_assign (size_def_stmt)
+ && gimple_assign_rhs_code (size_def_stmt) == POINTER_DIFF_EXPR)
{
- 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;
+ *num = NULL_TREE;
+ return true;
}
+ *num = NULL_TREE;
+ return false;
}
/* This function checks whether ARG is a result of multiplication
@@ -2269,26 +3201,8 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
/* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */
if (TREE_CODE (arg) == INTEGER_CST)
- {
- bool sign = false;
- HOST_WIDE_INT size = TREE_INT_CST_LOW (arg);
- if (size < 0)
- {
- size = -size;
- sign = true;
- }
- tree arg2 = build_int_cst (TREE_TYPE (arg), size);
- if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size)))
- {
- tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size);
- if (sign)
- number = build_int_cst (TREE_TYPE (number),
- -tree_to_shwi (number));
- *num = number;
- return true;
- }
- return false;
- }
+ return calculate_mult_num (arg, num, struct_size);
+
gimple *size_def_stmt = SSA_NAME_DEF_STMT (arg);
/* If the allocation statement was of the form
@@ -2304,43 +3218,20 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
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)
+ tree_code rhs_code = gimple_assign_rhs_code (size_def_stmt);
+ if (rhs_code == PLUS_EXPR)
+ return trace_calculate_plus (size_def_stmt, num, struct_size);
+ else if (rhs_code == MULT_EXPR)
+ return trace_calculate_mult (size_def_stmt, num, struct_size);
+ else if (rhs_code == SSA_NAME)
{
arg = gimple_assign_rhs1 (size_def_stmt);
size_def_stmt = SSA_NAME_DEF_STMT (arg);
}
+ else if (rhs_code == NEGATE_EXPR && current_mode == STRUCT_REORDER_FIELDS)
+ return trace_calculate_negate (size_def_stmt, num, struct_size);
+ else if (rhs_code == NOP_EXPR && current_mode == STRUCT_REORDER_FIELDS)
+ return trace_calculate_diff (size_def_stmt, num);
else
{
*num = NULL_TREE;
@@ -2357,18 +3248,22 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
bool
ipa_struct_reorg::handled_allocation_stmt (gimple *stmt)
{
- if (current_mode == COMPLETE_STRUCT_RELAYOUT
+ if ((current_mode == STRUCT_REORDER_FIELDS)
+ && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)))
+ return true;
+ if ((current_mode == COMPLETE_STRUCT_RELAYOUT)
&& gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
return true;
-
- if (current_mode != COMPLETE_STRUCT_RELAYOUT)
- 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;
+ if ((current_mode == NORMAL)
+ && (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;
}
@@ -2376,7 +3271,7 @@ ipa_struct_reorg::handled_allocation_stmt (gimple *stmt)
elements in the array allocated. */
tree
-ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
+ipa_struct_reorg::allocate_size (srtype *type, srdecl *decl, gimple *stmt)
{
if (!stmt
|| gimple_code (stmt) != GIMPLE_CALL
@@ -2396,6 +3291,10 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
tree struct_size = TYPE_SIZE_UNIT (type->type);
+ /* Specify the correct size to relax multi-layer pointer. */
+ if (TREE_CODE (decl->decl) == SSA_NAME && isptrptr (decl->orig_type))
+ struct_size = TYPE_SIZE_UNIT (decl->orig_type);
+
tree size = gimple_call_arg (stmt, 0);
if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
@@ -2409,8 +3308,10 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
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. */
+ /* ??? Check that first argument is a constant
+ equal to the size of structure. */
+ /* If the allocated number is equal to the value of struct_size,
+ the value of arg1 is changed to the allocated number. */
if (operand_equal_p (size, struct_size, 0))
return arg1;
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2453,10 +3354,16 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
if (!d)
{
+ /* MEM[(struct arc *)_1].head = _2; _2 = calloc (100, 104). */
if (VOID_POINTER_P (TREE_TYPE (side))
&& TREE_CODE (side) == SSA_NAME)
- current_function->record_decl (type, side, -1);
+ {
+ /* The type is other, the declaration is side. */
+ current_function->record_decl (type, side, -1,
+ isptrptr (TREE_TYPE (other)) ? TREE_TYPE (other) : NULL);
+ }
else
+ /* *_1 = &MEM[(void *)&x + 8B]. */
type->mark_escape (escape_cast_another_ptr, stmt);
}
else if (type != d->type)
@@ -2464,6 +3371,17 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
type->mark_escape (escape_cast_another_ptr, stmt);
d->type->mark_escape (escape_cast_another_ptr, stmt);
}
+ /* x_1 = y.x_nodes; void *x;
+ Directly mark the structure pointer type assigned
+ to the void* variable as escape. */
+ else if (current_mode == STRUCT_REORDER_FIELDS
+ && TREE_CODE (side) == SSA_NAME
+ && VOID_POINTER_P (TREE_TYPE (side))
+ && SSA_NAME_VAR (side)
+ && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (side))))
+ mark_type_as_escape (TREE_TYPE (other), escape_cast_void, stmt);
+
+ check_ptr_layers (side, other, stmt);
}
/* Record accesses in an assignment statement STMT. */
@@ -2486,8 +3404,12 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt)
if (!handled_type (TREE_TYPE (lhs)))
return;
/* Check if rhs2 is a multiplication of the size of the type. */
+ /* The size adjustment and judgment of multi-layer pointers
+ are added. */
if (is_result_of_mult (rhs2, &num,
- TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)))))
+ isptrptr (TREE_TYPE (lhs))
+ ? TYPE_SIZE_UNIT (TREE_TYPE (lhs))
+ : TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)))))
{
record_stmt_expr (lhs, node, stmt);
record_stmt_expr (rhs1, node, stmt);
@@ -2525,9 +3447,8 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt)
}
static bool
-check_mem_ref_offset (tree expr)
+check_mem_ref_offset (tree expr, tree *num)
{
- tree num = NULL;
bool ret = false;
if (TREE_CODE (expr) != MEM_REF)
@@ -2538,15 +3459,18 @@ check_mem_ref_offset (tree expr)
tree tmp = TREE_OPERAND (expr, 0);
if (TREE_CODE (tmp) == ADDR_EXPR)
tmp = TREE_OPERAND (tmp, 0);
- tree size = TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp)));
- ret = is_result_of_mult (field_off, &num, size);
+ /* Specify the correct size for the multi-layer pointer. */
+ tree size = isptrptr (TREE_TYPE (tmp))
+ ? TYPE_SIZE_UNIT (TREE_TYPE (tmp))
+ : TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp)));
+ ret = is_result_of_mult (field_off, num, size);
return ret;
}
static tree
get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
bool &realpart, bool &imagpart,
- tree &accesstype)
+ tree &accesstype, tree *num)
{
offset = 0;
realpart = false;
@@ -2569,22 +3493,29 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
{
case COMPONENT_REF:
{
+ /* x.a = _1; If expr is the lvalue of stmt,
+ then field type is FIELD_DECL - POINTER_TYPE - RECORD_TYPE. */
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);
+ /* x.a = _1; If expr is the lvalue of stmt,
+ then expr type is VAR_DECL - RECORD_TYPE (fetch x) */
expr = TREE_OPERAND (expr, 0);
accesstype = NULL;
break;
}
case MEM_REF:
{
+ /* _2 = MEM[(struct s * *)_1];
+ If expr is the right value of stmt, then field_off type is
+ INTEGER_CST - POINTER_TYPE - POINTER_TYPE - RECORD_TYPE. */
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);
- if (!check_mem_ref_offset (expr))
+ if (!check_mem_ref_offset (expr, num))
offset += tree_to_uhwi (field_off);
return TREE_OPERAND (expr, 0);
}
@@ -2626,10 +3557,11 @@ ipa_struct_reorg::wholeaccess (tree expr, tree base,
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 &realpart, bool &imagpart, bool &address,
+ bool &escape_from_base, bool should_create,
bool can_escape)
{
+ tree num = NULL_TREE;
HOST_WIDE_INT offset;
tree accesstype;
address = false;
@@ -2641,8 +3573,9 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
mark_as_bit_field = true;
}
+ /* Ref is classified into two types: COMPONENT_REF or MER_REF. */
base = get_ref_base_and_offset (expr, offset, realpart, imagpart,
- accesstype);
+ accesstype, &num);
/* Variable access, unkown type. */
if (base == NULL)
@@ -2680,6 +3613,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
if (!t)
return false;
}
+ /* If no such decl is finded
+ or orig_type is not added to this decl, then add it. */
else if (!d && accesstype)
{
if (!should_create)
@@ -2691,15 +3626,52 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
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)))
+ /* If base is not void* mark the type as escaping.
+ release INTEGER_TYPE cast to struct pointer.
+ (If t has escpaed above, then directly returns
+ and doesn't mark escape follow.). */
+ /* _1 = MEM[(struct arc_t * *)a_1].
+ then base a_1: ssa_name - pointer_type - integer_type. */
+ if (current_mode == STRUCT_REORDER_FIELDS)
{
- gcc_assert (can_escape);
- t->mark_escape (escape_cast_another_ptr, NULL);
- return false;
+ bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base))
+ && (TREE_CODE (inner_type (TREE_TYPE (base)))
+ == INTEGER_TYPE);
+ if (!(VOID_POINTER_P (TREE_TYPE (base))
+ || (current_function->is_safe_func && is_int_ptr)))
+ {
+ gcc_assert (can_escape);
+ t->mark_escape (escape_cast_another_ptr, NULL);
+ return false;
+ }
+ if (TREE_CODE (base) == SSA_NAME
+ && !(current_function->is_safe_func && is_int_ptr))
+ {
+ /* Add a safe func mechanism. */
+ if (!(current_function->is_safe_func
+ && is_from_void_ptr_parm (base)))
+ /* Add auxiliary information of the multi-layer pointer
+ type. */
+ current_function->record_decl (t, base, -1,
+ isptrptr (accesstype) ? accesstype : NULL);
+ }
+ }
+ else
+ {
+ 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)
+ {
+ /* Add auxiliary information of the multi-layer pointer
+ type. */
+ current_function->record_decl (t, base, -1,
+ isptrptr (accesstype) ? accesstype : NULL);
+ }
}
- if (TREE_CODE (base) == SSA_NAME)
- current_function->record_decl (t, base, -1);
}
else if (!d)
return false;
@@ -2707,7 +3679,10 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
t = d->type;
if (t->has_escaped ())
+ {
+ escape_from_base = true;
return false;
+ }
if (mark_as_bit_field)
{
@@ -2716,6 +3691,17 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
return false;
}
+ /* Escape the operation of fetching field with pointer offset such as:
+ *(&(t->right)) = malloc (0); -> MEM[(struct node * *)_1 + 8B] = malloc (0);
+ */
+ if (current_mode != NORMAL
+ && (TREE_CODE (expr) == MEM_REF) && (offset != 0))
+ {
+ gcc_assert (can_escape);
+ t->mark_escape (escape_non_multiply_size, NULL);
+ return false;
+ }
+
if (wholeaccess (expr, base, accesstype, t))
{
field = NULL;
@@ -2733,7 +3719,6 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
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);
@@ -2747,9 +3732,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect,
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 = ");
+ fprintf (dump_file, "\noriginal expr = ");
print_generic_expr (dump_file, expr);
- fprintf (dump_file, "\n");
}
gcc_assert (can_escape);
t->mark_escape (escape_unkown_field, NULL);
@@ -2772,8 +3756,9 @@ ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes,
srtype *type;
srfield *field;
bool realpart, imagpart, address;
+ bool escape_from_base = false;
if (!get_type_field (expr, base, indirect, type, field,
- realpart, imagpart, address))
+ realpart, imagpart, address, escape_from_base))
return;
type->mark_escape (escapes, stmt);
@@ -2846,10 +3831,23 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt)
gimple_call_arg (stmt, i));
if (d)
d->type->mark_escape (escapes, stmt);
+
+ if (escapes == escape_external_function
+ && !gimple_call_builtin_p (stmt, BUILT_IN_MEMSET))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "escape_external_function: ");
+ print_gimple_stmt (dump_file, stmt, 0);
+ }
+ if (d)
+ ext_func_types.safe_push (d->type);
+ }
}
return;
}
+ /* Get func param it's tree_list. */
argtype = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
{
@@ -2857,9 +3855,14 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt)
if (argtype)
{
tree argtypet = TREE_VALUE (argtype);
- if (!free_or_realloc
+ /* callee_func (_1, _2);
+ Check the callee func, instead of current func. */
+ if (!(free_or_realloc
+ || (current_mode == STRUCT_REORDER_FIELDS
+ && safe_functions.contains (
+ node->get_edge (stmt)->callee)))
&& VOID_POINTER_P (argtypet))
- mark_type_as_escape (TREE_TYPE (arg), escape_cast_void);
+ mark_type_as_escape (TREE_TYPE (arg), escape_cast_void, stmt);
else
record_stmt_expr (arg, node, stmt);
}
@@ -2878,12 +3881,22 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt)
srtype *type;
srfield *field;
bool realpart, imagpart, address;
+ bool escape_from_base = false;
if (!get_type_field (expr, base, indirect, type, field,
- realpart, imagpart, address))
+ realpart, imagpart, address, escape_from_base))
return;
- if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg))
- type->mark_escape (escape_non_optimize, stmt);
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ if (!opt_for_fn (current_function_decl, flag_ipa_reorder_fields))
+ type->mark_escape (escape_non_optimize, stmt);
+ }
+ else
+ {
+ 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));
@@ -2901,10 +3914,10 @@ ipa_struct_reorg::find_function (cgraph_node *node)
}
void
-ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type,
- vec<srdecl *> &worklist,
- gimple *stmt)
+ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl,
+ vec<srdecl *> &worklist, gimple *stmt)
{
+ srtype *type = decl->type;
if (integer_zerop (newdecl))
return;
@@ -2916,7 +3929,8 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type,
type->mark_escape (escape_cast_another_ptr, stmt);
return;
}
- if (d->type == type)
+ if (d->type == type
+ && cmp_ptr_layers (TREE_TYPE (newdecl), TREE_TYPE (decl->decl)))
return;
srtype *type1 = d->type;
@@ -2967,7 +3981,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type,
/* 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)
+ tree a_decl = d->orig_type ? d->orig_type : TREE_TYPE (newdecl);
+ tree b_decl = decl->orig_type ? decl->orig_type : TREE_TYPE (decl->decl);
+ if (d->type == type && cmp_ptr_layers (a_decl, b_decl))
return;
srtype *type1 = d->type;
@@ -3000,6 +4016,96 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type)
}
}
+/* Check the definition of gimple assign. */
+
+void
+ipa_struct_reorg::check_definition_assign (srdecl *decl,
+ vec<srdecl *> &worklist)
+{
+ tree ssa_name = decl->decl;
+ srtype *type = decl->type;
+ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name);
+ 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 = NULL_TREE;
+ /* Specify the correct size for the multi-layer pointer. */
+ if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type)
+ ? TYPE_SIZE_UNIT (decl->orig_type)
+ : TYPE_SIZE_UNIT (type->type)))
+ type->mark_escape (escape_non_multiply_size, stmt);
+
+ if (TREE_CODE (rhs) == SSA_NAME)
+ check_type_and_push (rhs, decl, worklist, stmt);
+ return;
+ }
+
+ if (gimple_assign_rhs_code (stmt) == MAX_EXPR
+ || gimple_assign_rhs_code (stmt) == MIN_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR)
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ if (TREE_CODE (rhs) == SSA_NAME)
+ check_type_and_push (rhs, decl, worklist, stmt);
+ if (TREE_CODE (rhs2) == SSA_NAME)
+ check_type_and_push (rhs2, decl, 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);
+ check_ptr_layers (decl->decl, rhs, stmt);
+}
+
+/* Check the definition of gimple call. */
+
+void
+ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl *> &worklist)
+{
+ tree ssa_name = decl->decl;
+ srtype *type = decl->type;
+ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name);
+ gcc_assert (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), decl, worklist, stmt);
+
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ if (!handled_allocation_stmt (stmt))
+ type->mark_escape (escape_return, stmt);
+ if (!allocate_size (type, decl, stmt))
+ type->mark_escape (escape_non_multiply_size, stmt);
+ }
+ else
+ {
+ if (!handled_allocation_stmt (stmt)
+ || !allocate_size (type, decl, stmt))
+ type->mark_escape (escape_return, stmt);
+ }
+
+ check_alloc_num (stmt, type);
+ return;
+}
+
/*
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
@@ -3029,9 +4135,12 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
if (var
&& TREE_CODE (var) == PARM_DECL
&& VOID_POINTER_P (TREE_TYPE (ssa_name)))
- type->mark_escape (escape_cast_void, NULL);
+ type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name));
return;
}
+ if (current_mode == STRUCT_REORDER_FIELDS && SSA_NAME_VAR (ssa_name)
+ && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name))))
+ type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name));
gimple *stmt = SSA_NAME_DEF_STMT (ssa_name);
/*
@@ -3039,17 +4148,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
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);
- check_alloc_num (stmt, type);
- return;
- }
+ check_definition_call (decl, worklist);
/* If the SSA_NAME is sourced from an inline-asm,
just mark the type as escaping. */
if (gimple_code (stmt) == GIMPLE_ASM)
@@ -3065,58 +4164,11 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
{
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;
- }
-
- if (gimple_assign_rhs_code (stmt) == MAX_EXPR
- || gimple_assign_rhs_code (stmt) == MIN_EXPR
- || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR
- || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR
- || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR)
- {
- tree rhs2 = gimple_assign_rhs2 (stmt);
- if (TREE_CODE (rhs) == SSA_NAME)
- check_type_and_push (rhs, type, worklist, stmt);
- if (TREE_CODE (rhs2) == SSA_NAME)
- check_type_and_push (rhs2, type, worklist, stmt);
- return;
- }
-
- /* Casts between pointers and integer are escaping. */
- if (gimple_assign_cast_p (stmt))
- {
- type->mark_escape (escape_cast_int, stmt);
+ decl, worklist, 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);
+ if (gimple_code (stmt) == GIMPLE_ASSIGN)
+ check_definition_assign (decl, worklist);
}
/* Mark the types used by the inline-asm as escaping.
@@ -3149,45 +4201,121 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt,
{
srtype *type = decl->type;
- if (TREE_CODE (other) == SSA_NAME
- || DECL_P (other)
+ if (TREE_CODE (other) == SSA_NAME || DECL_P (other)
|| TREE_CODE (other) == INTEGER_CST)
{
- check_type_and_push (other, type, worklist, stmt);
+ check_type_and_push (other, decl, 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)
+ {
+ /* In Complete Struct Relayout, if lhs type is the same
+ as rhs type, we could return without any harm. */
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT)
+ return;
+
+ tree base;
+ bool indirect;
+ srtype *type1;
+ srfield *field;
+ bool realpart, imagpart, address;
+ bool escape_from_base = false;
+ if (!get_type_field (other, base, indirect, type1, field,
+ realpart, imagpart, address, escape_from_base))
+ {
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ /* Release INTEGER_TYPE cast to struct pointer. */
+ bool cast_from_int_ptr = current_function->is_safe_func && base
+ && find_decl (base) == NULL && POINTER_TYPE_P (TREE_TYPE (base))
+ && (TREE_CODE (inner_type (TREE_TYPE (base))) == INTEGER_TYPE);
+
+ /* Add a safe func mechanism. */
+ bool from_void_ptr_parm = current_function->is_safe_func
+ && TREE_CODE (base) == SSA_NAME && is_from_void_ptr_parm (base);
+
+ /* Release type is used by a type which escapes. */
+ if (escape_from_base || cast_from_int_ptr || from_void_ptr_parm)
+ return;
+ }
+ type->mark_escape (escape_cast_another_ptr, stmt);
+ }
+
return;
}
- tree t = TREE_TYPE (other);
- if (!handled_type (t))
+ if (t1)
+ t1->mark_escape (escape_cast_another_ptr, stmt);
+
+ type->mark_escape (escape_cast_another_ptr, stmt);
+}
+
+
+/* Get the expr base. */
+
+void
+get_base (tree &base, tree expr)
+{
+ if (TREE_CODE (expr) == MEM_REF)
+ base = TREE_OPERAND (expr, 0);
+ else if (TREE_CODE (expr) == COMPONENT_REF)
+ {
+ base = TREE_OPERAND (expr, 0);
+ base = (TREE_CODE (base) == MEM_REF) ? TREE_OPERAND (base, 0) : base;
+ }
+ else if (TREE_CODE (expr) == ADDR_EXPR)
+ base = TREE_OPERAND (expr, 0);
+}
+
+/* Check whether the number of pointer layers of exprs is equal,
+ marking unequals as escape. */
+
+void
+ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple *stmt)
+{
+ if (current_mode != STRUCT_REORDER_FIELDS || current_function->is_safe_func
+ || !(POINTER_TYPE_P (TREE_TYPE (a_expr)))
+ || !(POINTER_TYPE_P (TREE_TYPE (b_expr)))
+ || !handled_type (TREE_TYPE (a_expr))
+ || !handled_type (TREE_TYPE (b_expr)))
+ return;
+
+ tree a_base = a_expr;
+ tree b_base = b_expr;
+ get_base (a_base, a_expr);
+ get_base (b_base, b_expr);
+
+ srdecl *a = find_decl (a_base);
+ srdecl *b = find_decl (b_base);
+ if (a && b == NULL && TREE_CODE (b_expr) != INTEGER_CST)
{
- type->mark_escape (escape_cast_another_ptr, stmt);
+ a->type->mark_escape (escape_cast_another_ptr, stmt);
return;
}
-
- srtype *t1 = find_type (inner_type (t));
- if (t1 == type)
+ else if (b && a == NULL && TREE_CODE (a_expr) != INTEGER_CST)
{
- /* In Complete Struct Relayout, if lhs type is the same
- as rhs type, we could return without any harm. */
- if (current_mode == COMPLETE_STRUCT_RELAYOUT)
- return;
-
- 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);
-
+ b->type->mark_escape (escape_cast_another_ptr, stmt);
return;
}
+ else if (a == NULL && b == NULL)
+ return;
- if (t1)
- t1->mark_escape (escape_cast_another_ptr, stmt);
+ if (cmp_ptr_layers (TREE_TYPE (a_expr), TREE_TYPE (b_expr)))
+ return;
- type->mark_escape (escape_cast_another_ptr, stmt);
+ if (a)
+ a->type->mark_escape (escape_cast_another_ptr, stmt);
+ if (b)
+ b->type->mark_escape (escape_cast_another_ptr, stmt);
}
void
@@ -3205,7 +4333,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
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);
+ check_type_and_push (gimple_phi_result (stmt), decl, worklist, stmt);
return;
}
@@ -3221,10 +4349,15 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
tree rhs2 = gimple_cond_rhs (stmt);
tree orhs = rhs1;
enum tree_code code = gimple_cond_code (stmt);
- if (code != EQ_EXPR && code != NE_EXPR
- && (current_mode != COMPLETE_STRUCT_RELAYOUT
- || (code != LT_EXPR && code != LE_EXPR
- && code != GT_EXPR && code != GE_EXPR)))
+ if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR))
+ || (current_mode == COMPLETE_STRUCT_RELAYOUT
+ && (code != EQ_EXPR && code != NE_EXPR
+ && code != LT_EXPR && code != LE_EXPR
+ && code != GT_EXPR && code != GE_EXPR))
+ || (current_mode == STRUCT_REORDER_FIELDS
+ && (code != EQ_EXPR && code != NE_EXPR
+ && code != LT_EXPR && code != LE_EXPR
+ && code != GT_EXPR && code != GE_EXPR)))
{
mark_expr_escape (rhs1, escape_non_eq, stmt);
mark_expr_escape (rhs2, escape_non_eq, stmt);
@@ -3235,7 +4368,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
return;
if (TREE_CODE (orhs) != SSA_NAME)
mark_expr_escape (rhs1, escape_non_eq, stmt);
- check_type_and_push (orhs, type, worklist, stmt);
+ check_type_and_push (orhs, decl, worklist, stmt);
return;
}
@@ -3254,9 +4387,14 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
tree rhs2 = gimple_assign_rhs2 (stmt);
tree orhs = rhs1;
enum tree_code code = gimple_assign_rhs_code (stmt);
- if (code != EQ_EXPR && code != NE_EXPR
- && (current_mode != COMPLETE_STRUCT_RELAYOUT
- || (code != LT_EXPR && code != LE_EXPR
+ if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR))
+ || (current_mode == COMPLETE_STRUCT_RELAYOUT
+ && (code != EQ_EXPR && code != NE_EXPR
+ && code != LT_EXPR && code != LE_EXPR
+ && code != GT_EXPR && code != GE_EXPR))
+ || (current_mode == STRUCT_REORDER_FIELDS
+ && (code != EQ_EXPR && code != NE_EXPR
+ && code != LT_EXPR && code != LE_EXPR
&& code != GT_EXPR && code != GE_EXPR)))
{
mark_expr_escape (rhs1, escape_non_eq, stmt);
@@ -3268,7 +4406,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
return;
if (TREE_CODE (orhs) != SSA_NAME)
mark_expr_escape (rhs1, escape_non_eq, stmt);
- check_type_and_push (orhs, type, worklist, stmt);
+ check_type_and_push (orhs, decl, worklist, stmt);
return;
}
@@ -3282,6 +4420,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
check_other_side (decl, lhs, stmt, worklist);
return;
}
+ check_ptr_layers (lhs, rhs, stmt);
}
if (is_gimple_assign (stmt)
@@ -3291,9 +4430,26 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *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)))
+ check_ptr_layers (lhs, decl->decl, stmt);
+ /* Specify the correct size for the multi-layer pointer. */
+ if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type)
+ ? TYPE_SIZE_UNIT (decl->orig_type)
+ : TYPE_SIZE_UNIT (type->type)))
type->mark_escape (escape_non_multiply_size, stmt);
}
+
+ if (is_gimple_assign (stmt)
+ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree other = rhs1 == decl->decl ? rhs2 : rhs1;
+
+ check_other_side (decl, other, stmt, worklist);
+ check_ptr_layers (decl->decl, other, stmt);
+ return;
+ }
+
}
/*
@@ -3360,17 +4516,43 @@ ipa_struct_reorg::record_function (cgraph_node *node)
if (DECL_PRESERVE_P (node->decl))
escapes = escape_marked_as_used;
else if (!node->local)
- escapes = escape_visible_function;
+ {
+ if (current_mode != STRUCT_REORDER_FIELDS)
+ escapes = escape_visible_function;
+ if (current_mode == STRUCT_REORDER_FIELDS && node->externally_visible)
+ 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;
+
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ if (!opt_for_fn (node->decl, flag_ipa_reorder_fields))
+ escapes = escape_non_optimize;
+ }
+ else if (current_mode == NORMAL || current_mode == COMPLETE_STRUCT_RELAYOUT)
+ {
+ if (!opt_for_fn (node->decl, flag_ipa_struct_reorg))
+ escapes = escape_non_optimize;
+ }
basic_block bb;
gimple_stmt_iterator si;
+ /* Add a safe func mechanism. */
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ current_function->is_safe_func = safe_functions.contains (node);
+ if (dump_file)
+ {
+ fprintf (dump_file, "\nfunction %s/%u: is_safe_func = %d\n",
+ node->name (), node->order,
+ current_function->is_safe_func);
+ }
+ }
+
/* Record the static chain decl. */
if (fn->static_chain_decl)
{
@@ -3503,6 +4685,42 @@ ipa_struct_reorg::record_function (cgraph_node *node)
return sfn;
}
+
+/* For a function that contains the void* parameter and passes the structure
+ pointer, check whether the function uses the input node safely.
+ For these functions, the void* parameter and related ssa_name are not
+ recorded in record_function (), and the input structure type is not escaped.
+*/
+
+void
+ipa_struct_reorg::record_safe_func_with_void_ptr_parm ()
+{
+ cgraph_node *node = NULL;
+ FOR_EACH_FUNCTION (node)
+ {
+ if (!node->real_symbol_p ())
+ continue;
+ if (node->definition)
+ {
+ if (!node->has_gimple_body_p () || node->inlined_to)
+ continue;
+ node->get_body ();
+ function *fn = DECL_STRUCT_FUNCTION (node->decl);
+ if (!fn)
+ continue;
+ push_cfun (fn);
+ if (is_safe_func_with_void_ptr_parm (node))
+ {
+ safe_functions.add (node);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nfunction %s/%u is safe function.\n",
+ node->name (), node->order);
+ }
+ pop_cfun ();
+ }
+ }
+}
+
/* Record all accesses for all types including global variables. */
void
@@ -3534,6 +4752,10 @@ ipa_struct_reorg::record_accesses (void)
record_var (var->decl, escapes);
}
+ /* Add a safe func mechanism. */
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ record_safe_func_with_void_ptr_parm ();
+
FOR_EACH_FUNCTION (cnode)
{
if (!cnode->real_symbol_p ())
@@ -3552,11 +4774,14 @@ ipa_struct_reorg::record_accesses (void)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "all types (before pruning):\n");
+ fprintf (dump_file, "\n");
+ fprintf (dump_file, "==============================================\n\n");
+ fprintf (dump_file, "======== all types (before pruning): ========\n\n");
dump_types (dump_file);
- fprintf (dump_file, "all functions (before pruning):\n");
+ fprintf (dump_file, "======= all functions (before pruning): =======\n");
dump_functions (dump_file);
}
+ /* If record_var () is called later, new types will not be recorded. */
done_recording = true;
}
@@ -3580,6 +4805,7 @@ ipa_struct_reorg::walk_field_for_cycles (srtype *type)
{
if (!field->type)
;
+ /* If there are two members of the same structure pointer type? */
else if (field->type->visited
|| walk_field_for_cycles (field->type))
{
@@ -3658,22 +4884,113 @@ ipa_struct_reorg::propagate_escape (void)
} while (changed);
}
+/* If the original type (with members) has escaped, corresponding to the
+ struct pointer type (empty member) in the structure fields
+ should also marked as escape. */
+
+void
+ipa_struct_reorg::propagate_escape_via_original (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ for (unsigned j = 0; j < types.length (); j++)
+ {
+ const char *type1 = get_type_name (types[i]->type);
+ const char *type2 = get_type_name (types[j]->type);
+ if (type1 == NULL || type2 == NULL)
+ continue;
+ if (type1 == type2 && types[j]->has_escaped ())
+ {
+ if (!types[i]->has_escaped ())
+ types[i]->mark_escape (escape_via_orig_escape, NULL);
+ break;
+ }
+ }
+ }
+}
+
+/* Marks the fileds as empty and does not have the original structure type
+ is escape. */
+
+void
+ipa_struct_reorg::propagate_escape_via_empty_with_no_original (void)
+{
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ if (types[i]->fields.length () == 0)
+ {
+ for (unsigned j = 0; j < types.length (); j++)
+ {
+ if (i != j && types[j]->fields.length ())
+ {
+ const char *type1 = get_type_name (types[i]->type);
+ const char *type2 = get_type_name (types[j]->type);
+ if (type1 != NULL && type2 != NULL && type1 == type2)
+ break;
+ }
+ if (j == types.length () - 1)
+ types[i]->mark_escape (escape_via_empty_no_orig, NULL);
+ }
+ }
+ }
+}
+
+/* Escape propagation is performed on types that escape through external
+ functions. */
+
+void
+ipa_struct_reorg::propagate_escape_via_ext_func_types (void)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\n propagate_escape_via_ext_func_types: \n\n");
+ unsigned i = 0;
+ hash_set<srtype *> visited_types;
+ while (i < ext_func_types.length ())
+ {
+ visited_types.add (ext_func_types[i]);
+ unsigned j = 0;
+ srfield * field;
+ FOR_EACH_VEC_ELT (ext_func_types[i]->fields, j, field)
+ {
+ if (field->type)
+ {
+ if (!field->type->has_escaped ())
+ field->type->mark_escape (escape_dependent_type_escapes, NULL);
+ if (!visited_types.contains (field->type))
+ ext_func_types.safe_push (field->type);
+ }
+ }
+ i++;
+ }
+}
+
/* Prune the escaped types and their decls from what was recorded. */
void
ipa_struct_reorg::prune_escaped_types (void)
{
- if (current_mode != COMPLETE_STRUCT_RELAYOUT)
+ if (current_mode != COMPLETE_STRUCT_RELAYOUT
+ && current_mode != STRUCT_REORDER_FIELDS)
{
+ /* Detect recusive types and mark them as escaping. */
detect_cycles ();
+ /* If contains or is contained by the escape type,
+ mark them as escaping. */
propagate_escape ();
}
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ propagate_escape_via_original ();
+ propagate_escape_via_empty_with_no_original ();
+ propagate_escape_via_ext_func_types ();
+ }
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "all types (after prop but before pruning):\n");
+ fprintf (dump_file, "==============================================\n\n");
+ fprintf (dump_file, "all types (after prop but before pruning): \n\n");
dump_types (dump_file);
- fprintf (dump_file, "all functions (after prop but before pruning):\n");
+ fprintf (dump_file, "all functions (after prop but before pruning): \n");
dump_functions (dump_file);
}
@@ -3721,7 +5038,8 @@ ipa_struct_reorg::prune_escaped_types (void)
/* Prune functions which don't refer to any variables any more. */
if (function->args.is_empty ()
&& function->decls.is_empty ()
- && function->globals.is_empty ())
+ && function->globals.is_empty ()
+ && current_mode != STRUCT_REORDER_FIELDS)
{
delete function;
functions.ordered_remove (i);
@@ -3746,24 +5064,31 @@ ipa_struct_reorg::prune_escaped_types (void)
/* Prune types that escape, all references to those types
will have been removed in the above loops. */
- for (unsigned i = 0; i < types.length ();)
+ /* The escape type is not deleted in STRUCT_REORDER_FIELDS,
+ Then the type that contains the escaped type fields
+ can find complete information. */
+ if (current_mode != STRUCT_REORDER_FIELDS)
{
- srtype *type = types[i];
- if (type->has_escaped ())
+ for (unsigned i = 0; i < types.length ();)
{
- /* All references to this type should have been removed now. */
- delete type;
- types.ordered_remove (i);
+ 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++;
}
- else
- i++;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "all types (after pruning):\n");
+ fprintf (dump_file, "==============================================\n\n");
+ fprintf (dump_file, "========= all types (after pruning): =========\n\n");
dump_types (dump_file);
- fprintf (dump_file, "all functions (after pruning):\n");
+ fprintf (dump_file, "======== all functions (after pruning): ========\n");
dump_functions (dump_file);
}
}
@@ -3790,6 +5115,26 @@ ipa_struct_reorg::create_new_types (void)
for (unsigned i = 0; i < types.length (); i++)
newtypes += types[i]->create_new_type ();
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ for (unsigned i = 0; i < types.length (); i++)
+ {
+ auto_vec <tree> *fields = fields_to_finish.get (types[i]->type);
+ if (fields)
+ {
+ for (unsigned j = 0; j < fields->length (); j++)
+ {
+ tree field = (*fields)[j];
+ TREE_TYPE (field)
+ = reconstruct_complex_type (TREE_TYPE (field),
+ types[i]->newtype[0]);
+ }
+ }
+ }
+ for (unsigned i = 0; i < types.length (); i++)
+ layout_type (types[i]->newtype[0]);
+ }
+
if (dump_file)
{
if (newtypes)
@@ -3894,7 +5239,8 @@ ipa_struct_reorg::create_new_args (cgraph_node *new_node)
char *name = NULL;
if (tname)
{
- name = concat (tname, ".reorg.0", NULL);
+ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS
+ ? ".reorder.0" : ".reorg.0", NULL);
new_name = get_identifier (name);
free (name);
}
@@ -3980,9 +5326,10 @@ ipa_struct_reorg::create_new_functions (void)
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 = node->create_version_clone_with_body (
+ vNULL, NULL, NULL, NULL, NULL,
+ current_mode == STRUCT_REORDER_FIELDS
+ ? "struct_reorder" : "struct_reorg");
new_node->can_change_signature = node->can_change_signature;
new_node->make_local ();
f->newnode = new_node;
@@ -4026,6 +5373,7 @@ ipa_struct_reorg::rewrite_expr (tree expr,
srfield *f;
bool realpart, imagpart;
bool address;
+ bool escape_from_base = false;
tree newbase[max_split];
memset (newexpr, 0, sizeof (tree[max_split]));
@@ -4043,8 +5391,8 @@ ipa_struct_reorg::rewrite_expr (tree expr,
return true;
}
- if (!get_type_field (expr, base, indirect, t, f,
- realpart, imagpart, address))
+ if (!get_type_field (expr, base, indirect, t, f, realpart, imagpart,
+ address, escape_from_base))
return false;
/* If the type is not changed, then just return false. */
@@ -4107,7 +5455,38 @@ ipa_struct_reorg::rewrite_expr (tree expr,
if (address)
newbase1 = build_fold_addr_expr (newbase1);
if (indirect)
- newbase1 = build_simple_mem_ref (newbase1);
+ {
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ /* Supports the MEM_REF offset.
+ _1 = MEM[(struct arc *)ap_1 + 72B].flow;
+ Old rewrite: _1 = ap.reorder.0_8->flow;
+ New rewrite: _1
+ = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow;
+ */
+ HOST_WIDE_INT offset_tmp = 0;
+ HOST_WIDE_INT mem_offset = 0;
+ bool realpart_tmp = false;
+ bool imagpart_tmp = false;
+ tree accesstype_tmp = NULL_TREE;
+ tree num = NULL_TREE;
+ get_ref_base_and_offset (expr, offset_tmp,
+ realpart_tmp, imagpart_tmp,
+ accesstype_tmp, &num);
+
+ tree ptype = TREE_TYPE (newbase1);
+ /* Specify the correct size for the multi-layer pointer. */
+ tree size = isptrptr (ptype) ? TYPE_SIZE_UNIT (ptype) :
+ TYPE_SIZE_UNIT (inner_type (ptype));
+ mem_offset = (num != NULL)
+ ? TREE_INT_CST_LOW (num) * tree_to_shwi (size)
+ : 0;
+ newbase1 = build2 (MEM_REF, TREE_TYPE (ptype), newbase1,
+ build_int_cst (ptype, mem_offset));
+ }
+ else
+ newbase1 = build_simple_mem_ref (newbase1);
+ }
newexpr[i] = build3 (COMPONENT_REF, TREE_TYPE (f->newfield[i]),
newbase1, f->newfield[i], NULL_TREE);
if (imagpart)
@@ -4151,8 +5530,12 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
return remove;
}
- if (gimple_assign_rhs_code (stmt) == EQ_EXPR
- || gimple_assign_rhs_code (stmt) == NE_EXPR)
+ if ((current_mode != STRUCT_REORDER_FIELDS
+ && (gimple_assign_rhs_code (stmt) == EQ_EXPR
+ || gimple_assign_rhs_code (stmt) == NE_EXPR))
+ || (current_mode == STRUCT_REORDER_FIELDS
+ && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
+ == tcc_comparison)))
{
tree rhs1 = gimple_assign_rhs1 (stmt);
tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -4160,6 +5543,10 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
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 (current_mode == STRUCT_REORDER_FIELDS
+ && rhs_code != EQ_EXPR && rhs_code != NE_EXPR)
+ code = rhs_code;
+
if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2))
return false;
tree newexpr = NULL_TREE;
@@ -4201,20 +5588,78 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
internal_error (
"The rhs of pointer is not a multiplicate and it slips through");
- num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num);
+ /* Add the judgment of num, support for POINTER_DIFF_EXPR.
+ _6 = _4 + _5;
+ _5 = (long unsigned int) _3;
+ _3 = _1 - old_2. */
+ if (current_mode != STRUCT_REORDER_FIELDS
+ || (current_mode == STRUCT_REORDER_FIELDS && (num != NULL)))
+ 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);
+ if (num != NULL)
+ {
+ 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);
+ }
+ else
+ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR,
+ newrhs[i], rhs2);
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
remove = true;
}
return remove;
}
+
+ /* Support POINTER_DIFF_EXPR rewriting. */
+ if (current_mode == STRUCT_REORDER_FIELDS
+ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR)
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree newrhs1[max_split];
+ tree newrhs2[max_split];
+
+ bool r1 = rewrite_expr (rhs1, newrhs1);
+ bool r2 = rewrite_expr (rhs2, newrhs2);
+
+ if (r1 != r2)
+ {
+ /* Handle NULL pointer specially. */
+ if (r1 && !r2 && integer_zerop (rhs2))
+ {
+ r2 = true;
+ for (unsigned i = 0; i < max_split && newrhs1[i]; i++)
+ newrhs2[i] = fold_convert (TREE_TYPE (newrhs1[i]), rhs2);
+ }
+ else if (r2 && !r1 && integer_zerop (rhs1))
+ {
+ r1 = true;
+ for (unsigned i = 0; i < max_split && newrhs2[i]; i++)
+ newrhs1[i] = fold_convert (TREE_TYPE (newrhs2[i]), rhs1);
+ }
+ else
+ return false;
+ }
+ else if (!r1 && !r2)
+ return false;
+
+ /* The two operands always have pointer/reference type. */
+ for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++)
+ {
+ gimple_assign_set_rhs1 (stmt, newrhs1[i]);
+ gimple_assign_set_rhs2 (stmt, newrhs2[i]);
+ update_stmt (stmt);
+ }
+ remove = false;
+ return remove;
+ }
+
if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
{
tree lhs = gimple_assign_lhs (stmt);
@@ -4222,9 +5667,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "rewriting statement:\n");
+ fprintf (dump_file, "\nrewriting stamtenet:\n");
print_gimple_stmt (dump_file, stmt, 0);
- fprintf (dump_file, "\n");
}
tree newlhs[max_split];
tree newrhs[max_split];
@@ -4271,7 +5715,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
if (!decl || !decl->type)
return false;
srtype *type = decl->type;
- tree num = allocate_size (type, stmt);
+ tree num = allocate_size (type, decl, stmt);
gcc_assert (num);
memset (newrhs1, 0, sizeof (newrhs1));
@@ -4291,7 +5735,10 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
/* Go through each new lhs. */
for (unsigned i = 0; i < max_split && decl->newdecl[i]; i++)
{
- tree newsize = TYPE_SIZE_UNIT (type->type);
+ /* Specify the correct size for the multi-layer pointer. */
+ tree newsize = isptrptr (decl->orig_type)
+ ? TYPE_SIZE_UNIT (decl->orig_type)
+ : TYPE_SIZE_UNIT (type->newtype[i]);
gimple *g;
/* Every allocation except for calloc needs
the size multiplied out. */
@@ -4352,6 +5799,23 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
gcc_assert (node);
srfunction *f = find_function (node);
+ /* Add a safe func mechanism. */
+ if (current_mode == STRUCT_REORDER_FIELDS && f && f->is_safe_func)
+ {
+ 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;
+ }
+ return false;
+ }
+
/* Did not find the function or had not cloned it return saying don't
change the function call. */
if (!f || !f->newf)
@@ -4437,7 +5901,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
&& TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
- gsi_replace (gsi, new_stmt, false);
+ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
/* We need to defer cleaning EH info on the new statement to
fixup-cfg. We may not have dominator information at this point
@@ -4450,7 +5914,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
add_stmt_to_eh_lp (new_stmt, lp_nr);
}
- return false;
+ return true;
}
/* Rewrite the conditional statement STMT. Return TRUE if the
@@ -4462,50 +5926,52 @@ 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)
+ if ((current_mode != STRUCT_REORDER_FIELDS
+ && (rhs_code != EQ_EXPR && rhs_code != NE_EXPR))
+ || (current_mode == STRUCT_REORDER_FIELDS
+ && TREE_CODE_CLASS (rhs_code) != tcc_comparison))
return false;
- tree rhs1 = gimple_cond_lhs (stmt);
- tree rhs2 = gimple_cond_rhs (stmt);
+ tree lhs = gimple_cond_lhs (stmt);
+ tree rhs = gimple_cond_rhs (stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "COND: Rewriting\n");
+ fprintf (dump_file, "\nCOND: Rewriting\n");
print_gimple_stmt (dump_file, stmt, 0);
+ print_generic_expr (dump_file, lhs);
fprintf (dump_file, "\n");
- print_generic_expr (dump_file, rhs1);
- fprintf (dump_file, "\n");
- print_generic_expr (dump_file, rhs2);
+ print_generic_expr (dump_file, rhs);
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))
+ 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");
+ fprintf (dump_file, "Did nothing to statement.\n");
return false;
}
- tree newexpr = NULL_TREE;
- for (unsigned i = 0; i < max_split && newrhs1[i]; i++)
+ /* Old rewrite: if (x_1 != 0B)
+ -> _1 = x.reorder.0_1 != 0B; if (_1 != 1)
+ The logic is incorrect.
+ New rewrite: if (x_1 != 0B)
+ -> if (x.reorder.0_1 != 0B); */
+ for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[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);
+ if (newlhs[i])
+ gimple_cond_set_lhs (stmt, newlhs[i]);
+ if (newrhs[i])
+ gimple_cond_set_rhs (stmt, newrhs[i]);
update_stmt (stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "replaced with:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
}
return false;
}
@@ -4516,6 +5982,9 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi)
bool
ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *)
{
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ /* Delete debug gimple now. */
+ return true;
bool remove = false;
if (gimple_debug_bind_p (stmt))
{
@@ -4568,7 +6037,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "\nrewriting PHI:");
+ fprintf (dump_file, "\nrewriting PHI:\n");
print_gimple_stmt (dump_file, phi, 0);
}
@@ -4579,7 +6048,15 @@ ipa_struct_reorg::rewrite_phi (gphi *phi)
{
tree newrhs[max_split];
phi_arg_d rhs = *gimple_phi_arg (phi, i);
- rewrite_expr (rhs.def, newrhs);
+
+ /* Handling the NULL phi Node. */
+ bool r = rewrite_expr (rhs.def, newrhs);
+ if (!r && integer_zerop (rhs.def))
+ {
+ for (unsigned i = 0; i < max_split && newlhs[i]; i++)
+ newrhs[i] = fold_convert (TREE_TYPE (newlhs[i]), rhs.def);
+ }
+
for (unsigned j = 0; j < max_split && newlhs[j]; j++)
{
SET_PHI_ARG_DEF (newphi[j], i, newrhs[j]);
@@ -4590,7 +6067,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "\ninto\n:");
+ fprintf (dump_file, "into:\n");
for (unsigned i = 0; i < max_split && newlhs[i]; i++)
{
print_gimple_stmt (dump_file, newphi[i], 0);
@@ -4663,12 +6140,59 @@ ipa_struct_reorg::rewrite_functions (void)
/* Create new types, if we did not create any new types,
then don't rewrite any accesses. */
if (!create_new_types ())
- return 0;
+ {
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ for (unsigned i = 0; i < functions.length (); i++)
+ {
+ srfunction *f = functions[i];
+ cgraph_node *node = f->node;
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nNo rewrite:\n");
+ dump_function_to_file (current_function_decl, dump_file,
+ dump_flags | TDF_VOPS);
+ }
+ pop_cfun ();
+ }
+ }
+ return 0;
+ }
+
+ if (current_mode == STRUCT_REORDER_FIELDS && dump_file)
+ {
+ fprintf (dump_file, "=========== all created newtypes: ===========\n\n");
+ dump_newtypes (dump_file);
+ }
if (functions.length ())
{
retval = TODO_remove_functions;
create_new_functions ();
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ prune_escaped_types ();
+ }
+ }
+
+ if (current_mode == STRUCT_REORDER_FIELDS)
+ {
+ for (unsigned i = 0; i < functions.length (); i++)
+ {
+ srfunction *f = functions[i];
+ cgraph_node *node = f->node;
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n",
+ i, f->node->name ());
+ if (current_function_decl)
+ dump_function_to_file (current_function_decl, dump_file,
+ dump_flags | TDF_VOPS);
+ }
+ pop_cfun ();
+ }
}
create_new_decls ();
@@ -4691,9 +6215,12 @@ ipa_struct_reorg::rewrite_functions (void)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "\nBefore rewrite:\n");
+ fprintf (dump_file, "\nBefore rewrite: %dth_%s\n",
+ i, f->node->name ());
dump_function_to_file (current_function_decl, dump_file,
dump_flags | TDF_VOPS);
+ fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n",
+ i, f->node->name ());
}
FOR_EACH_BB_FN (bb, cfun)
{
@@ -4761,9 +6288,10 @@ ipa_struct_reorg::rewrite_functions (void)
free_dominance_info (CDI_DOMINATORS);
- if (dump_file && (dump_flags & TDF_DETAILS))
+ if (dump_file)
{
- fprintf (dump_file, "\nAfter rewrite:\n");
+ fprintf (dump_file, "\nAfter rewrite: %dth_%s\n",
+ i, f->node->name ());
dump_function_to_file (current_function_decl, dump_file,
dump_flags | TDF_VOPS);
}
@@ -4809,16 +6337,21 @@ ipa_struct_reorg::execute (enum srmode mode)
{
unsigned int ret = 0;
- if (mode == NORMAL)
+ if (dump_file)
+ fprintf (dump_file, "\n\n====== ipa_struct_reorg level %d ======\n\n",
+ mode);
+
+ if (mode == NORMAL || mode == STRUCT_REORDER_FIELDS)
{
- current_mode = NORMAL;
- /* FIXME: If there is a top-level inline-asm,
+ current_mode = mode;
+ /* 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 ();
+ if (current_mode == NORMAL)
+ analyze_types ();
ret = rewrite_functions ();
}
@@ -4881,7 +6414,55 @@ pass_ipa_struct_reorg::gate (function *)
&& flag_lto_partition == LTO_PARTITION_ONE
/* Only enable struct optimizations in C since other
languages' grammar forbid. */
- && lang_c_p ());
+ && lang_c_p ()
+ /* Only enable struct optimizations in lto or whole_program. */
+ && (in_lto_p || flag_whole_program));
+}
+
+const pass_data pass_data_ipa_reorder_fields =
+{
+ SIMPLE_IPA_PASS, // type
+ "reorder_fields", // name
+ OPTGROUP_NONE, // optinfo_flags
+ TV_IPA_REORDER_FIELDS, // tv_id
+ 0, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // todo_flags_start
+ 0, // todo_flags_finish
+};
+
+class pass_ipa_reorder_fields : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_reorder_fields (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_reorder_fields, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *);
+ virtual unsigned int execute (function *)
+ {
+ unsigned int ret = 0;
+ ret = ipa_struct_reorg ().execute (STRUCT_REORDER_FIELDS);
+ return ret;
+ }
+
+}; // class pass_ipa_reorder_fields
+
+bool
+pass_ipa_reorder_fields::gate (function *)
+{
+ return (optimize >= 3
+ && flag_ipa_reorder_fields
+ /* Don't bother doing anything if the program has errors. */
+ && !seen_error ()
+ && flag_lto_partition == LTO_PARTITION_ONE
+ /* Only enable struct optimizations in C since other
+ languages' grammar forbid. */
+ && lang_c_p ()
+ /* Only enable struct optimizations in lto or whole_program. */
+ && (in_lto_p || flag_whole_program));
}
} // anon namespace
@@ -4891,4 +6472,10 @@ 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
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_reorder_fields (gcc::context *ctxt)
+{
+ return new pass_ipa_reorder_fields (ctxt);
+}
diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
index ef7f4c780..6f85adeb4 100644
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
@@ -68,12 +68,14 @@ struct srfunction
auto_vec<srdecl *> args;
auto_vec<srdecl *> globals;
auto_vec_del<srdecl> decls;
- srdecl *record_decl (srtype *, tree, int arg);
+ srdecl *record_decl (srtype *, tree, int arg, tree orig_type = NULL);
srfunction *old;
cgraph_node *newnode;
srfunction *newf;
+ bool is_safe_func;
+
// Constructors
srfunction (cgraph_node *n);
@@ -184,6 +186,11 @@ struct srfield
void create_new_fields (tree newtype[max_split],
tree newfields[max_split],
tree newlast[max_split]);
+ void reorder_fields (tree newfields[max_split], tree newlast[max_split],
+ tree &field);
+ void create_new_reorder_fields (tree newtype[max_split],
+ tree newfields[max_split],
+ tree newlast[max_split]);
};
struct sraccess
@@ -221,8 +228,11 @@ struct srdecl
tree newdecl[max_split];
+ /* Auxiliary record complete original type information of the void* type. */
+ tree orig_type;
+
// Constructors
- srdecl (srtype *type, tree decl, int argumentnum = -1);
+ srdecl (srtype *type, tree decl, int argumentnum = -1, tree orgtype = NULL);
// Methods
void dump (FILE *file);
diff --git a/gcc/passes.def b/gcc/passes.def
index 9692066e4..bdc835b87 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -178,6 +178,7 @@ along with GCC; see the file COPYING3. If not see
compiled unit. */
INSERT_PASSES_AFTER (all_late_ipa_passes)
NEXT_PASS (pass_ipa_pta);
+ NEXT_PASS (pass_ipa_reorder_fields);
/* FIXME: this should be a normal IP pass. */
NEXT_PASS (pass_ipa_struct_reorg);
NEXT_PASS (pass_omp_simd_clone);
diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
index 3fe64047c..6fa529eee 100644
--- a/gcc/symbol-summary.h
+++ b/gcc/symbol-summary.h
@@ -105,7 +105,7 @@ protected:
{
/* In structure optimizatons, we call new to ensure that
the allocated memory is initialized to 0. */
- if (flag_ipa_struct_reorg)
+ if (flag_ipa_struct_reorg || flag_ipa_reorder_fields)
return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
: new T ();
@@ -122,7 +122,7 @@ protected:
ggc_delete (item);
else
{
- if (flag_ipa_struct_reorg)
+ if (flag_ipa_struct_reorg || flag_ipa_reorder_fields)
delete item;
else
m_allocator.remove (item);
diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c
new file mode 100644
index 000000000..b95be2dab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c
@@ -0,0 +1,75 @@
+// escape_instance_field, "Type escapes via a field of instance".
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+typedef struct network
+{
+ arc_p arcs;
+ arc_p sorted_arcs;
+ int x;
+ node_p nodes;
+ node_p stop_nodes;
+ node_t node;
+} network_t;
+
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+ network_t* net_add;
+ node_t node;
+};
+
+
+const int MAX = 100;
+
+/* let it escape_array, "Type is used in an array [not handled yet]". */
+network_t* net[2];
+
+int
+main ()
+{
+ net[0] = (network_t*) calloc (1, sizeof(network_t));
+ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
+
+ /* Contains an escape type and has structure instance field. */
+ net[0]->arcs->node = net[0]->node;
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c
new file mode 100644
index 000000000..3d243313b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c
@@ -0,0 +1,94 @@
+// Verify in escape_dependent_type_escapes,
+// the multi-layer dereference is rewriting correctly,and the memory access
+// is correct.
+
+// release
+// escape_dependent_type_escapes,
+// "Type uses a type which escapes or is used by a type which escapes"
+// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer"
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ arc_p arcs;
+ arc_p sorted_arcs;
+ int x;
+ node_p nodes;
+ node_p stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+ network_t* net_add;
+};
+
+
+const int MAX = 100;
+
+/* let it escape_array, "Type is used in an array [not handled yet]". */
+network_t* net[2];
+arc_p stop_arcs = NULL;
+
+int
+main ()
+{
+ net[0] = (network_t*) calloc (1, sizeof(network_t));
+ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
+ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
+
+ net[0]->arcs->id = 100;
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ net[0]->arcs->id = net[0]->arcs->id + 2;
+ stop_arcs->cost = net[0]->arcs->id / 2;
+ stop_arcs->net_add = net[0];
+ printf("stop_arcs->cost = %ld\n", stop_arcs->cost);
+ net[0]->arcs++;
+ stop_arcs++;
+ }
+
+ if( net[1] != 0 && stop_arcs != 0)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c
new file mode 100644
index 000000000..faaf1e3a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c
@@ -0,0 +1,24 @@
+/* check_ptr_layers bugfix.*/
+/* { dg-do compile } */
+struct {
+ char a;
+} **b = 0, *e = 0;
+long c;
+char d = 9;
+int f;
+
+void g()
+{
+ for (; f;)
+ if (c)
+ (*e).a++;
+ if (!d)
+ for (;;)
+ b &&c;
+}
+int
+main()
+{
+ g();
+}
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c
new file mode 100644
index 000000000..886706ae9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c
@@ -0,0 +1,82 @@
+// bugfix:
+// Common members do not need to reconstruct.
+// Otherwise, eg:int* -> int** and void* -> void**.
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t* cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t** org_cost;
+};
+
+struct a
+{
+ int t;
+ int t1;
+};
+
+__attribute__((noinline)) int
+f(int i, int j)
+{
+ struct a *t = NULL;
+ struct a t1 = {i, j};
+ t = &t1;
+ auto int g(void) __attribute__((noinline));
+ int g(void)
+ {
+ return t->t + t->t1;
+ }
+ return g();
+}
+
+arc_t **ap = NULL;
+const int MAX = 100;
+
+int
+main()
+{
+ if (f(1, 2) != 3)
+ {
+ abort ();
+ }
+ ap = (arc_t**) malloc(MAX * sizeof(arc_t*));
+ (*ap)[0].id = 300;
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c
new file mode 100644
index 000000000..f3785f392
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MallocOrDie(x) sre_malloc((x))
+
+struct gki_elem {
+ char *key;
+ int idx;
+ struct gki_elem *nxt;
+};
+
+typedef struct {
+ struct gki_elem **table;
+
+ int primelevel;
+ int nhash;
+ int nkeys;
+} GKI;
+
+void
+Die(char *format, ...)
+{
+ exit(1);
+}
+
+void *
+sre_malloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc (size)) == NULL)
+ {
+ Die("malloc of %ld bytes failed", size);
+ }
+ return ptr;
+}
+
+
+__attribute__((noinline)) int
+GKIStoreKey(GKI *hash, char *key)
+{
+ hash->table[0] = MallocOrDie(sizeof(struct gki_elem));
+}
+
+int
+main ()
+{
+ GKI *hash;
+ char *key;
+ GKIStoreKey(hash, key);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c
new file mode 100644
index 000000000..1415d759a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c
@@ -0,0 +1,60 @@
+// verify newarc[cmp-1].flow
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+arc_p ap = NULL;
+
+int
+main ()
+{
+ ap = (arc_p) calloc(MAX, sizeof(arc_t));
+ printf("%d\n", ap[0].id);
+ for (int i = 1; i < MAX; i++)
+ {
+ ap[i-1].id = 500;
+ }
+ printf("%d\n", ap[0].id);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c
new file mode 100644
index 000000000..003da0b57
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c
@@ -0,0 +1,83 @@
+// release type is used by a type which escapes.
+// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer"
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ arc_p arcs;
+ arc_p sorted_arcs;
+ int x;
+ node_p nodes;
+ node_p stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+network_t* net = NULL;
+arc_p stop_arcs = NULL;
+int cnt = 0;
+
+int
+main ()
+{
+ net = (network_t*) calloc (1, 20);
+ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
+ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
+ if(!(net->arcs))
+ {
+ return -1;
+ }
+
+ for( int i = 0; i < MAX; i++, net->arcs = stop_arcs)
+ {
+ cnt++;
+ }
+
+ net = (network_t*) calloc (1, 20);
+ if( !(net->arcs) )
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c
new file mode 100644
index 000000000..84a34f241
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-shared" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ int x;
+ arc_p arcs, sorted_arcs;
+ node_p nodes, stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+extern int bcf_sr_add_reader (network_t *);
+extern int bcf_hdr_dup (arc_p);
+
+int
+test ()
+{
+ network_t *net = (network_t *) calloc (1, 20);
+
+ if (!bcf_sr_add_reader(net))
+ printf("error");
+ arc_p arc = net->nodes->basic_arc;
+ if(!bcf_hdr_dup(arc))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c
new file mode 100644
index 000000000..10dcf098c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c
@@ -0,0 +1,72 @@
+// release escape_cast_another_ptr, "Type escapes a cast to a different pointer"
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+typedef int cmp_t(const void *, const void *);
+
+__attribute__((noinline)) void
+spec_qsort(void *a, cmp_t *cmp)
+{
+ char *pb = NULL;
+ while (cmp(pb, a))
+ {
+ pb += 1;
+ }
+}
+
+static int arc_compare( arc_t **a1, int a2 )
+{
+ if( (*a1)->id < a2 )
+ {
+ return -1;
+ }
+ return 1;
+}
+
+int
+main()
+{
+ spec_qsort(NULL, (int (*)(const void *, const void *))arc_compare);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c
new file mode 100644
index 000000000..8d1a9a114
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c
@@ -0,0 +1,58 @@
+/* Supports the MEM_REF offset.
+ _1 = MEM[(struct arc *)ap_4 + 72B].flow;
+ Old rewrite:_1 = ap.reorder.0_8->flow;
+ New rewrite:_1 = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow. */
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+int
+main ()
+{
+ const int MAX = 100;
+ /* A similar scenario can be reproduced only by using local variables. */
+ arc_p ap = NULL;
+ ap = (arc_p) calloc(MAX, sizeof(arc_t));
+ printf("%d\n", ap[1].flow);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c
new file mode 100644
index 000000000..23765fc56
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct T_HASH_ENTRY
+{
+ unsigned int hash;
+ unsigned int klen;
+ char *key;
+} iHashEntry;
+
+typedef struct T_HASH
+{
+ unsigned int size;
+ unsigned int fill;
+ unsigned int keys;
+
+ iHashEntry **array;
+} uHash;
+
+uHash *retval;
+
+int
+main() {
+ retval->array = (iHashEntry **)calloc(sizeof(iHashEntry *), retval->size);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c
new file mode 100644
index 000000000..54e737ee8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c
@@ -0,0 +1,109 @@
+// For testing:
+/*
+Compile options: gcc -O3 -g
+-flto -flto-partition=one -fipa-reorder-fields -fipa-struct-reorg
+-v -save-temps -fdump-ipa-all-details test.c -o test
+
+in COMPLETE_STRUCT_RELAYOUT pass:
+N type: struct node.reorder.0 new = "Type escapes a cast to a different pointer"
+copy$head_26 = test_arc.reorder.0_49->head;
+
+type : struct arc.reorder.0(1599) {
+fields = {
+field (5382) {type = cost_t}
+field (5383) {type = struct node.reorder.0 *} // but node has escaped.
+field (5384) {type = struct node.reorder.0 *}
+field (5386) {type = struct arc.reorder.0 *}
+field (5387) {type = struct arc.reorder.0 *}
+field (5388) {type = flow_t}
+field (5389) {type = cost_t}
+field (5381) {type = int}
+field (5385) {type = short int}
+}
+
+// The types of the two types are inconsistent after the rewriting.
+newarc_2(D)->tail = tail_1(D);
+vs
+struct_reorder.0_61(D)->tail = tail_1(D);
+*/
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ arc_p arcs;
+ arc_p sorted_arcs;
+ int x;
+ node_p nodes;
+ node_p stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+__attribute__((noinline)) void
+replace_weaker_arc( arc_t *newarc, node_t *tail, node_t *head)
+{
+ printf("test");
+}
+
+__attribute__((noinline)) int64_t
+switch_arcs(arc_t** deleted_arcs, arc_t* arcnew)
+{
+ int64_t count = 0;
+ arc_t *test_arc, copy;
+
+ if (!test_arc->ident)
+ {
+ copy = *test_arc;
+ count++;
+ *test_arc = arcnew[0];
+ replace_weaker_arc(arcnew, NULL, NULL);
+ }
+ return count;
+}
+
+int
+main ()
+{
+ switch_arcs(NULL, NULL);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c
new file mode 100644
index 000000000..2ae46fb31
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c
@@ -0,0 +1,87 @@
+// escape_cast_void, "Type escapes a cast to/from void*"
+// stop_393 = net.stop_nodes; void *stop;
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ arc_p arcs, sorted_arcs;
+ int x;
+ node_p nodes, stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+network_t* net = NULL;
+int cnt = 0;
+
+__attribute__((noinline)) int
+primal_feasible (network_t *net)
+{
+ void* stop;
+ node_t *node;
+
+ node = net->nodes;
+ stop = (void *)net->stop_nodes;
+ for( node++; node < (node_t *)stop; node++ )
+ {
+ printf( "PRIMAL NETWORK SIMPLEX: " );
+ }
+ return 0;
+}
+
+int
+main ()
+{
+ net = (network_t*) calloc (1, 20);
+ net->nodes = calloc (MAX, sizeof (node_t));
+ net->stop_nodes = calloc (MAX, sizeof (node_t));
+ cnt = primal_feasible( net );
+
+ net = (network_t*) calloc (1, 20);
+ if( !(net->arcs) )
+ {
+ return -1;
+ }
+ return cnt;
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c
new file mode 100644
index 000000000..3a3c10b70
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c
@@ -0,0 +1,71 @@
+// support POINTER_DIFF_EXPR & NOP_EXPR to avoid
+// escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt"
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct network
+{
+ arc_p arcs;
+ arc_p sorted_arcs;
+ int x;
+ node_p nodes;
+ node_p stop_nodes;
+} network_t;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+int
+main ()
+{
+ arc_t *old_arcs;
+ node_t *node;
+ node_t *stop;
+ size_t off;
+ network_t* net;
+
+ for( ; node->number < stop->number; node++ )
+ {
+ off = node->basic_arc - old_arcs;
+ node->basic_arc = (arc_t *)(net->arcs + off);
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c
new file mode 100644
index 000000000..7b7d110df
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c
@@ -0,0 +1,55 @@
+// support NEGATE_EXPR rewriting
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+int
+main ()
+{
+ int64_t susp = 0;
+ const int MAX = 100;
+ arc_p ap = (arc_p) calloc(MAX, sizeof(arc_t));
+ ap -= susp;
+ printf("%d\n", ap[1].flow);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c
new file mode 100644
index 000000000..317aafa5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct node
+{
+ struct node *left, *right;
+ double a, b, c, d, e, f;
+}
+*a;
+int b, c;
+void
+CreateNode (struct node **p1)
+{
+ *p1 = calloc (10, sizeof (struct node));
+}
+
+int
+main ()
+{
+ a->left = 0;
+ struct node *t = a;
+ CreateNode (&t->right);
+
+ struct node p = *a;
+ b = 1;
+ if (p.left)
+ b = 0;
+ if (b)
+ printf (" Tree.\n");
+}
+
+/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c
new file mode 100644
index 000000000..01a33f669
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c
@@ -0,0 +1,55 @@
+// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]";
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+arc_t **ap = NULL;
+
+int
+main ()
+{
+ ap = (arc_t**) malloc(MAX * sizeof(arc_t*));
+ (*ap)[0].id = 300;
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c
new file mode 100644
index 000000000..a38556533
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c
@@ -0,0 +1,58 @@
+// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]"
+
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+arc_p **ap;
+
+
+int
+main ()
+{
+ ap = (arc_p**) calloc(MAX, sizeof(arc_p*));
+ (**ap)[0].id = 500;
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c
new file mode 100644
index 000000000..5c17ee528
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c
@@ -0,0 +1,57 @@
+// release escape_rescusive_type, "Recusive type"
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+arc_p ap = NULL;
+
+int
+main ()
+{
+ ap = (arc_p) calloc (MAX, sizeof (arc_t));
+ ap[0].id = 100;
+ ap[0].head = (node_p) calloc (MAX, sizeof (node_t));
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c
new file mode 100644
index 000000000..710517ee9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c
@@ -0,0 +1,65 @@
+// support more gimple assign rhs code
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+__attribute__((noinline)) int
+compare(arc_p p1, arc_p p2)
+{
+ return p1 < p2;
+}
+
+int n = 0;
+int m = 0;
+
+int
+main ()
+{
+ scanf ("%d %d", &n, &m);
+ arc_p p = calloc (10, sizeof (struct arc));
+ if (compare (&p[n], &p[m]))
+ {
+ printf ("ss!");
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c
new file mode 100644
index 000000000..6ed0a5d2d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c
@@ -0,0 +1,72 @@
+// rewrite_cond bugfix;
+/*
+if (iterator_600 != 0B)
+old rewrite: _1369 = iterator.reorder.0_1249 != 0B; if (_1369 != 1)
+new rewrite: if (iterator.reorder.0_1249 != 0B)
+*/
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct list_elem
+{
+ arc_t* arc;
+ struct list_elem* next;
+}list_elem;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+int i = 0;
+
+int
+main ()
+{
+ register list_elem *first_list_elem;
+ register list_elem* iterator;
+ iterator = first_list_elem->next;
+ while (iterator)
+ {
+ iterator = iterator->next;
+ i++;
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c
new file mode 100644
index 000000000..5a2dd964f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c
@@ -0,0 +1,58 @@
+// support if (_150 >= _154)
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+int
+main()
+{
+ arc_p **ap = (arc_p**) malloc(1 * sizeof(arc_p*));
+ arc_p **arcs_pointer_sorted = (arc_p**) malloc(1 * sizeof(arc_p*));
+ arcs_pointer_sorted[0] = (arc_p*) calloc (1, sizeof(arc_p));
+
+ if (arcs_pointer_sorted >= ap)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c
new file mode 100644
index 000000000..faa90b42d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c
@@ -0,0 +1,81 @@
+/*
+Exclude the rewriting error caused by
+first_list_elem = (list_elem *)NULL;
+rewriting PHI:first_list_elem_700 = PHI <0B(144), 0B(146)>
+into:
+first_list_elem.reorder.0_55 = PHI <(144), (146)>
+*/
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+typedef struct list_elem
+{
+ arc_t* arc;
+ struct list_elem* next;
+}list_elem;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout, firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail, head;
+ short ident;
+ arc_p nextout, nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+const int MAX = 100;
+
+list_elem* new_list_elem;
+list_elem* first_list_elem;
+
+int
+main ()
+{
+ int i = 0;
+ list_elem *first_list_elem;
+ list_elem *new_list_elem;
+ arc_t *arcout;
+ for( ; i < MAX && arcout->ident == -1; i++);
+
+ first_list_elem = (list_elem *)NULL;
+ for( ; i < MAX; i++)
+ {
+ new_list_elem = (list_elem*) calloc(1, sizeof(list_elem));
+ new_list_elem->next = first_list_elem;
+ first_list_elem = new_list_elem;
+ }
+ if (first_list_elem != 0)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_shwi.c b/gcc/testsuite/gcc.dg/struct/rf_shwi.c
new file mode 100644
index 000000000..2bb326ff2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_shwi.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+
+struct foo {int dx; long dy; int dz; };
+struct goo {long offset; struct foo* pfoo; };
+
+void* func (long);
+
+__attribute__((used)) static void
+test(struct goo* g)
+{
+ void* pvoid;
+ struct foo* f;
+
+ for (f = g->pfoo; f->dx; f++)
+ {
+ if (f->dy)
+ break;
+ }
+ f--;
+
+ pvoid = func(f->dz + g->offset);
+ return;
+}
diff --git a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c
new file mode 100644
index 000000000..8f2da99cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c
@@ -0,0 +1,92 @@
+// release escape_visible_function, "Type escapes via expternally visible function call"
+// compile options: gcc -O3 -fno-inline -fwhole-program
+// -flto-partition=one -fipa-struct-reorg arc_compare.c -fdump-ipa-all -S -v
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct node node_t;
+typedef struct node *node_p;
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct node
+{
+ int64_t potential;
+ int orientation;
+ node_p child;
+ node_p pred;
+ node_p sibling;
+ node_p sibling_prev;
+ arc_p basic_arc;
+ arc_p firstout;
+ arc_p firstin;
+ arc_p arc_tmp;
+ int64_t flow;
+ int64_t depth;
+ int number;
+ int time;
+};
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ node_p tail;
+ node_p head;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+__attribute__((noinline)) static int
+arc_compare( arc_t **a1, arc_t **a2 )
+{
+ if( (*a1)->flow > (*a2)->flow )
+ {
+ return 1;
+ }
+ if( (*a1)->flow < (*a2)->flow )
+ {
+ return -1;
+ }
+ if( (*a1)->id < (*a2)->id )
+ {
+ return -1;
+ }
+
+ return 1;
+}
+
+__attribute__((noinline)) void
+spec_qsort(void *array, int nitems, int size,
+ int (*cmp)(const void*,const void*))
+{
+ for (int i = 0; i < nitems - 1; i++)
+ {
+ if (cmp (array , array))
+ {
+ printf ("CMP 1\n");
+ }
+ else
+ {
+ printf ("CMP 2\n");
+ }
+ }
+}
+
+typedef int cmp_t(const void *, const void *);
+
+int
+main ()
+{
+ void *p = calloc (100, sizeof (arc_t **));
+ spec_qsort (p, 100, 0, (int (*)(const void *, const void *))arc_compare);
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c
new file mode 100644
index 000000000..723142c59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c
@@ -0,0 +1,54 @@
+// Add a safe func mechanism.
+// avoid escape_unkown_field, "Type escapes via an unkown field accessed"
+// avoid escape_cast_void, "Type escapes a cast to/from void*" eg: GIMPLE_NOP
+/* { dg-do compile } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct arc
+{
+ int id;
+ int64_t cost;
+ short ident;
+ arc_p nextout;
+ arc_p nextin;
+ int64_t flow;
+ int64_t org_cost;
+};
+
+void
+__attribute__((noinline)) spec_qsort (void *a, size_t es)
+{
+ char *pa;
+ char *pb;
+ int cmp_result;
+
+ while ((*(arc_t **)a)->id < *((int *)a))
+ {
+ if (cmp_result == 0)
+ {
+ spec_qsort (a, es);
+ pa = (char *)a - es;
+ a += es;
+ *(long *)pb = *(long *)pa;
+ }
+ else
+ {
+ a -= pa - pb;
+ }
+ }
+}
+
+int
+main()
+{
+ arc_p **arcs_pointer_sorted;
+ spec_qsort (arcs_pointer_sorted[0], sizeof (arc_p));
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
index 43913104e..5a476e8f9 100644
--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
@@ -27,8 +27,21 @@ set STRUCT_REORG_TORTURE_OPTIONS [list \
set-torture-options $STRUCT_REORG_TORTURE_OPTIONS {{}}
-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
+# -fipa-struct-reorg
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_*.c]] \
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_*.c]] \
"" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.cpp]] \
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
+
+# -fipa-reorder-fields
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf_*.c]] \
+ "" "-fipa-reorder-fields -fdump-ipa-all -flto-partition=one -fwhole-program"
# All done.
torture-finish
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
index 6565fe8dd..23444fe8b 100644
--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" }
+// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" }
struct a
{
@@ -21,4 +21,10 @@ int g(void)
return b->t;
}
+int main()
+{
+ f ();
+ return g ();
+}
+
/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
index 5864ad46f..2d1f95c99 100644
--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
+++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" }
+// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" }
#include <stdlib.h>
typedef struct {
@@ -10,7 +10,7 @@ typedef struct {
compile_stack_elt_t *stack;
unsigned size;
} compile_stack_type;
-void f (const char *p, const char *pend, int c)
+__attribute__((noinline)) void f (const char *p, const char *pend, int c)
{
compile_stack_type compile_stack;
while (p != pend)
@@ -20,4 +20,9 @@ void f (const char *p, const char *pend, int c)
* sizeof (compile_stack_elt_t));
}
+int main()
+{
+ f (NULL, NULL, 1);
+}
+
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 98a5a490f..2b27c858a 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_REORDER_FIELDS , "ipa struct reorder fields optimization")
DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization")
DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations")
DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 56898e019..a9ec8ed21 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -527,6 +527,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_reorder_fields (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);
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化