123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200 |
- /* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2015 Free Software Foundation, Inc.
- This file is part of GAS, the GNU Assembler.
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "as.h"
- #include <limits.h>
- #include "sb.h"
- #include "safe-ctype.h"
- #include "tc-xtensa.h"
- #include "subsegs.h"
- #include "xtensa-relax.h"
- #include "dwarf2dbg.h"
- #include "xtensa-istack.h"
- #include "struc-symbol.h"
- #include "xtensa-config.h"
- /* Provide default values for new configuration settings. */
- #ifndef XSHAL_ABI
- #define XSHAL_ABI 0
- #endif
- #ifndef uint32
- #define uint32 unsigned int
- #endif
- #ifndef int32
- #define int32 signed int
- #endif
- /* Notes:
- Naming conventions (used somewhat inconsistently):
- The xtensa_ functions are exported
- The xg_ functions are internal
- We also have a couple of different extensibility mechanisms.
- 1) The idiom replacement:
- This is used when a line is first parsed to
- replace an instruction pattern with another instruction
- It is currently limited to replacements of instructions
- with constant operands.
- 2) The xtensa-relax.c mechanism that has stronger instruction
- replacement patterns. When an instruction's immediate field
- does not fit the next instruction sequence is attempted.
- In addition, "narrow" opcodes are supported this way. */
- /* Define characters with special meanings to GAS. */
- const char comment_chars[] = "#";
- const char line_comment_chars[] = "#";
- const char line_separator_chars[] = ";";
- const char EXP_CHARS[] = "eE";
- const char FLT_CHARS[] = "rRsSfFdDxXpP";
- /* Flags to indicate whether the hardware supports the density and
- absolute literals options. */
- bfd_boolean density_supported = XCHAL_HAVE_DENSITY;
- bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
- static vliw_insn cur_vinsn;
- unsigned xtensa_num_pipe_stages;
- unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
- static enum debug_info_type xt_saved_debug_type = DEBUG_NONE;
- /* Some functions are only valid in the front end. This variable
- allows us to assert that we haven't crossed over into the
- back end. */
- static bfd_boolean past_xtensa_end = FALSE;
- /* Flags for properties of the last instruction in a segment. */
- #define FLAG_IS_A0_WRITER 0x1
- #define FLAG_IS_BAD_LOOPEND 0x2
- /* We define a special segment names ".literal" to place literals
- into. The .fini and .init sections are special because they
- contain code that is moved together by the linker. We give them
- their own special .fini.literal and .init.literal sections. */
- #define LITERAL_SECTION_NAME xtensa_section_rename (".literal")
- #define LIT4_SECTION_NAME xtensa_section_rename (".lit4")
- #define INIT_SECTION_NAME xtensa_section_rename (".init")
- #define FINI_SECTION_NAME xtensa_section_rename (".fini")
- /* This type is used for the directive_stack to keep track of the
- state of the literal collection pools. If lit_prefix is set, it is
- used to determine the literal section names; otherwise, the literal
- sections are determined based on the current text section. The
- lit_seg and lit4_seg fields cache these literal sections, with the
- current_text_seg field used a tag to indicate whether the cached
- values are valid. */
- typedef struct lit_state_struct
- {
- char *lit_prefix;
- segT current_text_seg;
- segT lit_seg;
- segT lit4_seg;
- } lit_state;
- static lit_state default_lit_sections;
- /* We keep a list of literal segments. The seg_list type is the node
- for this list. The literal_head pointer is the head of the list,
- with the literal_head_h dummy node at the start. */
- typedef struct seg_list_struct
- {
- struct seg_list_struct *next;
- segT seg;
- } seg_list;
- static seg_list literal_head_h;
- static seg_list *literal_head = &literal_head_h;
- /* Lists of symbols. We keep a list of symbols that label the current
- instruction, so that we can adjust the symbols when inserting alignment
- for various instructions. We also keep a list of all the symbols on
- literals, so that we can fix up those symbols when the literals are
- later moved into the text sections. */
- typedef struct sym_list_struct
- {
- struct sym_list_struct *next;
- symbolS *sym;
- } sym_list;
- static sym_list *insn_labels = NULL;
- static sym_list *free_insn_labels = NULL;
- static sym_list *saved_insn_labels = NULL;
- static sym_list *literal_syms;
- /* Flags to determine whether to prefer const16 or l32r
- if both options are available. */
- int prefer_const16 = 0;
- int prefer_l32r = 0;
- /* Global flag to indicate when we are emitting literals. */
- int generating_literals = 0;
- /* The following PROPERTY table definitions are copied from
- <elf/xtensa.h> and must be kept in sync with the code there. */
- /* Flags in the property tables to specify whether blocks of memory
- are literals, instructions, data, or unreachable. For
- instructions, blocks that begin loop targets and branch targets are
- designated. Blocks that do not allow density, instruction
- reordering or transformation are also specified. Finally, for
- branch targets, branch target alignment priority is included.
- Alignment of the next block is specified in the current block
- and the size of the current block does not include any fill required
- to align to the next block. */
- #define XTENSA_PROP_LITERAL 0x00000001
- #define XTENSA_PROP_INSN 0x00000002
- #define XTENSA_PROP_DATA 0x00000004
- #define XTENSA_PROP_UNREACHABLE 0x00000008
- /* Instruction only properties at beginning of code. */
- #define XTENSA_PROP_INSN_LOOP_TARGET 0x00000010
- #define XTENSA_PROP_INSN_BRANCH_TARGET 0x00000020
- /* Instruction only properties about code. */
- #define XTENSA_PROP_INSN_NO_DENSITY 0x00000040
- #define XTENSA_PROP_INSN_NO_REORDER 0x00000080
- /* Historically, NO_TRANSFORM was a property of instructions,
- but it should apply to literals under certain circumstances. */
- #define XTENSA_PROP_NO_TRANSFORM 0x00000100
- /* Branch target alignment information. This transmits information
- to the linker optimization about the priority of aligning a
- particular block for branch target alignment: None, low priority,
- high priority, or required. These only need to be checked in
- instruction blocks marked as XTENSA_PROP_INSN_BRANCH_TARGET.
- Common usage is
- switch (GET_XTENSA_PROP_BT_ALIGN (flags))
- case XTENSA_PROP_BT_ALIGN_NONE:
- case XTENSA_PROP_BT_ALIGN_LOW:
- case XTENSA_PROP_BT_ALIGN_HIGH:
- case XTENSA_PROP_BT_ALIGN_REQUIRE:
- */
- #define XTENSA_PROP_BT_ALIGN_MASK 0x00000600
- /* No branch target alignment. */
- #define XTENSA_PROP_BT_ALIGN_NONE 0x0
- /* Low priority branch target alignment. */
- #define XTENSA_PROP_BT_ALIGN_LOW 0x1
- /* High priority branch target alignment. */
- #define XTENSA_PROP_BT_ALIGN_HIGH 0x2
- /* Required branch target alignment. */
- #define XTENSA_PROP_BT_ALIGN_REQUIRE 0x3
- #define GET_XTENSA_PROP_BT_ALIGN(flag) \
- (((unsigned) ((flag) & (XTENSA_PROP_BT_ALIGN_MASK))) >> 9)
- #define SET_XTENSA_PROP_BT_ALIGN(flag, align) \
- (((flag) & (~XTENSA_PROP_BT_ALIGN_MASK)) | \
- (((align) << 9) & XTENSA_PROP_BT_ALIGN_MASK))
- /* Alignment is specified in the block BEFORE the one that needs
- alignment. Up to 5 bits. Use GET_XTENSA_PROP_ALIGNMENT(flags) to
- get the required alignment specified as a power of 2. Use
- SET_XTENSA_PROP_ALIGNMENT(flags, pow2) to set the required
- alignment. Be careful of side effects since the SET will evaluate
- flags twice. Also, note that the SIZE of a block in the property
- table does not include the alignment size, so the alignment fill
- must be calculated to determine if two blocks are contiguous.
- TEXT_ALIGN is not currently implemented but is a placeholder for a
- possible future implementation. */
- #define XTENSA_PROP_ALIGN 0x00000800
- #define XTENSA_PROP_ALIGNMENT_MASK 0x0001f000
- #define GET_XTENSA_PROP_ALIGNMENT(flag) \
- (((unsigned) ((flag) & (XTENSA_PROP_ALIGNMENT_MASK))) >> 12)
- #define SET_XTENSA_PROP_ALIGNMENT(flag, align) \
- (((flag) & (~XTENSA_PROP_ALIGNMENT_MASK)) | \
- (((align) << 12) & XTENSA_PROP_ALIGNMENT_MASK))
- #define XTENSA_PROP_INSN_ABSLIT 0x00020000
- /* Structure for saving instruction and alignment per-fragment data
- that will be written to the object file. This structure is
- equivalent to the actual data that will be written out to the file
- but is easier to use. We provide a conversion to file flags
- in frag_flags_to_number. */
- typedef struct frag_flags_struct frag_flags;
- struct frag_flags_struct
- {
- /* is_literal should only be used after xtensa_move_literals.
- If you need to check if you are generating a literal fragment,
- then use the generating_literals global. */
- unsigned is_literal : 1;
- unsigned is_insn : 1;
- unsigned is_data : 1;
- unsigned is_unreachable : 1;
- /* is_specific_opcode implies no_transform. */
- unsigned is_no_transform : 1;
- struct
- {
- unsigned is_loop_target : 1;
- unsigned is_branch_target : 1; /* Branch targets have a priority. */
- unsigned bt_align_priority : 2;
- unsigned is_no_density : 1;
- /* no_longcalls flag does not need to be placed in the object file. */
- unsigned is_no_reorder : 1;
- /* Uses absolute literal addressing for l32r. */
- unsigned is_abslit : 1;
- } insn;
- unsigned is_align : 1;
- unsigned alignment : 5;
- };
- /* Structure for saving information about a block of property data
- for frags that have the same flags. */
- struct xtensa_block_info_struct
- {
- segT sec;
- bfd_vma offset;
- size_t size;
- frag_flags flags;
- struct xtensa_block_info_struct *next;
- };
- /* Structure for saving the current state before emitting literals. */
- typedef struct emit_state_struct
- {
- const char *name;
- segT now_seg;
- subsegT now_subseg;
- int generating_literals;
- } emit_state;
- /* Opcode placement information */
- typedef unsigned long long bitfield;
- #define bit_is_set(bit, bf) ((bf) & (0x01ll << (bit)))
- #define set_bit(bit, bf) ((bf) |= (0x01ll << (bit)))
- #define clear_bit(bit, bf) ((bf) &= ~(0x01ll << (bit)))
- #define MAX_FORMATS 32
- typedef struct op_placement_info_struct
- {
- int num_formats;
- /* A number describing how restrictive the issue is for this
- opcode. For example, an opcode that fits lots of different
- formats has a high freedom, as does an opcode that fits
- only one format but many slots in that format. The most
- restrictive is the opcode that fits only one slot in one
- format. */
- int issuef;
- xtensa_format narrowest;
- char narrowest_size;
- char narrowest_slot;
- /* formats is a bitfield with the Nth bit set
- if the opcode fits in the Nth xtensa_format. */
- bitfield formats;
- /* slots[N]'s Mth bit is set if the op fits in the
- Mth slot of the Nth xtensa_format. */
- bitfield slots[MAX_FORMATS];
- /* A count of the number of slots in a given format
- an op can fit (i.e., the bitcount of the slot field above). */
- char slots_in_format[MAX_FORMATS];
- } op_placement_info, *op_placement_info_table;
- op_placement_info_table op_placement_table;
- /* Extra expression types. */
- #define O_pltrel O_md1 /* like O_symbol but use a PLT reloc */
- #define O_hi16 O_md2 /* use high 16 bits of symbolic value */
- #define O_lo16 O_md3 /* use low 16 bits of symbolic value */
- #define O_pcrel O_md4 /* value is a PC-relative offset */
- #define O_tlsfunc O_md5 /* TLS_FUNC/TLSDESC_FN relocation */
- #define O_tlsarg O_md6 /* TLS_ARG/TLSDESC_ARG relocation */
- #define O_tlscall O_md7 /* TLS_CALL relocation */
- #define O_tpoff O_md8 /* TPOFF relocation */
- #define O_dtpoff O_md9 /* DTPOFF relocation */
- struct suffix_reloc_map
- {
- char *suffix;
- int length;
- bfd_reloc_code_real_type reloc;
- unsigned char operator;
- };
- #define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op }
- static struct suffix_reloc_map suffix_relocs[] =
- {
- SUFFIX_MAP ("l", BFD_RELOC_LO16, O_lo16),
- SUFFIX_MAP ("h", BFD_RELOC_HI16, O_hi16),
- SUFFIX_MAP ("plt", BFD_RELOC_XTENSA_PLT, O_pltrel),
- SUFFIX_MAP ("pcrel", BFD_RELOC_32_PCREL, O_pcrel),
- SUFFIX_MAP ("tlsfunc", BFD_RELOC_XTENSA_TLS_FUNC, O_tlsfunc),
- SUFFIX_MAP ("tlsarg", BFD_RELOC_XTENSA_TLS_ARG, O_tlsarg),
- SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall),
- SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff),
- SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff),
- { (char *) 0, 0, BFD_RELOC_UNUSED, 0 }
- };
- /* Directives. */
- typedef enum
- {
- directive_none = 0,
- directive_literal,
- directive_density,
- directive_transform,
- directive_freeregs,
- directive_longcalls,
- directive_literal_prefix,
- directive_schedule,
- directive_absolute_literals,
- directive_last_directive
- } directiveE;
- typedef struct
- {
- const char *name;
- bfd_boolean can_be_negated;
- } directive_infoS;
- const directive_infoS directive_info[] =
- {
- { "none", FALSE },
- { "literal", FALSE },
- { "density", TRUE },
- { "transform", TRUE },
- { "freeregs", FALSE },
- { "longcalls", TRUE },
- { "literal_prefix", FALSE },
- { "schedule", TRUE },
- { "absolute-literals", TRUE }
- };
- bfd_boolean directive_state[] =
- {
- FALSE, /* none */
- FALSE, /* literal */
- #if !XCHAL_HAVE_DENSITY
- FALSE, /* density */
- #else
- TRUE, /* density */
- #endif
- TRUE, /* transform */
- FALSE, /* freeregs */
- FALSE, /* longcalls */
- FALSE, /* literal_prefix */
- FALSE, /* schedule */
- #if XSHAL_USE_ABSOLUTE_LITERALS
- TRUE /* absolute_literals */
- #else
- FALSE /* absolute_literals */
- #endif
- };
- /* A circular list of all potential and actual literal pool locations
- in a segment. */
- struct litpool_frag
- {
- struct litpool_frag *next;
- struct litpool_frag *prev;
- fragS *fragP;
- addressT addr;
- short priority; /* 1, 2, or 3 -- 1 is highest */
- short original_priority;
- };
- /* Map a segment to its litpool_frag list. */
- struct litpool_seg
- {
- struct litpool_seg *next;
- asection *seg;
- struct litpool_frag frag_list;
- int frag_count; /* since last litpool location */
- };
- static struct litpool_seg litpool_seg_list;
- /* Directive functions. */
- static void xtensa_begin_directive (int);
- static void xtensa_end_directive (int);
- static void xtensa_literal_prefix (void);
- static void xtensa_literal_position (int);
- static void xtensa_literal_pseudo (int);
- static void xtensa_frequency_pseudo (int);
- static void xtensa_elf_cons (int);
- static void xtensa_leb128 (int);
- /* Parsing and Idiom Translation. */
- static bfd_reloc_code_real_type xtensa_elf_suffix (char **, expressionS *);
- /* Various Other Internal Functions. */
- extern bfd_boolean xg_is_single_relaxable_insn (TInsn *, TInsn *, bfd_boolean);
- static bfd_boolean xg_build_to_insn (TInsn *, TInsn *, BuildInstr *);
- static void xtensa_mark_literal_pool_location (void);
- static addressT get_expanded_loop_offset (xtensa_opcode);
- static fragS *get_literal_pool_location (segT);
- static void set_literal_pool_location (segT, fragS *);
- static void xtensa_set_frag_assembly_state (fragS *);
- static void finish_vinsn (vliw_insn *);
- static bfd_boolean emit_single_op (TInsn *);
- static int total_frag_text_expansion (fragS *);
- static bfd_boolean use_trampolines = TRUE;
- static void xtensa_check_frag_count (void);
- static void xtensa_create_trampoline_frag (bfd_boolean);
- static void xtensa_maybe_create_trampoline_frag (void);
- struct trampoline_frag;
- static int init_trampoline_frag (struct trampoline_frag *);
- static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
- static bfd_boolean auto_litpools = FALSE;
- static int auto_litpool_limit = 10000;
- /* Alignment Functions. */
- static int get_text_align_power (unsigned);
- static int get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean);
- static int branch_align_power (segT);
- /* Helpers for xtensa_relax_frag(). */
- static long relax_frag_add_nop (fragS *);
- /* Accessors for additional per-subsegment information. */
- static unsigned get_last_insn_flags (segT, subsegT);
- static void set_last_insn_flags (segT, subsegT, unsigned, bfd_boolean);
- static float get_subseg_total_freq (segT, subsegT);
- static float get_subseg_target_freq (segT, subsegT);
- static void set_subseg_freq (segT, subsegT, float, float);
- /* Segment list functions. */
- static void xtensa_move_literals (void);
- static void xtensa_reorder_segments (void);
- static void xtensa_switch_to_literal_fragment (emit_state *);
- static void xtensa_switch_to_non_abs_literal_fragment (emit_state *);
- static void xtensa_switch_section_emit_state (emit_state *, segT, subsegT);
- static void xtensa_restore_emit_state (emit_state *);
- static segT cache_literal_section (bfd_boolean);
- /* Import from elf32-xtensa.c in BFD library. */
- extern asection *xtensa_make_property_section (asection *, const char *);
- /* op_placement_info functions. */
- static void init_op_placement_info_table (void);
- extern bfd_boolean opcode_fits_format_slot (xtensa_opcode, xtensa_format, int);
- static int xg_get_single_size (xtensa_opcode);
- static xtensa_format xg_get_single_format (xtensa_opcode);
- static int xg_get_single_slot (xtensa_opcode);
- /* TInsn and IStack functions. */
- static bfd_boolean tinsn_has_symbolic_operands (const TInsn *);
- static bfd_boolean tinsn_has_invalid_symbolic_operands (const TInsn *);
- static bfd_boolean tinsn_has_complex_operands (const TInsn *);
- static bfd_boolean tinsn_to_insnbuf (TInsn *, xtensa_insnbuf);
- static bfd_boolean tinsn_check_arguments (const TInsn *);
- static void tinsn_from_chars (TInsn *, char *, int);
- static void tinsn_immed_from_frag (TInsn *, fragS *, int);
- static int get_num_stack_text_bytes (IStack *);
- static int get_num_stack_literal_bytes (IStack *);
- static bfd_boolean tinsn_to_slotbuf (xtensa_format, int, TInsn *, xtensa_insnbuf);
- /* vliw_insn functions. */
- static void xg_init_vinsn (vliw_insn *);
- static void xg_copy_vinsn (vliw_insn *, vliw_insn *);
- static void xg_clear_vinsn (vliw_insn *);
- static bfd_boolean vinsn_has_specific_opcodes (vliw_insn *);
- static void xg_free_vinsn (vliw_insn *);
- static bfd_boolean vinsn_to_insnbuf
- (vliw_insn *, char *, fragS *, bfd_boolean);
- static void vinsn_from_chars (vliw_insn *, char *);
- /* Expression Utilities. */
- bfd_boolean expr_is_const (const expressionS *);
- offsetT get_expr_const (const expressionS *);
- void set_expr_const (expressionS *, offsetT);
- bfd_boolean expr_is_register (const expressionS *);
- offsetT get_expr_register (const expressionS *);
- void set_expr_symbol_offset (expressionS *, symbolS *, offsetT);
- bfd_boolean expr_is_equal (expressionS *, expressionS *);
- static void copy_expr (expressionS *, const expressionS *);
- /* Section renaming. */
- static void build_section_rename (const char *);
- /* ISA imported from bfd. */
- extern xtensa_isa xtensa_default_isa;
- extern int target_big_endian;
- static xtensa_opcode xtensa_addi_opcode;
- static xtensa_opcode xtensa_addmi_opcode;
- static xtensa_opcode xtensa_call0_opcode;
- static xtensa_opcode xtensa_call4_opcode;
- static xtensa_opcode xtensa_call8_opcode;
- static xtensa_opcode xtensa_call12_opcode;
- static xtensa_opcode xtensa_callx0_opcode;
- static xtensa_opcode xtensa_callx4_opcode;
- static xtensa_opcode xtensa_callx8_opcode;
- static xtensa_opcode xtensa_callx12_opcode;
- static xtensa_opcode xtensa_const16_opcode;
- static xtensa_opcode xtensa_entry_opcode;
- static xtensa_opcode xtensa_extui_opcode;
- static xtensa_opcode xtensa_movi_opcode;
- static xtensa_opcode xtensa_movi_n_opcode;
- static xtensa_opcode xtensa_isync_opcode;
- static xtensa_opcode xtensa_j_opcode;
- static xtensa_opcode xtensa_jx_opcode;
- static xtensa_opcode xtensa_l32r_opcode;
- static xtensa_opcode xtensa_loop_opcode;
- static xtensa_opcode xtensa_loopnez_opcode;
- static xtensa_opcode xtensa_loopgtz_opcode;
- static xtensa_opcode xtensa_nop_opcode;
- static xtensa_opcode xtensa_nop_n_opcode;
- static xtensa_opcode xtensa_or_opcode;
- static xtensa_opcode xtensa_ret_opcode;
- static xtensa_opcode xtensa_ret_n_opcode;
- static xtensa_opcode xtensa_retw_opcode;
- static xtensa_opcode xtensa_retw_n_opcode;
- static xtensa_opcode xtensa_rsr_lcount_opcode;
- static xtensa_opcode xtensa_waiti_opcode;
- static int config_max_slots = 0;
- /* Command-line Options. */
- bfd_boolean use_literal_section = TRUE;
- enum flix_level produce_flix = FLIX_ALL;
- static bfd_boolean align_targets = TRUE;
- static bfd_boolean warn_unaligned_branch_targets = FALSE;
- static bfd_boolean has_a0_b_retw = FALSE;
- static bfd_boolean workaround_a0_b_retw = FALSE;
- static bfd_boolean workaround_b_j_loop_end = FALSE;
- static bfd_boolean workaround_short_loop = FALSE;
- static bfd_boolean maybe_has_short_loop = FALSE;
- static bfd_boolean workaround_close_loop_end = FALSE;
- static bfd_boolean maybe_has_close_loop_end = FALSE;
- static bfd_boolean enforce_three_byte_loop_align = FALSE;
- /* When workaround_short_loops is TRUE, all loops with early exits must
- have at least 3 instructions. workaround_all_short_loops is a modifier
- to the workaround_short_loop flag. In addition to the
- workaround_short_loop actions, all straightline loopgtz and loopnez
- must have at least 3 instructions. */
- static bfd_boolean workaround_all_short_loops = FALSE;
- static void
- xtensa_setup_hw_workarounds (int earliest, int latest)
- {
- if (earliest > latest)
- as_fatal (_("illegal range of target hardware versions"));
- /* Enable all workarounds for pre-T1050.0 hardware. */
- if (earliest < 105000 || latest < 105000)
- {
- workaround_a0_b_retw |= TRUE;
- workaround_b_j_loop_end |= TRUE;
- workaround_short_loop |= TRUE;
- workaround_close_loop_end |= TRUE;
- workaround_all_short_loops |= TRUE;
- enforce_three_byte_loop_align = TRUE;
- }
- }
- enum
- {
- option_density = OPTION_MD_BASE,
- option_no_density,
- option_flix,
- option_no_generate_flix,
- option_no_flix,
- option_relax,
- option_no_relax,
- option_link_relax,
- option_no_link_relax,
- option_generics,
- option_no_generics,
- option_transform,
- option_no_transform,
- option_text_section_literals,
- option_no_text_section_literals,
- option_absolute_literals,
- option_no_absolute_literals,
- option_align_targets,
- option_no_align_targets,
- option_warn_unaligned_targets,
- option_longcalls,
- option_no_longcalls,
- option_workaround_a0_b_retw,
- option_no_workaround_a0_b_retw,
- option_workaround_b_j_loop_end,
- option_no_workaround_b_j_loop_end,
- option_workaround_short_loop,
- option_no_workaround_short_loop,
- option_workaround_all_short_loops,
- option_no_workaround_all_short_loops,
- option_workaround_close_loop_end,
- option_no_workaround_close_loop_end,
- option_no_workarounds,
- option_rename_section_name,
- option_prefer_l32r,
- option_prefer_const16,
- option_target_hardware,
- option_trampolines,
- option_no_trampolines,
- option_auto_litpools,
- option_no_auto_litpools,
- option_auto_litpool_limit,
- };
- const char *md_shortopts = "";
- struct option md_longopts[] =
- {
- { "density", no_argument, NULL, option_density },
- { "no-density", no_argument, NULL, option_no_density },
- { "flix", no_argument, NULL, option_flix },
- { "no-generate-flix", no_argument, NULL, option_no_generate_flix },
- { "no-allow-flix", no_argument, NULL, option_no_flix },
- /* Both "relax" and "generics" are deprecated and treated as equivalent
- to the "transform" option. */
- { "relax", no_argument, NULL, option_relax },
- { "no-relax", no_argument, NULL, option_no_relax },
- { "generics", no_argument, NULL, option_generics },
- { "no-generics", no_argument, NULL, option_no_generics },
- { "transform", no_argument, NULL, option_transform },
- { "no-transform", no_argument, NULL, option_no_transform },
- { "text-section-literals", no_argument, NULL, option_text_section_literals },
- { "no-text-section-literals", no_argument, NULL,
- option_no_text_section_literals },
- { "absolute-literals", no_argument, NULL, option_absolute_literals },
- { "no-absolute-literals", no_argument, NULL, option_no_absolute_literals },
- /* This option was changed from -align-target to -target-align
- because it conflicted with the "-al" option. */
- { "target-align", no_argument, NULL, option_align_targets },
- { "no-target-align", no_argument, NULL, option_no_align_targets },
- { "warn-unaligned-targets", no_argument, NULL,
- option_warn_unaligned_targets },
- { "longcalls", no_argument, NULL, option_longcalls },
- { "no-longcalls", no_argument, NULL, option_no_longcalls },
- { "no-workaround-a0-b-retw", no_argument, NULL,
- option_no_workaround_a0_b_retw },
- { "workaround-a0-b-retw", no_argument, NULL, option_workaround_a0_b_retw },
- { "no-workaround-b-j-loop-end", no_argument, NULL,
- option_no_workaround_b_j_loop_end },
- { "workaround-b-j-loop-end", no_argument, NULL,
- option_workaround_b_j_loop_end },
- { "no-workaround-short-loops", no_argument, NULL,
- option_no_workaround_short_loop },
- { "workaround-short-loops", no_argument, NULL,
- option_workaround_short_loop },
- { "no-workaround-all-short-loops", no_argument, NULL,
- option_no_workaround_all_short_loops },
- { "workaround-all-short-loop", no_argument, NULL,
- option_workaround_all_short_loops },
- { "prefer-l32r", no_argument, NULL, option_prefer_l32r },
- { "prefer-const16", no_argument, NULL, option_prefer_const16 },
- { "no-workarounds", no_argument, NULL, option_no_workarounds },
- { "no-workaround-close-loop-end", no_argument, NULL,
- option_no_workaround_close_loop_end },
- { "workaround-close-loop-end", no_argument, NULL,
- option_workaround_close_loop_end },
- { "rename-section", required_argument, NULL, option_rename_section_name },
- { "link-relax", no_argument, NULL, option_link_relax },
- { "no-link-relax", no_argument, NULL, option_no_link_relax },
- { "target-hardware", required_argument, NULL, option_target_hardware },
- { "trampolines", no_argument, NULL, option_trampolines },
- { "no-trampolines", no_argument, NULL, option_no_trampolines },
- { "auto-litpools", no_argument, NULL, option_auto_litpools },
- { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
- { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
- { NULL, no_argument, NULL, 0 }
- };
- size_t md_longopts_size = sizeof md_longopts;
- int
- md_parse_option (int c, char *arg)
- {
- switch (c)
- {
- case option_density:
- as_warn (_("--density option is ignored"));
- return 1;
- case option_no_density:
- as_warn (_("--no-density option is ignored"));
- return 1;
- case option_link_relax:
- linkrelax = 1;
- return 1;
- case option_no_link_relax:
- linkrelax = 0;
- return 1;
- case option_flix:
- produce_flix = FLIX_ALL;
- return 1;
- case option_no_generate_flix:
- produce_flix = FLIX_NO_GENERATE;
- return 1;
- case option_no_flix:
- produce_flix = FLIX_NONE;
- return 1;
- case option_generics:
- as_warn (_("--generics is deprecated; use --transform instead"));
- return md_parse_option (option_transform, arg);
- case option_no_generics:
- as_warn (_("--no-generics is deprecated; use --no-transform instead"));
- return md_parse_option (option_no_transform, arg);
- case option_relax:
- as_warn (_("--relax is deprecated; use --transform instead"));
- return md_parse_option (option_transform, arg);
- case option_no_relax:
- as_warn (_("--no-relax is deprecated; use --no-transform instead"));
- return md_parse_option (option_no_transform, arg);
- case option_longcalls:
- directive_state[directive_longcalls] = TRUE;
- return 1;
- case option_no_longcalls:
- directive_state[directive_longcalls] = FALSE;
- return 1;
- case option_text_section_literals:
- use_literal_section = FALSE;
- return 1;
- case option_no_text_section_literals:
- use_literal_section = TRUE;
- return 1;
- case option_absolute_literals:
- if (!absolute_literals_supported)
- {
- as_fatal (_("--absolute-literals option not supported in this Xtensa configuration"));
- return 0;
- }
- directive_state[directive_absolute_literals] = TRUE;
- return 1;
- case option_no_absolute_literals:
- directive_state[directive_absolute_literals] = FALSE;
- return 1;
- case option_workaround_a0_b_retw:
- workaround_a0_b_retw = TRUE;
- return 1;
- case option_no_workaround_a0_b_retw:
- workaround_a0_b_retw = FALSE;
- return 1;
- case option_workaround_b_j_loop_end:
- workaround_b_j_loop_end = TRUE;
- return 1;
- case option_no_workaround_b_j_loop_end:
- workaround_b_j_loop_end = FALSE;
- return 1;
- case option_workaround_short_loop:
- workaround_short_loop = TRUE;
- return 1;
- case option_no_workaround_short_loop:
- workaround_short_loop = FALSE;
- return 1;
- case option_workaround_all_short_loops:
- workaround_all_short_loops = TRUE;
- return 1;
- case option_no_workaround_all_short_loops:
- workaround_all_short_loops = FALSE;
- return 1;
- case option_workaround_close_loop_end:
- workaround_close_loop_end = TRUE;
- return 1;
- case option_no_workaround_close_loop_end:
- workaround_close_loop_end = FALSE;
- return 1;
- case option_no_workarounds:
- workaround_a0_b_retw = FALSE;
- workaround_b_j_loop_end = FALSE;
- workaround_short_loop = FALSE;
- workaround_all_short_loops = FALSE;
- workaround_close_loop_end = FALSE;
- return 1;
- case option_align_targets:
- align_targets = TRUE;
- return 1;
- case option_no_align_targets:
- align_targets = FALSE;
- return 1;
- case option_warn_unaligned_targets:
- warn_unaligned_branch_targets = TRUE;
- return 1;
- case option_rename_section_name:
- build_section_rename (arg);
- return 1;
- case 'Q':
- /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
- should be emitted or not. FIXME: Not implemented. */
- return 1;
- case option_prefer_l32r:
- if (prefer_const16)
- as_fatal (_("prefer-l32r conflicts with prefer-const16"));
- prefer_l32r = 1;
- return 1;
- case option_prefer_const16:
- if (prefer_l32r)
- as_fatal (_("prefer-const16 conflicts with prefer-l32r"));
- prefer_const16 = 1;
- return 1;
- case option_target_hardware:
- {
- int earliest, latest = 0;
- if (*arg == 0 || *arg == '-')
- as_fatal (_("invalid target hardware version"));
- earliest = strtol (arg, &arg, 0);
- if (*arg == 0)
- latest = earliest;
- else if (*arg == '-')
- {
- if (*++arg == 0)
- as_fatal (_("invalid target hardware version"));
- latest = strtol (arg, &arg, 0);
- }
- if (*arg != 0)
- as_fatal (_("invalid target hardware version"));
- xtensa_setup_hw_workarounds (earliest, latest);
- return 1;
- }
- case option_transform:
- /* This option has no affect other than to use the defaults,
- which are already set. */
- return 1;
- case option_no_transform:
- /* This option turns off all transformations of any kind.
- However, because we want to preserve the state of other
- directives, we only change its own field. Thus, before
- you perform any transformation, always check if transform
- is available. If you use the functions we provide for this
- purpose, you will be ok. */
- directive_state[directive_transform] = FALSE;
- return 1;
- case option_trampolines:
- use_trampolines = TRUE;
- return 1;
- case option_no_trampolines:
- use_trampolines = FALSE;
- return 1;
- case option_auto_litpools:
- auto_litpools = TRUE;
- use_literal_section = FALSE;
- return 1;
- case option_no_auto_litpools:
- auto_litpools = FALSE;
- auto_litpool_limit = -1;
- return 1;
- case option_auto_litpool_limit:
- {
- int value = 0;
- if (auto_litpool_limit < 0)
- as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
- if (*arg == 0 || *arg == '-')
- as_fatal (_("invalid auto-litpool-limit argument"));
- value = strtol (arg, &arg, 10);
- if (*arg != 0)
- as_fatal (_("invalid auto-litpool-limit argument"));
- if (value < 100 || value > 10000)
- as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
- auto_litpool_limit = value;
- auto_litpools = TRUE;
- use_literal_section = FALSE;
- return 1;
- }
- default:
- return 0;
- }
- }
- void
- md_show_usage (FILE *stream)
- {
- fputs ("\n\
- Xtensa options:\n\
- --[no-]text-section-literals\n\
- [Do not] put literals in the text section\n\
- --[no-]absolute-literals\n\
- [Do not] default to use non-PC-relative literals\n\
- --[no-]target-align [Do not] try to align branch targets\n\
- --[no-]longcalls [Do not] emit 32-bit call sequences\n\
- --[no-]transform [Do not] transform instructions\n\
- --flix both allow hand-written and generate flix bundles\n\
- --no-generate-flix allow hand-written but do not generate\n\
- flix bundles\n\
- --no-allow-flix neither allow hand-written nor generate\n\
- flix bundles\n\
- --rename-section old=new Rename section 'old' to 'new'\n\
- --[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
- when jumps do not reach their targets\n\
- --[no-]auto-litpools [Do not] automatically create literal pools\n\
- --auto-litpool-limit=<value>\n\
- (range 100-10000) Maximum number of blocks of\n\
- instructions to emit between literal pool\n\
- locations; implies --auto-litpools flag\n", stream);
- }
- /* Functions related to the list of current label symbols. */
- static void
- xtensa_add_insn_label (symbolS *sym)
- {
- sym_list *l;
- if (!free_insn_labels)
- l = (sym_list *) xmalloc (sizeof (sym_list));
- else
- {
- l = free_insn_labels;
- free_insn_labels = l->next;
- }
- l->sym = sym;
- l->next = insn_labels;
- insn_labels = l;
- }
- static void
- xtensa_clear_insn_labels (void)
- {
- sym_list **pl;
- for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
- ;
- *pl = insn_labels;
- insn_labels = NULL;
- }
- static void
- xtensa_move_labels (fragS *new_frag, valueT new_offset)
- {
- sym_list *lit;
- for (lit = insn_labels; lit; lit = lit->next)
- {
- symbolS *lit_sym = lit->sym;
- S_SET_VALUE (lit_sym, new_offset);
- symbol_set_frag (lit_sym, new_frag);
- }
- }
- /* Directive data and functions. */
- typedef struct state_stackS_struct
- {
- directiveE directive;
- bfd_boolean negated;
- bfd_boolean old_state;
- const char *file;
- unsigned int line;
- const void *datum;
- struct state_stackS_struct *prev;
- } state_stackS;
- state_stackS *directive_state_stack;
- const pseudo_typeS md_pseudo_table[] =
- {
- { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0). */
- { "literal_position", xtensa_literal_position, 0 },
- { "frame", s_ignore, 0 }, /* Formerly used for STABS debugging. */
- { "long", xtensa_elf_cons, 4 },
- { "word", xtensa_elf_cons, 4 },
- { "4byte", xtensa_elf_cons, 4 },
- { "short", xtensa_elf_cons, 2 },
- { "2byte", xtensa_elf_cons, 2 },
- { "sleb128", xtensa_leb128, 1},
- { "uleb128", xtensa_leb128, 0},
- { "begin", xtensa_begin_directive, 0 },
- { "end", xtensa_end_directive, 0 },
- { "literal", xtensa_literal_pseudo, 0 },
- { "frequency", xtensa_frequency_pseudo, 0 },
- { NULL, 0, 0 },
- };
- static bfd_boolean
- use_transform (void)
- {
- /* After md_end, you should be checking frag by frag, rather
- than state directives. */
- gas_assert (!past_xtensa_end);
- return directive_state[directive_transform];
- }
- static bfd_boolean
- do_align_targets (void)
- {
- /* Do not use this function after md_end; just look at align_targets
- instead. There is no target-align directive, so alignment is either
- enabled for all frags or not done at all. */
- gas_assert (!past_xtensa_end);
- return align_targets && use_transform ();
- }
- static void
- directive_push (directiveE directive, bfd_boolean negated, const void *datum)
- {
- char *file;
- unsigned int line;
- state_stackS *stack = (state_stackS *) xmalloc (sizeof (state_stackS));
- as_where (&file, &line);
- stack->directive = directive;
- stack->negated = negated;
- stack->old_state = directive_state[directive];
- stack->file = file;
- stack->line = line;
- stack->datum = datum;
- stack->prev = directive_state_stack;
- directive_state_stack = stack;
- directive_state[directive] = !negated;
- }
- static void
- directive_pop (directiveE *directive,
- bfd_boolean *negated,
- const char **file,
- unsigned int *line,
- const void **datum)
- {
- state_stackS *top = directive_state_stack;
- if (!directive_state_stack)
- {
- as_bad (_("unmatched end directive"));
- *directive = directive_none;
- return;
- }
- directive_state[directive_state_stack->directive] = top->old_state;
- *directive = top->directive;
- *negated = top->negated;
- *file = top->file;
- *line = top->line;
- *datum = top->datum;
- directive_state_stack = top->prev;
- free (top);
- }
- static void
- directive_balance (void)
- {
- while (directive_state_stack)
- {
- directiveE directive;
- bfd_boolean negated;
- const char *file;
- unsigned int line;
- const void *datum;
- directive_pop (&directive, &negated, &file, &line, &datum);
- as_warn_where ((char *) file, line,
- _(".begin directive with no matching .end directive"));
- }
- }
- static bfd_boolean
- inside_directive (directiveE dir)
- {
- state_stackS *top = directive_state_stack;
- while (top && top->directive != dir)
- top = top->prev;
- return (top != NULL);
- }
- static void
- get_directive (directiveE *directive, bfd_boolean *negated)
- {
- int len;
- unsigned i;
- char *directive_string;
- if (strncmp (input_line_pointer, "no-", 3) != 0)
- *negated = FALSE;
- else
- {
- *negated = TRUE;
- input_line_pointer += 3;
- }
- len = strspn (input_line_pointer,
- "abcdefghijklmnopqrstuvwxyz_-/0123456789.");
- /* This code is a hack to make .begin [no-][generics|relax] exactly
- equivalent to .begin [no-]transform. We should remove it when
- we stop accepting those options. */
- if (strncmp (input_line_pointer, "generics", strlen ("generics")) == 0)
- {
- as_warn (_("[no-]generics is deprecated; use [no-]transform instead"));
- directive_string = "transform";
- }
- else if (strncmp (input_line_pointer, "relax", strlen ("relax")) == 0)
- {
- as_warn (_("[no-]relax is deprecated; use [no-]transform instead"));
- directive_string = "transform";
- }
- else
- directive_string = input_line_pointer;
- for (i = 0; i < sizeof (directive_info) / sizeof (*directive_info); ++i)
- {
- if (strncmp (directive_string, directive_info[i].name, len) == 0)
- {
- input_line_pointer += len;
- *directive = (directiveE) i;
- if (*negated && !directive_info[i].can_be_negated)
- as_bad (_("directive %s cannot be negated"),
- directive_info[i].name);
- return;
- }
- }
- as_bad (_("unknown directive"));
- *directive = (directiveE) XTENSA_UNDEFINED;
- }
- static void
- xtensa_begin_directive (int ignore ATTRIBUTE_UNUSED)
- {
- directiveE directive;
- bfd_boolean negated;
- emit_state *state;
- lit_state *ls;
- get_directive (&directive, &negated);
- if (directive == (directiveE) XTENSA_UNDEFINED)
- {
- discard_rest_of_line ();
- return;
- }
- if (cur_vinsn.inside_bundle)
- as_bad (_("directives are not valid inside bundles"));
- switch (directive)
- {
- case directive_literal:
- if (!inside_directive (directive_literal))
- {
- /* Previous labels go with whatever follows this directive, not with
- the literal, so save them now. */
- saved_insn_labels = insn_labels;
- insn_labels = NULL;
- }
- as_warn (_(".begin literal is deprecated; use .literal instead"));
- state = (emit_state *) xmalloc (sizeof (emit_state));
- xtensa_switch_to_literal_fragment (state);
- directive_push (directive_literal, negated, state);
- break;
- case directive_literal_prefix:
- /* Have to flush pending output because a movi relaxed to an l32r
- might produce a literal. */
- md_flush_pending_output ();
- /* Check to see if the current fragment is a literal
- fragment. If it is, then this operation is not allowed. */
- if (generating_literals)
- {
- as_bad (_("cannot set literal_prefix inside literal fragment"));
- return;
- }
- /* Allocate the literal state for this section and push
- onto the directive stack. */
- ls = xmalloc (sizeof (lit_state));
- gas_assert (ls);
- *ls = default_lit_sections;
- directive_push (directive_literal_prefix, negated, ls);
- /* Process the new prefix. */
- xtensa_literal_prefix ();
- break;
- case directive_freeregs:
- /* This information is currently unused, but we'll accept the statement
- and just discard the rest of the line. This won't check the syntax,
- but it will accept every correct freeregs directive. */
- input_line_pointer += strcspn (input_line_pointer, "\n");
- directive_push (directive_freeregs, negated, 0);
- break;
- case directive_schedule:
- md_flush_pending_output ();
- frag_var (rs_fill, 0, 0, frag_now->fr_subtype,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- directive_push (directive_schedule, negated, 0);
- xtensa_set_frag_assembly_state (frag_now);
- break;
- case directive_density:
- as_warn (_(".begin [no-]density is ignored"));
- break;
- case directive_absolute_literals:
- md_flush_pending_output ();
- if (!absolute_literals_supported && !negated)
- {
- as_warn (_("Xtensa absolute literals option not supported; ignored"));
- break;
- }
- xtensa_set_frag_assembly_state (frag_now);
- directive_push (directive, negated, 0);
- break;
- default:
- md_flush_pending_output ();
- xtensa_set_frag_assembly_state (frag_now);
- directive_push (directive, negated, 0);
- break;
- }
- demand_empty_rest_of_line ();
- }
- static void
- xtensa_end_directive (int ignore ATTRIBUTE_UNUSED)
- {
- directiveE begin_directive, end_directive;
- bfd_boolean begin_negated, end_negated;
- const char *file;
- unsigned int line;
- emit_state *state;
- emit_state **state_ptr;
- lit_state *s;
- if (cur_vinsn.inside_bundle)
- as_bad (_("directives are not valid inside bundles"));
- get_directive (&end_directive, &end_negated);
- md_flush_pending_output ();
- switch ((int) end_directive)
- {
- case XTENSA_UNDEFINED:
- discard_rest_of_line ();
- return;
- case (int) directive_density:
- as_warn (_(".end [no-]density is ignored"));
- demand_empty_rest_of_line ();
- break;
- case (int) directive_absolute_literals:
- if (!absolute_literals_supported && !end_negated)
- {
- as_warn (_("Xtensa absolute literals option not supported; ignored"));
- demand_empty_rest_of_line ();
- return;
- }
- break;
- default:
- break;
- }
- state_ptr = &state; /* use state_ptr to avoid type-punning warning */
- directive_pop (&begin_directive, &begin_negated, &file, &line,
- (const void **) state_ptr);
- if (begin_directive != directive_none)
- {
- if (begin_directive != end_directive || begin_negated != end_negated)
- {
- as_bad (_("does not match begin %s%s at %s:%d"),
- begin_negated ? "no-" : "",
- directive_info[begin_directive].name, file, line);
- }
- else
- {
- switch (end_directive)
- {
- case directive_literal:
- frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_restore_emit_state (state);
- xtensa_set_frag_assembly_state (frag_now);
- free (state);
- if (!inside_directive (directive_literal))
- {
- /* Restore the list of current labels. */
- xtensa_clear_insn_labels ();
- insn_labels = saved_insn_labels;
- }
- break;
- case directive_literal_prefix:
- /* Restore the default collection sections from saved state. */
- s = (lit_state *) state;
- gas_assert (s);
- default_lit_sections = *s;
- /* Free the state storage. */
- free (s->lit_prefix);
- free (s);
- break;
- case directive_schedule:
- case directive_freeregs:
- break;
- default:
- xtensa_set_frag_assembly_state (frag_now);
- break;
- }
- }
- }
- demand_empty_rest_of_line ();
- }
- /* Place an aligned literal fragment at the current location. */
- static void
- xtensa_literal_position (int ignore ATTRIBUTE_UNUSED)
- {
- md_flush_pending_output ();
- if (inside_directive (directive_literal))
- as_warn (_(".literal_position inside literal directive; ignoring"));
- xtensa_mark_literal_pool_location ();
- demand_empty_rest_of_line ();
- xtensa_clear_insn_labels ();
- }
- /* Support .literal label, expr, ... */
- static void
- xtensa_literal_pseudo (int ignored ATTRIBUTE_UNUSED)
- {
- emit_state state;
- char *p, *base_name;
- char c;
- segT dest_seg;
- if (inside_directive (directive_literal))
- {
- as_bad (_(".literal not allowed inside .begin literal region"));
- ignore_rest_of_line ();
- return;
- }
- md_flush_pending_output ();
- /* Previous labels go with whatever follows this directive, not with
- the literal, so save them now. */
- saved_insn_labels = insn_labels;
- insn_labels = NULL;
- /* If we are using text-section literals, then this is the right value... */
- dest_seg = now_seg;
- base_name = input_line_pointer;
- xtensa_switch_to_literal_fragment (&state);
- /* ...but if we aren't using text-section-literals, then we
- need to put them in the section we just switched to. */
- if (use_literal_section || directive_state[directive_absolute_literals])
- dest_seg = now_seg;
- /* FIXME, despite the previous comments, dest_seg is unused... */
- (void) dest_seg;
- /* All literals are aligned to four-byte boundaries. */
- frag_align (2, 0, 0);
- record_alignment (now_seg, 2);
- c = get_symbol_name (&base_name);
- /* Just after name is now '\0'. */
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE_AFTER_NAME ();
- if (*input_line_pointer != ',' && *input_line_pointer != ':')
- {
- as_bad (_("expected comma or colon after symbol name; "
- "rest of line ignored"));
- ignore_rest_of_line ();
- xtensa_restore_emit_state (&state);
- return;
- }
- *p = 0;
- colon (base_name);
- *p = c;
- input_line_pointer++; /* skip ',' or ':' */
- xtensa_elf_cons (4);
- xtensa_restore_emit_state (&state);
- /* Restore the list of current labels. */
- xtensa_clear_insn_labels ();
- insn_labels = saved_insn_labels;
- }
- static void
- xtensa_literal_prefix (void)
- {
- char *name;
- int len;
- /* Parse the new prefix from the input_line_pointer. */
- SKIP_WHITESPACE ();
- len = strspn (input_line_pointer,
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz_/0123456789.$");
- /* Get a null-terminated copy of the name. */
- name = xmalloc (len + 1);
- gas_assert (name);
- strncpy (name, input_line_pointer, len);
- name[len] = 0;
- /* Skip the name in the input line. */
- input_line_pointer += len;
- default_lit_sections.lit_prefix = name;
- /* Clear cached literal sections, since the prefix has changed. */
- default_lit_sections.lit_seg = NULL;
- default_lit_sections.lit4_seg = NULL;
- }
- /* Support ".frequency branch_target_frequency fall_through_frequency". */
- static void
- xtensa_frequency_pseudo (int ignored ATTRIBUTE_UNUSED)
- {
- float fall_through_f, target_f;
- fall_through_f = (float) strtod (input_line_pointer, &input_line_pointer);
- if (fall_through_f < 0)
- {
- as_bad (_("fall through frequency must be greater than 0"));
- ignore_rest_of_line ();
- return;
- }
- target_f = (float) strtod (input_line_pointer, &input_line_pointer);
- if (target_f < 0)
- {
- as_bad (_("branch target frequency must be greater than 0"));
- ignore_rest_of_line ();
- return;
- }
- set_subseg_freq (now_seg, now_subseg, target_f + fall_through_f, target_f);
- demand_empty_rest_of_line ();
- }
- /* Like normal .long/.short/.word, except support @plt, etc.
- Clobbers input_line_pointer, checks end-of-line. */
- static void
- xtensa_elf_cons (int nbytes)
- {
- expressionS exp;
- bfd_reloc_code_real_type reloc;
- md_flush_pending_output ();
- if (cur_vinsn.inside_bundle)
- as_bad (_("directives are not valid inside bundles"));
- if (is_it_end_of_statement ())
- {
- demand_empty_rest_of_line ();
- return;
- }
- do
- {
- expression (&exp);
- if (exp.X_op == O_symbol
- && *input_line_pointer == '@'
- && ((reloc = xtensa_elf_suffix (&input_line_pointer, &exp))
- != BFD_RELOC_NONE))
- {
- reloc_howto_type *reloc_howto =
- bfd_reloc_type_lookup (stdoutput, reloc);
- if (reloc == BFD_RELOC_UNUSED || !reloc_howto)
- as_bad (_("unsupported relocation"));
- else if ((reloc >= BFD_RELOC_XTENSA_SLOT0_OP
- && reloc <= BFD_RELOC_XTENSA_SLOT14_OP)
- || (reloc >= BFD_RELOC_XTENSA_SLOT0_ALT
- && reloc <= BFD_RELOC_XTENSA_SLOT14_ALT))
- as_bad (_("opcode-specific %s relocation used outside "
- "an instruction"), reloc_howto->name);
- else if (nbytes != (int) bfd_get_reloc_size (reloc_howto))
- as_bad (_("%s relocations do not fit in %d bytes"),
- reloc_howto->name, nbytes);
- else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC
- || reloc == BFD_RELOC_XTENSA_TLS_ARG
- || reloc == BFD_RELOC_XTENSA_TLS_CALL)
- as_bad (_("invalid use of %s relocation"), reloc_howto->name);
- else
- {
- char *p = frag_more ((int) nbytes);
- xtensa_set_frag_assembly_state (frag_now);
- fix_new_exp (frag_now, p - frag_now->fr_literal,
- nbytes, &exp, reloc_howto->pc_relative, reloc);
- }
- }
- else
- {
- xtensa_set_frag_assembly_state (frag_now);
- emit_expr (&exp, (unsigned int) nbytes);
- }
- }
- while (*input_line_pointer++ == ',');
- input_line_pointer--; /* Put terminator back into stream. */
- demand_empty_rest_of_line ();
- }
- static bfd_boolean is_leb128_expr;
- static void
- xtensa_leb128 (int sign)
- {
- is_leb128_expr = TRUE;
- s_leb128 (sign);
- is_leb128_expr = FALSE;
- }
- /* Parsing and Idiom Translation. */
- /* Parse @plt, etc. and return the desired relocation. */
- static bfd_reloc_code_real_type
- xtensa_elf_suffix (char **str_p, expressionS *exp_p)
- {
- char ident[20];
- char *str = *str_p;
- char *str2;
- int ch;
- int len;
- struct suffix_reloc_map *ptr;
- if (*str++ != '@')
- return BFD_RELOC_NONE;
- for (ch = *str, str2 = ident;
- (str2 < ident + sizeof (ident) - 1
- && (ISALNUM (ch) || ch == '@'));
- ch = *++str)
- {
- *str2++ = (ISLOWER (ch)) ? ch : TOLOWER (ch);
- }
- *str2 = '\0';
- len = str2 - ident;
- ch = ident[0];
- for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++)
- if (ch == ptr->suffix[0]
- && len == ptr->length
- && memcmp (ident, ptr->suffix, ptr->length) == 0)
- {
- /* Now check for "identifier@suffix+constant". */
- if (*str == '-' || *str == '+')
- {
- char *orig_line = input_line_pointer;
- expressionS new_exp;
- input_line_pointer = str;
- expression (&new_exp);
- if (new_exp.X_op == O_constant)
- {
- exp_p->X_add_number += new_exp.X_add_number;
- str = input_line_pointer;
- }
- if (&input_line_pointer != str_p)
- input_line_pointer = orig_line;
- }
- *str_p = str;
- return ptr->reloc;
- }
- return BFD_RELOC_UNUSED;
- }
- /* Find the matching operator type. */
- static unsigned char
- map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
- {
- struct suffix_reloc_map *sfx;
- unsigned char operator = (unsigned char) -1;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
- {
- if (sfx->reloc == reloc)
- {
- operator = sfx->operator;
- break;
- }
- }
- gas_assert (operator != (unsigned char) -1);
- return operator;
- }
- /* Find the matching reloc type. */
- static bfd_reloc_code_real_type
- map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal)
- {
- struct suffix_reloc_map *sfx;
- bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
- {
- if (sfx->operator == operator)
- {
- reloc = sfx->reloc;
- break;
- }
- }
- if (is_literal)
- {
- if (reloc == BFD_RELOC_XTENSA_TLS_FUNC)
- return BFD_RELOC_XTENSA_TLSDESC_FN;
- else if (reloc == BFD_RELOC_XTENSA_TLS_ARG)
- return BFD_RELOC_XTENSA_TLSDESC_ARG;
- }
- if (reloc == BFD_RELOC_UNUSED)
- return BFD_RELOC_32;
- return reloc;
- }
- static const char *
- expression_end (const char *name)
- {
- while (1)
- {
- switch (*name)
- {
- case '}':
- case ';':
- case '\0':
- case ',':
- case ':':
- return name;
- case ' ':
- case '\t':
- ++name;
- continue;
- default:
- return 0;
- }
- }
- }
- #define ERROR_REG_NUM ((unsigned) -1)
- static unsigned
- tc_get_register (const char *prefix)
- {
- unsigned reg;
- const char *next_expr;
- const char *old_line_pointer;
- SKIP_WHITESPACE ();
- old_line_pointer = input_line_pointer;
- if (*input_line_pointer == '$')
- ++input_line_pointer;
- /* Accept "sp" as a synonym for "a1". */
- if (input_line_pointer[0] == 's' && input_line_pointer[1] == 'p'
- && expression_end (input_line_pointer + 2))
- {
- input_line_pointer += 2;
- return 1; /* AR[1] */
- }
- while (*input_line_pointer++ == *prefix++)
- ;
- --input_line_pointer;
- --prefix;
- if (*prefix)
- {
- as_bad (_("bad register name: %s"), old_line_pointer);
- return ERROR_REG_NUM;
- }
- if (!ISDIGIT ((unsigned char) *input_line_pointer))
- {
- as_bad (_("bad register number: %s"), input_line_pointer);
- return ERROR_REG_NUM;
- }
- reg = 0;
- while (ISDIGIT ((int) *input_line_pointer))
- reg = reg * 10 + *input_line_pointer++ - '0';
- if (!(next_expr = expression_end (input_line_pointer)))
- {
- as_bad (_("bad register name: %s"), old_line_pointer);
- return ERROR_REG_NUM;
- }
- input_line_pointer = (char *) next_expr;
- return reg;
- }
- static void
- expression_maybe_register (xtensa_opcode opc, int opnd, expressionS *tok)
- {
- xtensa_isa isa = xtensa_default_isa;
- /* Check if this is an immediate operand. */
- if (xtensa_operand_is_register (isa, opc, opnd) == 0)
- {
- bfd_reloc_code_real_type reloc;
- segT t = expression (tok);
- if (t == absolute_section
- && xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
- {
- gas_assert (tok->X_op == O_constant);
- tok->X_op = O_symbol;
- tok->X_add_symbol = &abs_symbol;
- }
- if ((tok->X_op == O_constant || tok->X_op == O_symbol)
- && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
- != BFD_RELOC_NONE))
- {
- switch (reloc)
- {
- case BFD_RELOC_LO16:
- if (tok->X_op == O_constant)
- {
- tok->X_add_number &= 0xffff;
- return;
- }
- break;
- case BFD_RELOC_HI16:
- if (tok->X_op == O_constant)
- {
- tok->X_add_number = ((unsigned) tok->X_add_number) >> 16;
- return;
- }
- break;
- case BFD_RELOC_UNUSED:
- as_bad (_("unsupported relocation"));
- return;
- case BFD_RELOC_32_PCREL:
- as_bad (_("pcrel relocation not allowed in an instruction"));
- return;
- default:
- break;
- }
- tok->X_op = map_suffix_reloc_to_operator (reloc);
- }
- }
- else
- {
- xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
- unsigned reg = tc_get_register (xtensa_regfile_shortname (isa, opnd_rf));
- if (reg != ERROR_REG_NUM) /* Already errored */
- {
- uint32 buf = reg;
- if (xtensa_operand_encode (isa, opc, opnd, &buf))
- as_bad (_("register number out of range"));
- }
- tok->X_op = O_register;
- tok->X_add_symbol = 0;
- tok->X_add_number = reg;
- }
- }
- /* Split up the arguments for an opcode or pseudo-op. */
- static int
- tokenize_arguments (char **args, char *str)
- {
- char *old_input_line_pointer;
- bfd_boolean saw_comma = FALSE;
- bfd_boolean saw_arg = FALSE;
- bfd_boolean saw_colon = FALSE;
- int num_args = 0;
- char *arg_end, *arg;
- int arg_len;
- /* Save and restore input_line_pointer around this function. */
- old_input_line_pointer = input_line_pointer;
- input_line_pointer = str;
- while (*input_line_pointer)
- {
- SKIP_WHITESPACE ();
- switch (*input_line_pointer)
- {
- case '\0':
- case '}':
- goto fini;
- case ':':
- input_line_pointer++;
- if (saw_comma || saw_colon || !saw_arg)
- goto err;
- saw_colon = TRUE;
- break;
- case ',':
- input_line_pointer++;
- if (saw_comma || saw_colon || !saw_arg)
- goto err;
- saw_comma = TRUE;
- break;
- default:
- if (!saw_comma && !saw_colon && saw_arg)
- goto err;
- arg_end = input_line_pointer + 1;
- while (!expression_end (arg_end))
- arg_end += 1;
- arg_len = arg_end - input_line_pointer;
- arg = (char *) xmalloc ((saw_colon ? 1 : 0) + arg_len + 1);
- args[num_args] = arg;
- if (saw_colon)
- *arg++ = ':';
- strncpy (arg, input_line_pointer, arg_len);
- arg[arg_len] = '\0';
- input_line_pointer = arg_end;
- num_args += 1;
- saw_comma = FALSE;
- saw_colon = FALSE;
- saw_arg = TRUE;
- break;
- }
- }
- fini:
- if (saw_comma || saw_colon)
- goto err;
- input_line_pointer = old_input_line_pointer;
- return num_args;
- err:
- if (saw_comma)
- as_bad (_("extra comma"));
- else if (saw_colon)
- as_bad (_("extra colon"));
- else if (!saw_arg)
- as_bad (_("missing argument"));
- else
- as_bad (_("missing comma or colon"));
- input_line_pointer = old_input_line_pointer;
- return -1;
- }
- /* Parse the arguments to an opcode. Return TRUE on error. */
- static bfd_boolean
- parse_arguments (TInsn *insn, int num_args, char **arg_strings)
- {
- expressionS *tok, *last_tok;
- xtensa_opcode opcode = insn->opcode;
- bfd_boolean had_error = TRUE;
- xtensa_isa isa = xtensa_default_isa;
- int n, num_regs = 0;
- int opcode_operand_count;
- int opnd_cnt, last_opnd_cnt;
- unsigned int next_reg = 0;
- char *old_input_line_pointer;
- if (insn->insn_type == ITYPE_LITERAL)
- opcode_operand_count = 1;
- else
- opcode_operand_count = xtensa_opcode_num_operands (isa, opcode);
- tok = insn->tok;
- memset (tok, 0, sizeof (*tok) * MAX_INSN_ARGS);
- /* Save and restore input_line_pointer around this function. */
- old_input_line_pointer = input_line_pointer;
- last_tok = 0;
- last_opnd_cnt = -1;
- opnd_cnt = 0;
- /* Skip invisible operands. */
- while (xtensa_operand_is_visible (isa, opcode, opnd_cnt) == 0)
- {
- opnd_cnt += 1;
- tok++;
- }
- for (n = 0; n < num_args; n++)
- {
- input_line_pointer = arg_strings[n];
- if (*input_line_pointer == ':')
- {
- xtensa_regfile opnd_rf;
- input_line_pointer++;
- if (num_regs == 0)
- goto err;
- gas_assert (opnd_cnt > 0);
- num_regs--;
- opnd_rf = xtensa_operand_regfile (isa, opcode, last_opnd_cnt);
- if (next_reg
- != tc_get_register (xtensa_regfile_shortname (isa, opnd_rf)))
- as_warn (_("incorrect register number, ignoring"));
- next_reg++;
- }
- else
- {
- if (opnd_cnt >= opcode_operand_count)
- {
- as_warn (_("too many arguments"));
- goto err;
- }
- gas_assert (opnd_cnt < MAX_INSN_ARGS);
- expression_maybe_register (opcode, opnd_cnt, tok);
- next_reg = tok->X_add_number + 1;
- if (tok->X_op == O_illegal || tok->X_op == O_absent)
- goto err;
- if (xtensa_operand_is_register (isa, opcode, opnd_cnt) == 1)
- {
- num_regs = xtensa_operand_num_regs (isa, opcode, opnd_cnt) - 1;
- /* minus 1 because we are seeing one right now */
- }
- else
- num_regs = 0;
- last_tok = tok;
- last_opnd_cnt = opnd_cnt;
- demand_empty_rest_of_line ();
- do
- {
- opnd_cnt += 1;
- tok++;
- }
- while (xtensa_operand_is_visible (isa, opcode, opnd_cnt) == 0);
- }
- }
- if (num_regs > 0 && ((int) next_reg != last_tok->X_add_number + 1))
- goto err;
- insn->ntok = tok - insn->tok;
- had_error = FALSE;
- err:
- input_line_pointer = old_input_line_pointer;
- return had_error;
- }
- static int
- get_invisible_operands (TInsn *insn)
- {
- xtensa_isa isa = xtensa_default_isa;
- static xtensa_insnbuf slotbuf = NULL;
- xtensa_format fmt;
- xtensa_opcode opc = insn->opcode;
- int slot, opnd, fmt_found;
- unsigned val;
- if (!slotbuf)
- slotbuf = xtensa_insnbuf_alloc (isa);
- /* Find format/slot where this can be encoded. */
- fmt_found = 0;
- slot = 0;
- for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++)
- {
- for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
- {
- if (xtensa_opcode_encode (isa, fmt, slot, slotbuf, opc) == 0)
- {
- fmt_found = 1;
- break;
- }
- }
- if (fmt_found) break;
- }
- if (!fmt_found)
- {
- as_bad (_("cannot encode opcode \"%s\""), xtensa_opcode_name (isa, opc));
- return -1;
- }
- /* First encode all the visible operands
- (to deal with shared field operands). */
- for (opnd = 0; opnd < insn->ntok; opnd++)
- {
- if (xtensa_operand_is_visible (isa, opc, opnd) == 1
- && (insn->tok[opnd].X_op == O_register
- || insn->tok[opnd].X_op == O_constant))
- {
- val = insn->tok[opnd].X_add_number;
- xtensa_operand_encode (isa, opc, opnd, &val);
- xtensa_operand_set_field (isa, opc, opnd, fmt, slot, slotbuf, val);
- }
- }
- /* Then pull out the values for the invisible ones. */
- for (opnd = 0; opnd < insn->ntok; opnd++)
- {
- if (xtensa_operand_is_visible (isa, opc, opnd) == 0)
- {
- xtensa_operand_get_field (isa, opc, opnd, fmt, slot, slotbuf, &val);
- xtensa_operand_decode (isa, opc, opnd, &val);
- insn->tok[opnd].X_add_number = val;
- if (xtensa_operand_is_register (isa, opc, opnd) == 1)
- insn->tok[opnd].X_op = O_register;
- else
- insn->tok[opnd].X_op = O_constant;
- }
- }
- return 0;
- }
- static void
- xg_reverse_shift_count (char **cnt_argp)
- {
- char *cnt_arg, *new_arg;
- cnt_arg = *cnt_argp;
- /* replace the argument with "31-(argument)" */
- new_arg = (char *) xmalloc (strlen (cnt_arg) + 6);
- sprintf (new_arg, "31-(%s)", cnt_arg);
- free (cnt_arg);
- *cnt_argp = new_arg;
- }
- /* If "arg" is a constant expression, return non-zero with the value
- in *valp. */
- static int
- xg_arg_is_constant (char *arg, offsetT *valp)
- {
- expressionS exp;
- char *save_ptr = input_line_pointer;
- input_line_pointer = arg;
- expression (&exp);
- input_line_pointer = save_ptr;
- if (exp.X_op == O_constant)
- {
- *valp = exp.X_add_number;
- return 1;
- }
- return 0;
- }
- static void
- xg_replace_opname (char **popname, char *newop)
- {
- free (*popname);
- *popname = (char *) xmalloc (strlen (newop) + 1);
- strcpy (*popname, newop);
- }
- static int
- xg_check_num_args (int *pnum_args,
- int expected_num,
- char *opname,
- char **arg_strings)
- {
- int num_args = *pnum_args;
- if (num_args < expected_num)
- {
- as_bad (_("not enough operands (%d) for '%s'; expected %d"),
- num_args, opname, expected_num);
- return -1;
- }
- if (num_args > expected_num)
- {
- as_warn (_("too many operands (%d) for '%s'; expected %d"),
- num_args, opname, expected_num);
- while (num_args-- > expected_num)
- {
- free (arg_strings[num_args]);
- arg_strings[num_args] = 0;
- }
- *pnum_args = expected_num;
- return -1;
- }
- return 0;
- }
- /* If the register is not specified as part of the opcode,
- then get it from the operand and move it to the opcode. */
- static int
- xg_translate_sysreg_op (char **popname, int *pnum_args, char **arg_strings)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_sysreg sr;
- char *opname, *new_opname;
- const char *sr_name;
- int is_user, is_write;
- opname = *popname;
- if (*opname == '_')
- opname += 1;
- is_user = (opname[1] == 'u');
- is_write = (opname[0] == 'w');
- /* Opname == [rw]ur or [rwx]sr... */
- if (xg_check_num_args (pnum_args, 2, opname, arg_strings))
- return -1;
- /* Check if the argument is a symbolic register name. */
- sr = xtensa_sysreg_lookup_name (isa, arg_strings[1]);
- /* Handle WSR to "INTSET" as a special case. */
- if (sr == XTENSA_UNDEFINED && is_write && !is_user
- && !strcasecmp (arg_strings[1], "intset"))
- sr = xtensa_sysreg_lookup_name (isa, "interrupt");
- if (sr == XTENSA_UNDEFINED
- || (xtensa_sysreg_is_user (isa, sr) == 1) != is_user)
- {
- /* Maybe it's a register number.... */
- offsetT val;
- if (!xg_arg_is_constant (arg_strings[1], &val))
- {
- as_bad (_("invalid register '%s' for '%s' instruction"),
- arg_strings[1], opname);
- return -1;
- }
- sr = xtensa_sysreg_lookup (isa, val, is_user);
- if (sr == XTENSA_UNDEFINED)
- {
- as_bad (_("invalid register number (%ld) for '%s' instruction"),
- (long) val, opname);
- return -1;
- }
- }
- /* Remove the last argument, which is now part of the opcode. */
- free (arg_strings[1]);
- arg_strings[1] = 0;
- *pnum_args = 1;
- /* Translate the opcode. */
- sr_name = xtensa_sysreg_name (isa, sr);
- /* Another special case for "WSR.INTSET".... */
- if (is_write && !is_user && !strcasecmp ("interrupt", sr_name))
- sr_name = "intset";
- new_opname = (char *) xmalloc (strlen (sr_name) + 6);
- sprintf (new_opname, "%s.%s", *popname, sr_name);
- free (*popname);
- *popname = new_opname;
- return 0;
- }
- static int
- xtensa_translate_old_userreg_ops (char **popname)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_sysreg sr;
- char *opname, *new_opname;
- const char *sr_name;
- bfd_boolean has_underbar = FALSE;
- opname = *popname;
- if (opname[0] == '_')
- {
- has_underbar = TRUE;
- opname += 1;
- }
- sr = xtensa_sysreg_lookup_name (isa, opname + 1);
- if (sr != XTENSA_UNDEFINED)
- {
- /* The new default name ("nnn") is different from the old default
- name ("URnnn"). The old default is handled below, and we don't
- want to recognize [RW]nnn, so do nothing if the name is the (new)
- default. */
- static char namebuf[10];
- sprintf (namebuf, "%d", xtensa_sysreg_number (isa, sr));
- if (strcmp (namebuf, opname + 1) == 0)
- return 0;
- }
- else
- {
- offsetT val;
- char *end;
- /* Only continue if the reg name is "URnnn". */
- if (opname[1] != 'u' || opname[2] != 'r')
- return 0;
- val = strtoul (opname + 3, &end, 10);
- if (*end != '\0')
- return 0;
- sr = xtensa_sysreg_lookup (isa, val, 1);
- if (sr == XTENSA_UNDEFINED)
- {
- as_bad (_("invalid register number (%ld) for '%s'"),
- (long) val, opname);
- return -1;
- }
- }
- /* Translate the opcode. */
- sr_name = xtensa_sysreg_name (isa, sr);
- new_opname = (char *) xmalloc (strlen (sr_name) + 6);
- sprintf (new_opname, "%s%cur.%s", (has_underbar ? "_" : ""),
- opname[0], sr_name);
- free (*popname);
- *popname = new_opname;
- return 0;
- }
- static int
- xtensa_translate_zero_immed (char *old_op,
- char *new_op,
- char **popname,
- int *pnum_args,
- char **arg_strings)
- {
- char *opname;
- offsetT val;
- opname = *popname;
- gas_assert (opname[0] != '_');
- if (strcmp (opname, old_op) != 0)
- return 0;
- if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
- return -1;
- if (xg_arg_is_constant (arg_strings[1], &val) && val == 0)
- {
- xg_replace_opname (popname, new_op);
- free (arg_strings[1]);
- arg_strings[1] = arg_strings[2];
- arg_strings[2] = 0;
- *pnum_args = 2;
- }
- return 0;
- }
- /* If the instruction is an idiom (i.e., a built-in macro), translate it.
- Returns non-zero if an error was found. */
- static int
- xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings)
- {
- char *opname = *popname;
- bfd_boolean has_underbar = FALSE;
- if (*opname == '_')
- {
- has_underbar = TRUE;
- opname += 1;
- }
- if (strcmp (opname, "mov") == 0)
- {
- if (use_transform () && !has_underbar && density_supported)
- xg_replace_opname (popname, "mov.n");
- else
- {
- if (xg_check_num_args (pnum_args, 2, opname, arg_strings))
- return -1;
- xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[2] = (char *) xmalloc (strlen (arg_strings[1]) + 1);
- strcpy (arg_strings[2], arg_strings[1]);
- *pnum_args = 3;
- }
- return 0;
- }
- if (strcmp (opname, "bbsi.l") == 0)
- {
- if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
- return -1;
- xg_replace_opname (popname, (has_underbar ? "_bbsi" : "bbsi"));
- if (target_big_endian)
- xg_reverse_shift_count (&arg_strings[1]);
- return 0;
- }
- if (strcmp (opname, "bbci.l") == 0)
- {
- if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
- return -1;
- xg_replace_opname (popname, (has_underbar ? "_bbci" : "bbci"));
- if (target_big_endian)
- xg_reverse_shift_count (&arg_strings[1]);
- return 0;
- }
- /* Don't do anything special with NOPs inside FLIX instructions. They
- are handled elsewhere. Real NOP instructions are always available
- in configurations with FLIX, so this should never be an issue but
- check for it anyway. */
- if (!cur_vinsn.inside_bundle && xtensa_nop_opcode == XTENSA_UNDEFINED
- && strcmp (opname, "nop") == 0)
- {
- if (use_transform () && !has_underbar && density_supported)
- xg_replace_opname (popname, "nop.n");
- else
- {
- if (xg_check_num_args (pnum_args, 0, opname, arg_strings))
- return -1;
- xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[0] = (char *) xmalloc (3);
- arg_strings[1] = (char *) xmalloc (3);
- arg_strings[2] = (char *) xmalloc (3);
- strcpy (arg_strings[0], "a1");
- strcpy (arg_strings[1], "a1");
- strcpy (arg_strings[2], "a1");
- *pnum_args = 3;
- }
- return 0;
- }
- /* Recognize [RW]UR and [RWX]SR. */
- if ((((opname[0] == 'r' || opname[0] == 'w')
- && (opname[1] == 'u' || opname[1] == 's'))
- || (opname[0] == 'x' && opname[1] == 's'))
- && opname[2] == 'r'
- && opname[3] == '\0')
- return xg_translate_sysreg_op (popname, pnum_args, arg_strings);
- /* Backward compatibility for RUR and WUR: Recognize [RW]UR<nnn> and
- [RW]<name> if <name> is the non-default name of a user register. */
- if ((opname[0] == 'r' || opname[0] == 'w')
- && xtensa_opcode_lookup (xtensa_default_isa, opname) == XTENSA_UNDEFINED)
- return xtensa_translate_old_userreg_ops (popname);
- /* Relax branches that don't allow comparisons against an immediate value
- of zero to the corresponding branches with implicit zero immediates. */
- if (!has_underbar && use_transform ())
- {
- if (xtensa_translate_zero_immed ("bnei", "bnez", popname,
- pnum_args, arg_strings))
- return -1;
- if (xtensa_translate_zero_immed ("beqi", "beqz", popname,
- pnum_args, arg_strings))
- return -1;
- if (xtensa_translate_zero_immed ("bgei", "bgez", popname,
- pnum_args, arg_strings))
- return -1;
- if (xtensa_translate_zero_immed ("blti", "bltz", popname,
- pnum_args, arg_strings))
- return -1;
- }
- return 0;
- }
- /* Functions for dealing with the Xtensa ISA. */
- /* Currently the assembler only allows us to use a single target per
- fragment. Because of this, only one operand for a given
- instruction may be symbolic. If there is a PC-relative operand,
- the last one is chosen. Otherwise, the result is the number of the
- last immediate operand, and if there are none of those, we fail and
- return -1. */
- static int
- get_relaxable_immed (xtensa_opcode opcode)
- {
- int last_immed = -1;
- int noperands, opi;
- if (opcode == XTENSA_UNDEFINED)
- return -1;
- noperands = xtensa_opcode_num_operands (xtensa_default_isa, opcode);
- for (opi = noperands - 1; opi >= 0; opi--)
- {
- if (xtensa_operand_is_visible (xtensa_default_isa, opcode, opi) == 0)
- continue;
- if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, opi) == 1)
- return opi;
- if (last_immed == -1
- && xtensa_operand_is_register (xtensa_default_isa, opcode, opi) == 0)
- last_immed = opi;
- }
- return last_immed;
- }
- static xtensa_opcode
- get_opcode_from_buf (const char *buf, int slot)
- {
- static xtensa_insnbuf insnbuf = NULL;
- static xtensa_insnbuf slotbuf = NULL;
- xtensa_isa isa = xtensa_default_isa;
- xtensa_format fmt;
- if (!insnbuf)
- {
- insnbuf = xtensa_insnbuf_alloc (isa);
- slotbuf = xtensa_insnbuf_alloc (isa);
- }
- xtensa_insnbuf_from_chars (isa, insnbuf, (const unsigned char *) buf, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- return XTENSA_UNDEFINED;
- if (slot >= xtensa_format_num_slots (isa, fmt))
- return XTENSA_UNDEFINED;
- xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
- return xtensa_opcode_decode (isa, fmt, slot, slotbuf);
- }
- #ifdef TENSILICA_DEBUG
- /* For debugging, print out the mapping of opcode numbers to opcodes. */
- static void
- xtensa_print_insn_table (void)
- {
- int num_opcodes, num_operands;
- xtensa_opcode opcode;
- xtensa_isa isa = xtensa_default_isa;
- num_opcodes = xtensa_isa_num_opcodes (xtensa_default_isa);
- for (opcode = 0; opcode < num_opcodes; opcode++)
- {
- int opn;
- fprintf (stderr, "%d: %s: ", opcode, xtensa_opcode_name (isa, opcode));
- num_operands = xtensa_opcode_num_operands (isa, opcode);
- for (opn = 0; opn < num_operands; opn++)
- {
- if (xtensa_operand_is_visible (isa, opcode, opn) == 0)
- continue;
- if (xtensa_operand_is_register (isa, opcode, opn) == 1)
- {
- xtensa_regfile opnd_rf =
- xtensa_operand_regfile (isa, opcode, opn);
- fprintf (stderr, "%s ", xtensa_regfile_shortname (isa, opnd_rf));
- }
- else if (xtensa_operand_is_PCrelative (isa, opcode, opn) == 1)
- fputs ("[lLr] ", stderr);
- else
- fputs ("i ", stderr);
- }
- fprintf (stderr, "\n");
- }
- }
- static void
- print_vliw_insn (xtensa_insnbuf vbuf)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_format f = xtensa_format_decode (isa, vbuf);
- xtensa_insnbuf sbuf = xtensa_insnbuf_alloc (isa);
- int op;
- fprintf (stderr, "format = %d\n", f);
- for (op = 0; op < xtensa_format_num_slots (isa, f); op++)
- {
- xtensa_opcode opcode;
- const char *opname;
- int operands;
- xtensa_format_get_slot (isa, f, op, vbuf, sbuf);
- opcode = xtensa_opcode_decode (isa, f, op, sbuf);
- opname = xtensa_opcode_name (isa, opcode);
- fprintf (stderr, "op in slot %i is %s;\n", op, opname);
- fprintf (stderr, " operands = ");
- for (operands = 0;
- operands < xtensa_opcode_num_operands (isa, opcode);
- operands++)
- {
- unsigned int val;
- if (xtensa_operand_is_visible (isa, opcode, operands) == 0)
- continue;
- xtensa_operand_get_field (isa, opcode, operands, f, op, sbuf, &val);
- xtensa_operand_decode (isa, opcode, operands, &val);
- fprintf (stderr, "%d ", val);
- }
- fprintf (stderr, "\n");
- }
- xtensa_insnbuf_free (isa, sbuf);
- }
- #endif /* TENSILICA_DEBUG */
- static bfd_boolean
- is_direct_call_opcode (xtensa_opcode opcode)
- {
- xtensa_isa isa = xtensa_default_isa;
- int n, num_operands;
- if (xtensa_opcode_is_call (isa, opcode) != 1)
- return FALSE;
- num_operands = xtensa_opcode_num_operands (isa, opcode);
- for (n = 0; n < num_operands; n++)
- {
- if (xtensa_operand_is_register (isa, opcode, n) == 0
- && xtensa_operand_is_PCrelative (isa, opcode, n) == 1)
- return TRUE;
- }
- return FALSE;
- }
- /* Convert from BFD relocation type code to slot and operand number.
- Returns non-zero on failure. */
- static int
- decode_reloc (bfd_reloc_code_real_type reloc, int *slot, bfd_boolean *is_alt)
- {
- if (reloc >= BFD_RELOC_XTENSA_SLOT0_OP
- && reloc <= BFD_RELOC_XTENSA_SLOT14_OP)
- {
- *slot = reloc - BFD_RELOC_XTENSA_SLOT0_OP;
- *is_alt = FALSE;
- }
- else if (reloc >= BFD_RELOC_XTENSA_SLOT0_ALT
- && reloc <= BFD_RELOC_XTENSA_SLOT14_ALT)
- {
- *slot = reloc - BFD_RELOC_XTENSA_SLOT0_ALT;
- *is_alt = TRUE;
- }
- else
- return -1;
- return 0;
- }
- /* Convert from slot number to BFD relocation type code for the
- standard PC-relative relocations. Return BFD_RELOC_NONE on
- failure. */
- static bfd_reloc_code_real_type
- encode_reloc (int slot)
- {
- if (slot < 0 || slot > 14)
- return BFD_RELOC_NONE;
- return BFD_RELOC_XTENSA_SLOT0_OP + slot;
- }
- /* Convert from slot numbers to BFD relocation type code for the
- "alternate" relocations. Return BFD_RELOC_NONE on failure. */
- static bfd_reloc_code_real_type
- encode_alt_reloc (int slot)
- {
- if (slot < 0 || slot > 14)
- return BFD_RELOC_NONE;
- return BFD_RELOC_XTENSA_SLOT0_ALT + slot;
- }
- static void
- xtensa_insnbuf_set_operand (xtensa_insnbuf slotbuf,
- xtensa_format fmt,
- int slot,
- xtensa_opcode opcode,
- int operand,
- uint32 value,
- const char *file,
- unsigned int line)
- {
- uint32 valbuf = value;
- if (xtensa_operand_encode (xtensa_default_isa, opcode, operand, &valbuf))
- {
- if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand)
- == 1)
- as_bad_where ((char *) file, line,
- _("operand %d of '%s' has out of range value '%u'"),
- operand + 1,
- xtensa_opcode_name (xtensa_default_isa, opcode),
- value);
- else
- as_bad_where ((char *) file, line,
- _("operand %d of '%s' has invalid value '%u'"),
- operand + 1,
- xtensa_opcode_name (xtensa_default_isa, opcode),
- value);
- return;
- }
- xtensa_operand_set_field (xtensa_default_isa, opcode, operand, fmt, slot,
- slotbuf, valbuf);
- }
- static uint32
- xtensa_insnbuf_get_operand (xtensa_insnbuf slotbuf,
- xtensa_format fmt,
- int slot,
- xtensa_opcode opcode,
- int opnum)
- {
- uint32 val = 0;
- (void) xtensa_operand_get_field (xtensa_default_isa, opcode, opnum,
- fmt, slot, slotbuf, &val);
- (void) xtensa_operand_decode (xtensa_default_isa, opcode, opnum, &val);
- return val;
- }
- /* Checks for rules from xtensa-relax tables. */
- /* The routine xg_instruction_matches_option_term must return TRUE
- when a given option term is true. The meaning of all of the option
- terms is given interpretation by this function. */
- static bfd_boolean
- xg_instruction_matches_option_term (TInsn *insn, const ReqOrOption *option)
- {
- if (strcmp (option->option_name, "realnop") == 0
- || strncmp (option->option_name, "IsaUse", 6) == 0)
- {
- /* These conditions were evaluated statically when building the
- relaxation table. There's no need to reevaluate them now. */
- return TRUE;
- }
- else if (strcmp (option->option_name, "FREEREG") == 0)
- return insn->extra_arg.X_op == O_register;
- else
- {
- as_fatal (_("internal error: unknown option name '%s'"),
- option->option_name);
- }
- }
- static bfd_boolean
- xg_instruction_matches_or_options (TInsn *insn,
- const ReqOrOptionList *or_option)
- {
- const ReqOrOption *option;
- /* Must match each of the AND terms. */
- for (option = or_option; option != NULL; option = option->next)
- {
- if (xg_instruction_matches_option_term (insn, option))
- return TRUE;
- }
- return FALSE;
- }
- static bfd_boolean
- xg_instruction_matches_options (TInsn *insn, const ReqOptionList *options)
- {
- const ReqOption *req_options;
- /* Must match each of the AND terms. */
- for (req_options = options;
- req_options != NULL;
- req_options = req_options->next)
- {
- /* Must match one of the OR clauses. */
- if (!xg_instruction_matches_or_options (insn,
- req_options->or_option_terms))
- return FALSE;
- }
- return TRUE;
- }
- /* Return the transition rule that matches or NULL if none matches. */
- static bfd_boolean
- xg_instruction_matches_rule (TInsn *insn, TransitionRule *rule)
- {
- PreconditionList *condition_l;
- if (rule->opcode != insn->opcode)
- return FALSE;
- for (condition_l = rule->conditions;
- condition_l != NULL;
- condition_l = condition_l->next)
- {
- expressionS *exp1;
- expressionS *exp2;
- Precondition *cond = condition_l->precond;
- switch (cond->typ)
- {
- case OP_CONSTANT:
- /* The expression must be the constant. */
- gas_assert (cond->op_num < insn->ntok);
- exp1 = &insn->tok[cond->op_num];
- if (expr_is_const (exp1))
- {
- switch (cond->cmp)
- {
- case OP_EQUAL:
- if (get_expr_const (exp1) != cond->op_data)
- return FALSE;
- break;
- case OP_NOTEQUAL:
- if (get_expr_const (exp1) == cond->op_data)
- return FALSE;
- break;
- default:
- return FALSE;
- }
- }
- else if (expr_is_register (exp1))
- {
- switch (cond->cmp)
- {
- case OP_EQUAL:
- if (get_expr_register (exp1) != cond->op_data)
- return FALSE;
- break;
- case OP_NOTEQUAL:
- if (get_expr_register (exp1) == cond->op_data)
- return FALSE;
- break;
- default:
- return FALSE;
- }
- }
- else
- return FALSE;
- break;
- case OP_OPERAND:
- gas_assert (cond->op_num < insn->ntok);
- gas_assert (cond->op_data < insn->ntok);
- exp1 = &insn->tok[cond->op_num];
- exp2 = &insn->tok[cond->op_data];
- switch (cond->cmp)
- {
- case OP_EQUAL:
- if (!expr_is_equal (exp1, exp2))
- return FALSE;
- break;
- case OP_NOTEQUAL:
- if (expr_is_equal (exp1, exp2))
- return FALSE;
- break;
- }
- break;
- case OP_LITERAL:
- case OP_LABEL:
- default:
- return FALSE;
- }
- }
- if (!xg_instruction_matches_options (insn, rule->options))
- return FALSE;
- return TRUE;
- }
- static int
- transition_rule_cmp (const TransitionRule *a, const TransitionRule *b)
- {
- bfd_boolean a_greater = FALSE;
- bfd_boolean b_greater = FALSE;
- ReqOptionList *l_a = a->options;
- ReqOptionList *l_b = b->options;
- /* We only care if they both are the same except for
- a const16 vs. an l32r. */
- while (l_a && l_b && ((l_a->next == NULL) == (l_b->next == NULL)))
- {
- ReqOrOptionList *l_or_a = l_a->or_option_terms;
- ReqOrOptionList *l_or_b = l_b->or_option_terms;
- while (l_or_a && l_or_b && ((l_a->next == NULL) == (l_b->next == NULL)))
- {
- if (l_or_a->is_true != l_or_b->is_true)
- return 0;
- if (strcmp (l_or_a->option_name, l_or_b->option_name) != 0)
- {
- /* This is the case we care about. */
- if (strcmp (l_or_a->option_name, "IsaUseConst16") == 0
- && strcmp (l_or_b->option_name, "IsaUseL32R") == 0)
- {
- if (prefer_const16)
- a_greater = TRUE;
- else
- b_greater = TRUE;
- }
- else if (strcmp (l_or_a->option_name, "IsaUseL32R") == 0
- && strcmp (l_or_b->option_name, "IsaUseConst16") == 0)
- {
- if (prefer_const16)
- b_greater = TRUE;
- else
- a_greater = TRUE;
- }
- else
- return 0;
- }
- l_or_a = l_or_a->next;
- l_or_b = l_or_b->next;
- }
- if (l_or_a || l_or_b)
- return 0;
- l_a = l_a->next;
- l_b = l_b->next;
- }
- if (l_a || l_b)
- return 0;
- /* Incomparable if the substitution was used differently in two cases. */
- if (a_greater && b_greater)
- return 0;
- if (b_greater)
- return 1;
- if (a_greater)
- return -1;
- return 0;
- }
- static TransitionRule *
- xg_instruction_match (TInsn *insn)
- {
- TransitionTable *table = xg_build_simplify_table (&transition_rule_cmp);
- TransitionList *l;
- gas_assert (insn->opcode < table->num_opcodes);
- /* Walk through all of the possible transitions. */
- for (l = table->table[insn->opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- if (xg_instruction_matches_rule (insn, rule))
- return rule;
- }
- return NULL;
- }
- /* Various Other Internal Functions. */
- static bfd_boolean
- is_unique_insn_expansion (TransitionRule *r)
- {
- if (!r->to_instr || r->to_instr->next != NULL)
- return FALSE;
- if (r->to_instr->typ != INSTR_INSTR)
- return FALSE;
- return TRUE;
- }
- /* Check if there is exactly one relaxation for INSN that converts it to
- another instruction of equal or larger size. If so, and if TARG is
- non-null, go ahead and generate the relaxed instruction into TARG. If
- NARROW_ONLY is true, then only consider relaxations that widen a narrow
- instruction, i.e., ignore relaxations that convert to an instruction of
- equal size. In some contexts where this function is used, only
- a single widening is allowed and the NARROW_ONLY argument is used to
- exclude cases like ADDI being "widened" to an ADDMI, which may
- later be relaxed to an ADDMI/ADDI pair. */
- bfd_boolean
- xg_is_single_relaxable_insn (TInsn *insn, TInsn *targ, bfd_boolean narrow_only)
- {
- TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
- TransitionList *l;
- TransitionRule *match = 0;
- gas_assert (insn->insn_type == ITYPE_INSN);
- gas_assert (insn->opcode < table->num_opcodes);
- for (l = table->table[insn->opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- if (xg_instruction_matches_rule (insn, rule)
- && is_unique_insn_expansion (rule)
- && (xg_get_single_size (insn->opcode) + (narrow_only ? 1 : 0)
- <= xg_get_single_size (rule->to_instr->opcode)))
- {
- if (match)
- return FALSE;
- match = rule;
- }
- }
- if (!match)
- return FALSE;
- if (targ)
- xg_build_to_insn (targ, insn, match->to_instr);
- return TRUE;
- }
- /* Return the maximum number of bytes this opcode can expand to. */
- static int
- xg_get_max_insn_widen_size (xtensa_opcode opcode)
- {
- TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
- TransitionList *l;
- int max_size = xg_get_single_size (opcode);
- gas_assert (opcode < table->num_opcodes);
- for (l = table->table[opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- BuildInstr *build_list;
- int this_size = 0;
- if (!rule)
- continue;
- build_list = rule->to_instr;
- if (is_unique_insn_expansion (rule))
- {
- gas_assert (build_list->typ == INSTR_INSTR);
- this_size = xg_get_max_insn_widen_size (build_list->opcode);
- }
- else
- for (; build_list != NULL; build_list = build_list->next)
- {
- switch (build_list->typ)
- {
- case INSTR_INSTR:
- this_size += xg_get_single_size (build_list->opcode);
- break;
- case INSTR_LITERAL_DEF:
- case INSTR_LABEL_DEF:
- default:
- break;
- }
- }
- if (this_size > max_size)
- max_size = this_size;
- }
- return max_size;
- }
- /* Return the maximum number of literal bytes this opcode can generate. */
- static int
- xg_get_max_insn_widen_literal_size (xtensa_opcode opcode)
- {
- TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
- TransitionList *l;
- int max_size = 0;
- gas_assert (opcode < table->num_opcodes);
- for (l = table->table[opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- BuildInstr *build_list;
- int this_size = 0;
- if (!rule)
- continue;
- build_list = rule->to_instr;
- if (is_unique_insn_expansion (rule))
- {
- gas_assert (build_list->typ == INSTR_INSTR);
- this_size = xg_get_max_insn_widen_literal_size (build_list->opcode);
- }
- else
- for (; build_list != NULL; build_list = build_list->next)
- {
- switch (build_list->typ)
- {
- case INSTR_LITERAL_DEF:
- /* Hard-coded 4-byte literal. */
- this_size += 4;
- break;
- case INSTR_INSTR:
- case INSTR_LABEL_DEF:
- default:
- break;
- }
- }
- if (this_size > max_size)
- max_size = this_size;
- }
- return max_size;
- }
- static bfd_boolean
- xg_is_relaxable_insn (TInsn *insn, int lateral_steps)
- {
- int steps_taken = 0;
- TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
- TransitionList *l;
- gas_assert (insn->insn_type == ITYPE_INSN);
- gas_assert (insn->opcode < table->num_opcodes);
- for (l = table->table[insn->opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- if (xg_instruction_matches_rule (insn, rule))
- {
- if (steps_taken == lateral_steps)
- return TRUE;
- steps_taken++;
- }
- }
- return FALSE;
- }
- static symbolS *
- get_special_literal_symbol (void)
- {
- static symbolS *sym = NULL;
- if (sym == NULL)
- sym = symbol_find_or_make ("SPECIAL_LITERAL0\001");
- return sym;
- }
- static symbolS *
- get_special_label_symbol (void)
- {
- static symbolS *sym = NULL;
- if (sym == NULL)
- sym = symbol_find_or_make ("SPECIAL_LABEL0\001");
- return sym;
- }
- static bfd_boolean
- xg_valid_literal_expression (const expressionS *exp)
- {
- switch (exp->X_op)
- {
- case O_constant:
- case O_symbol:
- case O_big:
- case O_uminus:
- case O_subtract:
- case O_pltrel:
- case O_pcrel:
- case O_tlsfunc:
- case O_tlsarg:
- case O_tpoff:
- case O_dtpoff:
- return TRUE;
- default:
- return FALSE;
- }
- }
- /* This will check to see if the value can be converted into the
- operand type. It will return TRUE if it does not fit. */
- static bfd_boolean
- xg_check_operand (int32 value, xtensa_opcode opcode, int operand)
- {
- uint32 valbuf = value;
- if (xtensa_operand_encode (xtensa_default_isa, opcode, operand, &valbuf))
- return TRUE;
- return FALSE;
- }
- /* Assumes: All immeds are constants. Check that all constants fit
- into their immeds; return FALSE if not. */
- static bfd_boolean
- xg_immeds_fit (const TInsn *insn)
- {
- xtensa_isa isa = xtensa_default_isa;
- int i;
- int n = insn->ntok;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < n; ++i)
- {
- const expressionS *exp = &insn->tok[i];
- if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
- continue;
- switch (exp->X_op)
- {
- case O_register:
- case O_constant:
- if (xg_check_operand (exp->X_add_number, insn->opcode, i))
- return FALSE;
- break;
- default:
- /* The symbol should have a fixup associated with it. */
- gas_assert (FALSE);
- break;
- }
- }
- return TRUE;
- }
- /* This should only be called after we have an initial
- estimate of the addresses. */
- static bfd_boolean
- xg_symbolic_immeds_fit (const TInsn *insn,
- segT pc_seg,
- fragS *pc_frag,
- offsetT pc_offset,
- long stretch)
- {
- xtensa_isa isa = xtensa_default_isa;
- symbolS *symbolP;
- fragS *sym_frag;
- offsetT target, pc;
- uint32 new_offset;
- int i;
- int n = insn->ntok;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < n; ++i)
- {
- const expressionS *exp = &insn->tok[i];
- if (xtensa_operand_is_register (isa, insn->opcode, i) == 1)
- continue;
- switch (exp->X_op)
- {
- case O_register:
- case O_constant:
- if (xg_check_operand (exp->X_add_number, insn->opcode, i))
- return FALSE;
- break;
- case O_lo16:
- case O_hi16:
- /* Check for the worst case. */
- if (xg_check_operand (0xffff, insn->opcode, i))
- return FALSE;
- break;
- case O_symbol:
- /* We only allow symbols for PC-relative references.
- If pc_frag == 0, then we don't have frag locations yet. */
- if (pc_frag == 0
- || xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 0)
- return FALSE;
- /* If it is a weak symbol or a symbol in a different section,
- it cannot be known to fit at assembly time. */
- if (S_IS_WEAK (exp->X_add_symbol)
- || S_GET_SEGMENT (exp->X_add_symbol) != pc_seg)
- {
- /* For a direct call with --no-longcalls, be optimistic and
- assume it will be in range. If the symbol is weak and
- undefined, it may remain undefined at link-time, in which
- case it will have a zero value and almost certainly be out
- of range for a direct call; thus, relax for undefined weak
- symbols even if longcalls is not enabled. */
- if (is_direct_call_opcode (insn->opcode)
- && ! pc_frag->tc_frag_data.use_longcalls
- && (! S_IS_WEAK (exp->X_add_symbol)
- || S_IS_DEFINED (exp->X_add_symbol)))
- return TRUE;
- return FALSE;
- }
- symbolP = exp->X_add_symbol;
- sym_frag = symbol_get_frag (symbolP);
- target = S_GET_VALUE (symbolP) + exp->X_add_number;
- pc = pc_frag->fr_address + pc_offset;
- /* If frag has yet to be reached on this pass, assume it
- will move by STRETCH just as we did. If this is not so,
- it will be because some frag between grows, and that will
- force another pass. Beware zero-length frags. There
- should be a faster way to do this. */
- if (stretch != 0
- && sym_frag->relax_marker != pc_frag->relax_marker
- && S_GET_SEGMENT (symbolP) == pc_seg)
- {
- target += stretch;
- }
- new_offset = target;
- xtensa_operand_do_reloc (isa, insn->opcode, i, &new_offset, pc);
- if (xg_check_operand (new_offset, insn->opcode, i))
- return FALSE;
- break;
- default:
- /* The symbol should have a fixup associated with it. */
- return FALSE;
- }
- }
- return TRUE;
- }
- /* Return TRUE on success. */
- static bfd_boolean
- xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
- {
- BuildOp *op;
- symbolS *sym;
- tinsn_init (targ);
- targ->debug_line = insn->debug_line;
- targ->loc_directive_seen = insn->loc_directive_seen;
- switch (bi->typ)
- {
- case INSTR_INSTR:
- op = bi->ops;
- targ->opcode = bi->opcode;
- targ->insn_type = ITYPE_INSN;
- targ->is_specific_opcode = FALSE;
- for (; op != NULL; op = op->next)
- {
- int op_num = op->op_num;
- int op_data = op->op_data;
- gas_assert (op->op_num < MAX_INSN_ARGS);
- if (targ->ntok <= op_num)
- targ->ntok = op_num + 1;
- switch (op->typ)
- {
- case OP_CONSTANT:
- set_expr_const (&targ->tok[op_num], op_data);
- break;
- case OP_OPERAND:
- gas_assert (op_data < insn->ntok);
- copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
- break;
- case OP_FREEREG:
- if (insn->extra_arg.X_op != O_register)
- return FALSE;
- copy_expr (&targ->tok[op_num], &insn->extra_arg);
- break;
- case OP_LITERAL:
- sym = get_special_literal_symbol ();
- set_expr_symbol_offset (&targ->tok[op_num], sym, 0);
- if (insn->tok[op_data].X_op == O_tlsfunc
- || insn->tok[op_data].X_op == O_tlsarg)
- copy_expr (&targ->extra_arg, &insn->tok[op_data]);
- break;
- case OP_LABEL:
- sym = get_special_label_symbol ();
- set_expr_symbol_offset (&targ->tok[op_num], sym, 0);
- break;
- case OP_OPERAND_HI16U:
- case OP_OPERAND_LOW16U:
- gas_assert (op_data < insn->ntok);
- if (expr_is_const (&insn->tok[op_data]))
- {
- long val;
- copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
- val = xg_apply_userdef_op_fn (op->typ,
- targ->tok[op_num].
- X_add_number);
- targ->tok[op_num].X_add_number = val;
- }
- else
- {
- /* For const16 we can create relocations for these. */
- if (targ->opcode == XTENSA_UNDEFINED
- || (targ->opcode != xtensa_const16_opcode))
- return FALSE;
- gas_assert (op_data < insn->ntok);
- /* Need to build a O_lo16 or O_hi16. */
- copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
- if (targ->tok[op_num].X_op == O_symbol)
- {
- if (op->typ == OP_OPERAND_HI16U)
- targ->tok[op_num].X_op = O_hi16;
- else if (op->typ == OP_OPERAND_LOW16U)
- targ->tok[op_num].X_op = O_lo16;
- else
- return FALSE;
- }
- }
- break;
- default:
- /* currently handles:
- OP_OPERAND_LOW8
- OP_OPERAND_HI24S
- OP_OPERAND_F32MINUS */
- if (xg_has_userdef_op_fn (op->typ))
- {
- gas_assert (op_data < insn->ntok);
- if (expr_is_const (&insn->tok[op_data]))
- {
- long val;
- copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
- val = xg_apply_userdef_op_fn (op->typ,
- targ->tok[op_num].
- X_add_number);
- targ->tok[op_num].X_add_number = val;
- }
- else
- return FALSE; /* We cannot use a relocation for this. */
- break;
- }
- gas_assert (0);
- break;
- }
- }
- break;
- case INSTR_LITERAL_DEF:
- op = bi->ops;
- targ->opcode = XTENSA_UNDEFINED;
- targ->insn_type = ITYPE_LITERAL;
- targ->is_specific_opcode = FALSE;
- for (; op != NULL; op = op->next)
- {
- int op_num = op->op_num;
- int op_data = op->op_data;
- gas_assert (op->op_num < MAX_INSN_ARGS);
- if (targ->ntok <= op_num)
- targ->ntok = op_num + 1;
- switch (op->typ)
- {
- case OP_OPERAND:
- gas_assert (op_data < insn->ntok);
- /* We can only pass resolvable literals through. */
- if (!xg_valid_literal_expression (&insn->tok[op_data]))
- return FALSE;
- copy_expr (&targ->tok[op_num], &insn->tok[op_data]);
- break;
- case OP_LITERAL:
- case OP_CONSTANT:
- case OP_LABEL:
- default:
- gas_assert (0);
- break;
- }
- }
- break;
- case INSTR_LABEL_DEF:
- op = bi->ops;
- targ->opcode = XTENSA_UNDEFINED;
- targ->insn_type = ITYPE_LABEL;
- targ->is_specific_opcode = FALSE;
- /* Literal with no ops is a label? */
- gas_assert (op == NULL);
- break;
- default:
- gas_assert (0);
- }
- return TRUE;
- }
- /* Return TRUE on success. */
- static bfd_boolean
- xg_build_to_stack (IStack *istack, TInsn *insn, BuildInstr *bi)
- {
- for (; bi != NULL; bi = bi->next)
- {
- TInsn *next_insn = istack_push_space (istack);
- if (!xg_build_to_insn (next_insn, insn, bi))
- return FALSE;
- }
- return TRUE;
- }
- /* Return TRUE on valid expansion. */
- static bfd_boolean
- xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps)
- {
- int stack_size = istack->ninsn;
- int steps_taken = 0;
- TransitionTable *table = xg_build_widen_table (&transition_rule_cmp);
- TransitionList *l;
- gas_assert (insn->insn_type == ITYPE_INSN);
- gas_assert (insn->opcode < table->num_opcodes);
- for (l = table->table[insn->opcode]; l != NULL; l = l->next)
- {
- TransitionRule *rule = l->rule;
- if (xg_instruction_matches_rule (insn, rule))
- {
- if (lateral_steps == steps_taken)
- {
- int i;
- /* This is it. Expand the rule to the stack. */
- if (!xg_build_to_stack (istack, insn, rule->to_instr))
- return FALSE;
- /* Check to see if it fits. */
- for (i = stack_size; i < istack->ninsn; i++)
- {
- TInsn *tinsn = &istack->insn[i];
- if (tinsn->insn_type == ITYPE_INSN
- && !tinsn_has_symbolic_operands (tinsn)
- && !xg_immeds_fit (tinsn))
- {
- istack->ninsn = stack_size;
- return FALSE;
- }
- }
- return TRUE;
- }
- steps_taken++;
- }
- }
- return FALSE;
- }
- /* Relax the assembly instruction at least "min_steps".
- Return the number of steps taken.
- For relaxation to correctly terminate, every relaxation chain must
- terminate in one of two ways:
- 1. If the chain from one instruction to the next consists entirely of
- single instructions, then the chain *must* handle all possible
- immediates without failing. It must not ever fail because an
- immediate is out of range. The MOVI.N -> MOVI -> L32R relaxation
- chain is one example. L32R loads 32 bits, and there cannot be an
- immediate larger than 32 bits, so it satisfies this condition.
- Single instruction relaxation chains are as defined by
- xg_is_single_relaxable_instruction.
- 2. Otherwise, the chain must end in a multi-instruction expansion: e.g.,
- BNEZ.N -> BNEZ -> BNEZ.W15 -> BENZ.N/J
- Strictly speaking, in most cases you can violate condition 1 and be OK
- -- in particular when the last two instructions have the same single
- size. But nevertheless, you should guarantee the above two conditions.
- We could fix this so that single-instruction expansions correctly
- terminate when they can't handle the range, but the error messages are
- worse, and it actually turns out that in every case but one (18-bit wide
- branches), you need a multi-instruction expansion to get the full range
- anyway. And because 18-bit branches are handled identically to 15-bit
- branches, there isn't any point in changing it. */
- static int
- xg_assembly_relax (IStack *istack,
- TInsn *insn,
- segT pc_seg,
- fragS *pc_frag, /* if pc_frag == 0, not pc-relative */
- offsetT pc_offset, /* offset in fragment */
- int min_steps, /* minimum conversion steps */
- long stretch) /* number of bytes stretched so far */
- {
- int steps_taken = 0;
- /* Some of its immeds don't fit. Try to build a relaxed version.
- This may go through a couple of stages of single instruction
- transformations before we get there. */
- TInsn single_target;
- TInsn current_insn;
- int lateral_steps = 0;
- int istack_size = istack->ninsn;
- if (xg_symbolic_immeds_fit (insn, pc_seg, pc_frag, pc_offset, stretch)
- && steps_taken >= min_steps)
- {
- istack_push (istack, insn);
- return steps_taken;
- }
- current_insn = *insn;
- /* Walk through all of the single instruction expansions. */
- while (xg_is_single_relaxable_insn (¤t_insn, &single_target, FALSE))
- {
- steps_taken++;
- if (xg_symbolic_immeds_fit (&single_target, pc_seg, pc_frag, pc_offset,
- stretch))
- {
- if (steps_taken >= min_steps)
- {
- istack_push (istack, &single_target);
- return steps_taken;
- }
- }
- current_insn = single_target;
- }
- /* Now check for a multi-instruction expansion. */
- while (xg_is_relaxable_insn (¤t_insn, lateral_steps))
- {
- if (xg_symbolic_immeds_fit (¤t_insn, pc_seg, pc_frag, pc_offset,
- stretch))
- {
- if (steps_taken >= min_steps)
- {
- istack_push (istack, ¤t_insn);
- return steps_taken;
- }
- }
- steps_taken++;
- if (xg_expand_to_stack (istack, ¤t_insn, lateral_steps))
- {
- if (steps_taken >= min_steps)
- return steps_taken;
- }
- lateral_steps++;
- istack->ninsn = istack_size;
- }
- /* It's not going to work -- use the original. */
- istack_push (istack, insn);
- return steps_taken;
- }
- static void
- xg_finish_frag (char *last_insn,
- enum xtensa_relax_statesE frag_state,
- enum xtensa_relax_statesE slot0_state,
- int max_growth,
- bfd_boolean is_insn)
- {
- /* Finish off this fragment so that it has at LEAST the desired
- max_growth. If it doesn't fit in this fragment, close this one
- and start a new one. In either case, return a pointer to the
- beginning of the growth area. */
- fragS *old_frag;
- frag_grow (max_growth);
- old_frag = frag_now;
- frag_now->fr_opcode = last_insn;
- if (is_insn)
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, max_growth, max_growth,
- frag_state, frag_now->fr_symbol, frag_now->fr_offset, last_insn);
- old_frag->tc_frag_data.slot_subtypes[0] = slot0_state;
- xtensa_set_frag_assembly_state (frag_now);
- /* Just to make sure that we did not split it up. */
- gas_assert (old_frag->fr_next == frag_now);
- }
- /* Return TRUE if the target frag is one of the next non-empty frags. */
- static bfd_boolean
- is_next_frag_target (const fragS *fragP, const fragS *target)
- {
- if (fragP == NULL)
- return FALSE;
- for (; fragP; fragP = fragP->fr_next)
- {
- if (fragP == target)
- return TRUE;
- if (fragP->fr_fix != 0)
- return FALSE;
- if (fragP->fr_type == rs_fill && fragP->fr_offset != 0)
- return FALSE;
- if ((fragP->fr_type == rs_align || fragP->fr_type == rs_align_code)
- && ((fragP->fr_address % (1 << fragP->fr_offset)) != 0))
- return FALSE;
- if (fragP->fr_type == rs_space)
- return FALSE;
- }
- return FALSE;
- }
- static bfd_boolean
- is_branch_jmp_to_next (TInsn *insn, fragS *fragP)
- {
- xtensa_isa isa = xtensa_default_isa;
- int i;
- int num_ops = xtensa_opcode_num_operands (isa, insn->opcode);
- int target_op = -1;
- symbolS *sym;
- fragS *target_frag;
- if (xtensa_opcode_is_branch (isa, insn->opcode) != 1
- && xtensa_opcode_is_jump (isa, insn->opcode) != 1)
- return FALSE;
- for (i = 0; i < num_ops; i++)
- {
- if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1)
- {
- target_op = i;
- break;
- }
- }
- if (target_op == -1)
- return FALSE;
- if (insn->ntok <= target_op)
- return FALSE;
- if (insn->tok[target_op].X_op != O_symbol)
- return FALSE;
- sym = insn->tok[target_op].X_add_symbol;
- if (sym == NULL)
- return FALSE;
- if (insn->tok[target_op].X_add_number != 0)
- return FALSE;
- target_frag = symbol_get_frag (sym);
- if (target_frag == NULL)
- return FALSE;
- if (is_next_frag_target (fragP->fr_next, target_frag)
- && S_GET_VALUE (sym) == target_frag->fr_address)
- return TRUE;
- return FALSE;
- }
- static void
- xg_add_branch_and_loop_targets (TInsn *insn)
- {
- xtensa_isa isa = xtensa_default_isa;
- int num_ops = xtensa_opcode_num_operands (isa, insn->opcode);
- if (xtensa_opcode_is_loop (isa, insn->opcode) == 1)
- {
- int i = 1;
- if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1
- && insn->tok[i].X_op == O_symbol)
- symbol_get_tc (insn->tok[i].X_add_symbol)->is_loop_target = TRUE;
- return;
- }
- if (xtensa_opcode_is_branch (isa, insn->opcode) == 1
- || xtensa_opcode_is_loop (isa, insn->opcode) == 1)
- {
- int i;
- for (i = 0; i < insn->ntok && i < num_ops; i++)
- {
- if (xtensa_operand_is_PCrelative (isa, insn->opcode, i) == 1
- && insn->tok[i].X_op == O_symbol)
- {
- symbolS *sym = insn->tok[i].X_add_symbol;
- symbol_get_tc (sym)->is_branch_target = TRUE;
- if (S_IS_DEFINED (sym))
- symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
- }
- }
- }
- }
- /* Return FALSE if no error. */
- static bfd_boolean
- xg_build_token_insn (BuildInstr *instr_spec, TInsn *old_insn, TInsn *new_insn)
- {
- int num_ops = 0;
- BuildOp *b_op;
- switch (instr_spec->typ)
- {
- case INSTR_INSTR:
- new_insn->insn_type = ITYPE_INSN;
- new_insn->opcode = instr_spec->opcode;
- break;
- case INSTR_LITERAL_DEF:
- new_insn->insn_type = ITYPE_LITERAL;
- new_insn->opcode = XTENSA_UNDEFINED;
- break;
- case INSTR_LABEL_DEF:
- abort ();
- }
- new_insn->is_specific_opcode = FALSE;
- new_insn->debug_line = old_insn->debug_line;
- new_insn->loc_directive_seen = old_insn->loc_directive_seen;
- for (b_op = instr_spec->ops; b_op != NULL; b_op = b_op->next)
- {
- expressionS *exp;
- const expressionS *src_exp;
- num_ops++;
- switch (b_op->typ)
- {
- case OP_CONSTANT:
- /* The expression must be the constant. */
- gas_assert (b_op->op_num < MAX_INSN_ARGS);
- exp = &new_insn->tok[b_op->op_num];
- set_expr_const (exp, b_op->op_data);
- break;
- case OP_OPERAND:
- gas_assert (b_op->op_num < MAX_INSN_ARGS);
- gas_assert (b_op->op_data < (unsigned) old_insn->ntok);
- src_exp = &old_insn->tok[b_op->op_data];
- exp = &new_insn->tok[b_op->op_num];
- copy_expr (exp, src_exp);
- break;
- case OP_LITERAL:
- case OP_LABEL:
- as_bad (_("can't handle generation of literal/labels yet"));
- gas_assert (0);
- default:
- as_bad (_("can't handle undefined OP TYPE"));
- gas_assert (0);
- }
- }
- new_insn->ntok = num_ops;
- return FALSE;
- }
- /* Return TRUE if it was simplified. */
- static bfd_boolean
- xg_simplify_insn (TInsn *old_insn, TInsn *new_insn)
- {
- TransitionRule *rule;
- BuildInstr *insn_spec;
- if (old_insn->is_specific_opcode || !density_supported)
- return FALSE;
- rule = xg_instruction_match (old_insn);
- if (rule == NULL)
- return FALSE;
- insn_spec = rule->to_instr;
- /* There should only be one. */
- gas_assert (insn_spec != NULL);
- gas_assert (insn_spec->next == NULL);
- if (insn_spec->next != NULL)
- return FALSE;
- xg_build_token_insn (insn_spec, old_insn, new_insn);
- return TRUE;
- }
- /* xg_expand_assembly_insn: (1) Simplify the instruction, i.e., l32i ->
- l32i.n. (2) Check the number of operands. (3) Place the instruction
- tokens into the stack or relax it and place multiple
- instructions/literals onto the stack. Return FALSE if no error. */
- static bfd_boolean
- xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn)
- {
- int noperands;
- TInsn new_insn;
- bfd_boolean do_expand;
- tinsn_init (&new_insn);
- /* Narrow it if we can. xg_simplify_insn now does all the
- appropriate checking (e.g., for the density option). */
- if (xg_simplify_insn (orig_insn, &new_insn))
- orig_insn = &new_insn;
- noperands = xtensa_opcode_num_operands (xtensa_default_isa,
- orig_insn->opcode);
- if (orig_insn->ntok < noperands)
- {
- as_bad (_("found %d operands for '%s': Expected %d"),
- orig_insn->ntok,
- xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
- noperands);
- return TRUE;
- }
- if (orig_insn->ntok > noperands)
- as_warn (_("found too many (%d) operands for '%s': Expected %d"),
- orig_insn->ntok,
- xtensa_opcode_name (xtensa_default_isa, orig_insn->opcode),
- noperands);
- /* If there are not enough operands, we will assert above. If there
- are too many, just cut out the extras here. */
- orig_insn->ntok = noperands;
- if (tinsn_has_invalid_symbolic_operands (orig_insn))
- return TRUE;
- /* Special case for extui opcode which has constraints not handled
- by the ordinary operand encoding checks. The number of operands
- and related syntax issues have already been checked. */
- if (orig_insn->opcode == xtensa_extui_opcode)
- {
- int shiftimm = orig_insn->tok[2].X_add_number;
- int maskimm = orig_insn->tok[3].X_add_number;
- if (shiftimm + maskimm > 32)
- {
- as_bad (_("immediate operands sum to greater than 32"));
- return TRUE;
- }
- }
- /* If the instruction will definitely need to be relaxed, it is better
- to expand it now for better scheduling. Decide whether to expand
- now.... */
- do_expand = (!orig_insn->is_specific_opcode && use_transform ());
- /* Calls should be expanded to longcalls only in the backend relaxation
- so that the assembly scheduler will keep the L32R/CALLX instructions
- adjacent. */
- if (is_direct_call_opcode (orig_insn->opcode))
- do_expand = FALSE;
- if (tinsn_has_symbolic_operands (orig_insn))
- {
- /* The values of symbolic operands are not known yet, so only expand
- now if an operand is "complex" (e.g., difference of symbols) and
- will have to be stored as a literal regardless of the value. */
- if (!tinsn_has_complex_operands (orig_insn))
- do_expand = FALSE;
- }
- else if (xg_immeds_fit (orig_insn))
- do_expand = FALSE;
- if (do_expand)
- xg_assembly_relax (istack, orig_insn, 0, 0, 0, 0, 0);
- else
- istack_push (istack, orig_insn);
- return FALSE;
- }
- /* Return TRUE if the section flags are marked linkonce
- or the name is .gnu.linkonce.*. */
- static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
- static bfd_boolean
- get_is_linkonce_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec)
- {
- flagword flags, link_once_flags;
- flags = bfd_get_section_flags (abfd, sec);
- link_once_flags = (flags & SEC_LINK_ONCE);
- /* Flags might not be set yet. */
- if (!link_once_flags
- && strncmp (segment_name (sec), ".gnu.linkonce.", linkonce_len) == 0)
- link_once_flags = SEC_LINK_ONCE;
- return (link_once_flags != 0);
- }
- static void
- xtensa_add_literal_sym (symbolS *sym)
- {
- sym_list *l;
- l = (sym_list *) xmalloc (sizeof (sym_list));
- l->sym = sym;
- l->next = literal_syms;
- literal_syms = l;
- }
- static symbolS *
- xtensa_create_literal_symbol (segT sec, fragS *frag)
- {
- static int lit_num = 0;
- static char name[256];
- symbolS *symbolP;
- sprintf (name, ".L_lit_sym%d", lit_num);
- /* Create a local symbol. If it is in a linkonce section, we have to
- be careful to make sure that if it is used in a relocation that the
- symbol will be in the output file. */
- if (get_is_linkonce_section (stdoutput, sec))
- {
- symbolP = symbol_new (name, sec, 0, frag);
- S_CLEAR_EXTERNAL (symbolP);
- /* symbolP->local = 1; */
- }
- else
- symbolP = symbol_new (name, sec, 0, frag);
- xtensa_add_literal_sym (symbolP);
- lit_num++;
- return symbolP;
- }
- /* Currently all literals that are generated here are 32-bit L32R targets. */
- static symbolS *
- xg_assemble_literal (/* const */ TInsn *insn)
- {
- emit_state state;
- symbolS *lit_sym = NULL;
- bfd_reloc_code_real_type reloc;
- bfd_boolean pcrel = FALSE;
- char *p;
- /* size = 4 for L32R. It could easily be larger when we move to
- larger constants. Add a parameter later. */
- offsetT litsize = 4;
- offsetT litalign = 2; /* 2^2 = 4 */
- expressionS saved_loc;
- expressionS * emit_val;
- set_expr_symbol_offset (&saved_loc, frag_now->fr_symbol, frag_now_fix ());
- gas_assert (insn->insn_type == ITYPE_LITERAL);
- gas_assert (insn->ntok == 1); /* must be only one token here */
- xtensa_switch_to_literal_fragment (&state);
- emit_val = &insn->tok[0];
- if (emit_val->X_op == O_big)
- {
- int size = emit_val->X_add_number * CHARS_PER_LITTLENUM;
- if (size > litsize)
- {
- /* This happens when someone writes a "movi a2, big_number". */
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
- _("invalid immediate"));
- xtensa_restore_emit_state (&state);
- return NULL;
- }
- }
- /* Force a 4-byte align here. Note that this opens a new frag, so all
- literals done with this function have a frag to themselves. That's
- important for the way text section literals work. */
- frag_align (litalign, 0, 0);
- record_alignment (now_seg, litalign);
- switch (emit_val->X_op)
- {
- case O_pcrel:
- pcrel = TRUE;
- /* fall through */
- case O_pltrel:
- case O_tlsfunc:
- case O_tlsarg:
- case O_tpoff:
- case O_dtpoff:
- p = frag_more (litsize);
- xtensa_set_frag_assembly_state (frag_now);
- reloc = map_operator_to_reloc (emit_val->X_op, TRUE);
- if (emit_val->X_add_symbol)
- emit_val->X_op = O_symbol;
- else
- emit_val->X_op = O_constant;
- fix_new_exp (frag_now, p - frag_now->fr_literal,
- litsize, emit_val, pcrel, reloc);
- break;
- default:
- emit_expr (emit_val, litsize);
- break;
- }
- gas_assert (frag_now->tc_frag_data.literal_frag == NULL);
- frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg);
- frag_now->fr_symbol = xtensa_create_literal_symbol (now_seg, frag_now);
- lit_sym = frag_now->fr_symbol;
- /* Go back. */
- xtensa_restore_emit_state (&state);
- return lit_sym;
- }
- static void
- xg_assemble_literal_space (/* const */ int size, int slot)
- {
- emit_state state;
- /* We might have to do something about this alignment. It only
- takes effect if something is placed here. */
- offsetT litalign = 2; /* 2^2 = 4 */
- fragS *lit_saved_frag;
- gas_assert (size % 4 == 0);
- xtensa_switch_to_literal_fragment (&state);
- /* Force a 4-byte align here. */
- frag_align (litalign, 0, 0);
- record_alignment (now_seg, litalign);
- frag_grow (size);
- lit_saved_frag = frag_now;
- frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg);
- frag_now->fr_symbol = xtensa_create_literal_symbol (now_seg, frag_now);
- xg_finish_frag (0, RELAX_LITERAL, 0, size, FALSE);
- /* Go back. */
- xtensa_restore_emit_state (&state);
- frag_now->tc_frag_data.literal_frags[slot] = lit_saved_frag;
- }
- /* Put in a fixup record based on the opcode.
- Return TRUE on success. */
- static bfd_boolean
- xg_add_opcode_fix (TInsn *tinsn,
- int opnum,
- xtensa_format fmt,
- int slot,
- expressionS *exp,
- fragS *fragP,
- offsetT offset)
- {
- xtensa_opcode opcode = tinsn->opcode;
- bfd_reloc_code_real_type reloc;
- reloc_howto_type *howto;
- int fmt_length;
- fixS *the_fix;
- reloc = BFD_RELOC_NONE;
- /* First try the special cases for "alternate" relocs. */
- if (opcode == xtensa_l32r_opcode)
- {
- if (fragP->tc_frag_data.use_absolute_literals)
- reloc = encode_alt_reloc (slot);
- }
- else if (opcode == xtensa_const16_opcode)
- {
- if (exp->X_op == O_lo16)
- {
- reloc = encode_reloc (slot);
- exp->X_op = O_symbol;
- }
- else if (exp->X_op == O_hi16)
- {
- reloc = encode_alt_reloc (slot);
- exp->X_op = O_symbol;
- }
- }
- if (opnum != get_relaxable_immed (opcode))
- {
- as_bad (_("invalid relocation for operand %i of '%s'"),
- opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
- }
- /* Handle erroneous "@h" and "@l" expressions here before they propagate
- into the symbol table where the generic portions of the assembler
- won't know what to do with them. */
- if (exp->X_op == O_lo16 || exp->X_op == O_hi16)
- {
- as_bad (_("invalid expression for operand %i of '%s'"),
- opnum + 1, xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
- }
- /* Next try the generic relocs. */
- if (reloc == BFD_RELOC_NONE)
- reloc = encode_reloc (slot);
- if (reloc == BFD_RELOC_NONE)
- {
- as_bad (_("invalid relocation in instruction slot %i"), slot);
- return FALSE;
- }
- howto = bfd_reloc_type_lookup (stdoutput, reloc);
- if (!howto)
- {
- as_bad (_("undefined symbol for opcode \"%s\""),
- xtensa_opcode_name (xtensa_default_isa, opcode));
- return FALSE;
- }
- fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
- the_fix = fix_new_exp (fragP, offset, fmt_length, exp,
- howto->pc_relative, reloc);
- the_fix->fx_no_overflow = 1;
- the_fix->tc_fix_data.X_add_symbol = exp->X_add_symbol;
- the_fix->tc_fix_data.X_add_number = exp->X_add_number;
- the_fix->tc_fix_data.slot = slot;
- return TRUE;
- }
- static bfd_boolean
- xg_emit_insn_to_buf (TInsn *tinsn,
- char *buf,
- fragS *fragP,
- offsetT offset,
- bfd_boolean build_fix)
- {
- static xtensa_insnbuf insnbuf = NULL;
- bfd_boolean has_symbolic_immed = FALSE;
- bfd_boolean ok = TRUE;
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
- has_symbolic_immed = tinsn_to_insnbuf (tinsn, insnbuf);
- if (has_symbolic_immed && build_fix)
- {
- /* Add a fixup. */
- xtensa_format fmt = xg_get_single_format (tinsn->opcode);
- int slot = xg_get_single_slot (tinsn->opcode);
- int opnum = get_relaxable_immed (tinsn->opcode);
- expressionS *exp = &tinsn->tok[opnum];
- if (!xg_add_opcode_fix (tinsn, opnum, fmt, slot, exp, fragP, offset))
- ok = FALSE;
- }
- fragP->tc_frag_data.is_insn = TRUE;
- xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf,
- (unsigned char *) buf, 0);
- return ok;
- }
- static void
- xg_resolve_literals (TInsn *insn, symbolS *lit_sym)
- {
- symbolS *sym = get_special_literal_symbol ();
- int i;
- if (lit_sym == 0)
- return;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < insn->ntok; i++)
- if (insn->tok[i].X_add_symbol == sym)
- insn->tok[i].X_add_symbol = lit_sym;
- }
- static void
- xg_resolve_labels (TInsn *insn, symbolS *label_sym)
- {
- symbolS *sym = get_special_label_symbol ();
- int i;
- for (i = 0; i < insn->ntok; i++)
- if (insn->tok[i].X_add_symbol == sym)
- insn->tok[i].X_add_symbol = label_sym;
- }
- /* Return TRUE if the instruction can write to the specified
- integer register. */
- static bfd_boolean
- is_register_writer (const TInsn *insn, const char *regset, int regnum)
- {
- int i;
- int num_ops;
- xtensa_isa isa = xtensa_default_isa;
- num_ops = xtensa_opcode_num_operands (isa, insn->opcode);
- for (i = 0; i < num_ops; i++)
- {
- char inout;
- inout = xtensa_operand_inout (isa, insn->opcode, i);
- if ((inout == 'o' || inout == 'm')
- && xtensa_operand_is_register (isa, insn->opcode, i) == 1)
- {
- xtensa_regfile opnd_rf =
- xtensa_operand_regfile (isa, insn->opcode, i);
- if (!strcmp (xtensa_regfile_shortname (isa, opnd_rf), regset))
- {
- if ((insn->tok[i].X_op == O_register)
- && (insn->tok[i].X_add_number == regnum))
- return TRUE;
- }
- }
- }
- return FALSE;
- }
- static bfd_boolean
- is_bad_loopend_opcode (const TInsn *tinsn)
- {
- xtensa_opcode opcode = tinsn->opcode;
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
- if (opcode == xtensa_call0_opcode
- || opcode == xtensa_callx0_opcode
- || opcode == xtensa_call4_opcode
- || opcode == xtensa_callx4_opcode
- || opcode == xtensa_call8_opcode
- || opcode == xtensa_callx8_opcode
- || opcode == xtensa_call12_opcode
- || opcode == xtensa_callx12_opcode
- || opcode == xtensa_isync_opcode
- || opcode == xtensa_ret_opcode
- || opcode == xtensa_ret_n_opcode
- || opcode == xtensa_retw_opcode
- || opcode == xtensa_retw_n_opcode
- || opcode == xtensa_waiti_opcode
- || opcode == xtensa_rsr_lcount_opcode)
- return TRUE;
- return FALSE;
- }
- /* Labels that begin with ".Ln" or ".LM" are unaligned.
- This allows the debugger to add unaligned labels.
- Also, the assembler generates stabs labels that need
- not be aligned: FAKE_LABEL_NAME . {"F", "L", "endfunc"}. */
- static bfd_boolean
- is_unaligned_label (symbolS *sym)
- {
- const char *name = S_GET_NAME (sym);
- static size_t fake_size = 0;
- if (name
- && name[0] == '.'
- && name[1] == 'L' && (name[2] == 'n' || name[2] == 'M'))
- return TRUE;
- /* FAKE_LABEL_NAME followed by "F", "L" or "endfunc" */
- if (fake_size == 0)
- fake_size = strlen (FAKE_LABEL_NAME);
- if (name
- && strncmp (FAKE_LABEL_NAME, name, fake_size) == 0
- && (name[fake_size] == 'F'
- || name[fake_size] == 'L'
- || (name[fake_size] == 'e'
- && strncmp ("endfunc", name+fake_size, 7) == 0)))
- return TRUE;
- return FALSE;
- }
- static fragS *
- next_non_empty_frag (const fragS *fragP)
- {
- fragS *next_fragP = fragP->fr_next;
- /* Sometimes an empty will end up here due storage allocation issues.
- So we have to skip until we find something legit. */
- while (next_fragP && next_fragP->fr_fix == 0)
- next_fragP = next_fragP->fr_next;
- if (next_fragP == NULL || next_fragP->fr_fix == 0)
- return NULL;
- return next_fragP;
- }
- static bfd_boolean
- next_frag_opcode_is_loop (const fragS *fragP, xtensa_opcode *opcode)
- {
- xtensa_opcode out_opcode;
- const fragS *next_fragP = next_non_empty_frag (fragP);
- if (next_fragP == NULL)
- return FALSE;
- out_opcode = get_opcode_from_buf (next_fragP->fr_literal, 0);
- if (xtensa_opcode_is_loop (xtensa_default_isa, out_opcode) == 1)
- {
- *opcode = out_opcode;
- return TRUE;
- }
- return FALSE;
- }
- static int
- frag_format_size (const fragS *fragP)
- {
- static xtensa_insnbuf insnbuf = NULL;
- xtensa_isa isa = xtensa_default_isa;
- xtensa_format fmt;
- int fmt_size;
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
- if (fragP == NULL)
- return XTENSA_UNDEFINED;
- xtensa_insnbuf_from_chars (isa, insnbuf,
- (unsigned char *) fragP->fr_literal, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- return XTENSA_UNDEFINED;
- fmt_size = xtensa_format_length (isa, fmt);
- /* If the next format won't be changing due to relaxation, just
- return the length of the first format. */
- if (fragP->fr_opcode != fragP->fr_literal)
- return fmt_size;
- /* If during relaxation we have to pull an instruction out of a
- multi-slot instruction, we will return the more conservative
- number. This works because alignment on bigger instructions
- is more restrictive than alignment on smaller instructions.
- This is more conservative than we would like, but it happens
- infrequently. */
- if (xtensa_format_num_slots (xtensa_default_isa, fmt) > 1)
- return fmt_size;
- /* If we aren't doing one of our own relaxations or it isn't
- slot-based, then the insn size won't change. */
- if (fragP->fr_type != rs_machine_dependent)
- return fmt_size;
- if (fragP->fr_subtype != RELAX_SLOTS)
- return fmt_size;
- /* If an instruction is about to grow, return the longer size. */
- if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1
- || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2
- || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP3)
- {
- /* For most frags at RELAX_IMMED_STEPX, with X > 0, the first
- instruction in the relaxed version is of length 3. (The case
- where we have to pull the instruction out of a FLIX bundle
- is handled conservatively above.) However, frags with opcodes
- that are expanding to wide branches end up having formats that
- are not determinable by the RELAX_IMMED_STEPX enumeration, and
- we can't tell directly what format the relaxer picked. This
- is a wart in the design of the relaxer that should someday be
- fixed, but would require major changes, or at least should
- be accompanied by major changes to make use of that data.
- In any event, we can tell that we are expanding from a single-slot
- format to a wider one with the logic below. */
- int i;
- int relaxed_size = fmt_size + fragP->tc_frag_data.text_expansion[0];
- for (i = 0; i < xtensa_isa_num_formats (isa); i++)
- {
- if (relaxed_size == xtensa_format_length (isa, i))
- return relaxed_size;
- }
- return 3;
- }
- if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
- return 2 + fragP->tc_frag_data.text_expansion[0];
- return fmt_size;
- }
- static int
- next_frag_format_size (const fragS *fragP)
- {
- const fragS *next_fragP = next_non_empty_frag (fragP);
- return frag_format_size (next_fragP);
- }
- /* In early Xtensa Processors, for reasons that are unclear, the ISA
- required two-byte instructions to be treated as three-byte instructions
- for loop instruction alignment. This restriction was removed beginning
- with Xtensa LX. Now the only requirement on loop instruction alignment
- is that the first instruction of the loop must appear at an address that
- does not cross a fetch boundary. */
- static int
- get_loop_align_size (int insn_size)
- {
- if (insn_size == XTENSA_UNDEFINED)
- return xtensa_fetch_width;
- if (enforce_three_byte_loop_align && insn_size == 2)
- return 3;
- return insn_size;
- }
- /* If the next legit fragment is an end-of-loop marker,
- switch its state so it will instantiate a NOP. */
- static void
- update_next_frag_state (fragS *fragP)
- {
- fragS *next_fragP = fragP->fr_next;
- fragS *new_target = NULL;
- if (align_targets)
- {
- /* We are guaranteed there will be one of these... */
- while (!(next_fragP->fr_type == rs_machine_dependent
- && (next_fragP->fr_subtype == RELAX_MAYBE_UNREACHABLE
- || next_fragP->fr_subtype == RELAX_UNREACHABLE)))
- next_fragP = next_fragP->fr_next;
- gas_assert (next_fragP->fr_type == rs_machine_dependent
- && (next_fragP->fr_subtype == RELAX_MAYBE_UNREACHABLE
- || next_fragP->fr_subtype == RELAX_UNREACHABLE));
- /* ...and one of these. */
- new_target = next_fragP->fr_next;
- while (!(new_target->fr_type == rs_machine_dependent
- && (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN
- || new_target->fr_subtype == RELAX_DESIRE_ALIGN)))
- new_target = new_target->fr_next;
- gas_assert (new_target->fr_type == rs_machine_dependent
- && (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN
- || new_target->fr_subtype == RELAX_DESIRE_ALIGN));
- }
- while (next_fragP && next_fragP->fr_fix == 0)
- {
- if (next_fragP->fr_type == rs_machine_dependent
- && next_fragP->fr_subtype == RELAX_LOOP_END)
- {
- next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP;
- return;
- }
- next_fragP = next_fragP->fr_next;
- }
- }
- static bfd_boolean
- next_frag_is_branch_target (const fragS *fragP)
- {
- /* Sometimes an empty will end up here due to storage allocation issues,
- so we have to skip until we find something legit. */
- for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
- {
- if (fragP->tc_frag_data.is_branch_target)
- return TRUE;
- if (fragP->fr_fix != 0)
- break;
- }
- return FALSE;
- }
- static bfd_boolean
- next_frag_is_loop_target (const fragS *fragP)
- {
- /* Sometimes an empty will end up here due storage allocation issues.
- So we have to skip until we find something legit. */
- for (fragP = fragP->fr_next; fragP; fragP = fragP->fr_next)
- {
- if (fragP->tc_frag_data.is_loop_target)
- return TRUE;
- if (fragP->fr_fix != 0)
- break;
- }
- return FALSE;
- }
- /* As specified in the relaxation table, when a loop instruction is
- relaxed, there are 24 bytes between the loop instruction itself and
- the first instruction in the loop. */
- #define RELAXED_LOOP_INSN_BYTES 24
- static addressT
- next_frag_pre_opcode_bytes (const fragS *fragp)
- {
- const fragS *next_fragp = fragp->fr_next;
- xtensa_opcode next_opcode;
- if (!next_frag_opcode_is_loop (fragp, &next_opcode))
- return 0;
- /* Sometimes an empty will end up here due to storage allocation issues,
- so we have to skip until we find something legit. */
- while (next_fragp->fr_fix == 0)
- next_fragp = next_fragp->fr_next;
- if (next_fragp->fr_type != rs_machine_dependent)
- return 0;
- /* There is some implicit knowledge encoded in here.
- The LOOP instructions that are NOT RELAX_IMMED have
- been relaxed. Note that we can assume that the LOOP
- instruction is in slot 0 because loops aren't bundleable. */
- if (next_fragp->tc_frag_data.slot_subtypes[0] > RELAX_IMMED)
- return get_expanded_loop_offset (next_opcode) + RELAXED_LOOP_INSN_BYTES;
- return 0;
- }
- /* Mark a location where we can later insert literal frags. Update
- the section's literal_pool_loc, so subsequent literals can be
- placed nearest to their use. */
- static void
- xtensa_mark_literal_pool_location (void)
- {
- /* Any labels pointing to the current location need
- to be adjusted to after the literal pool. */
- emit_state s;
- fragS *pool_location;
- if (use_literal_section)
- return;
- /* We stash info in these frags so we can later move the literal's
- fixes into this frchain's fix list. */
- pool_location = frag_now;
- frag_now->tc_frag_data.lit_frchain = frchain_now;
- frag_now->tc_frag_data.literal_frag = frag_now;
- /* Just record this frag. */
- xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
- frag_variant (rs_machine_dependent, 0, 0,
- RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.lit_seg = now_seg;
- frag_variant (rs_machine_dependent, 0, 0,
- RELAX_LITERAL_POOL_END, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- /* Now put a frag into the literal pool that points to this location. */
- set_literal_pool_location (now_seg, pool_location);
- xtensa_switch_to_non_abs_literal_fragment (&s);
- frag_align (2, 0, 0);
- record_alignment (now_seg, 2);
- /* Close whatever frag is there. */
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.literal_frag = pool_location;
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_restore_emit_state (&s);
- xtensa_set_frag_assembly_state (frag_now);
- }
- /* Build a nop of the correct size into tinsn. */
- static void
- build_nop (TInsn *tinsn, int size)
- {
- tinsn_init (tinsn);
- switch (size)
- {
- case 2:
- tinsn->opcode = xtensa_nop_n_opcode;
- tinsn->ntok = 0;
- if (tinsn->opcode == XTENSA_UNDEFINED)
- as_fatal (_("opcode 'NOP.N' unavailable in this configuration"));
- break;
- case 3:
- if (xtensa_nop_opcode == XTENSA_UNDEFINED)
- {
- tinsn->opcode = xtensa_or_opcode;
- set_expr_const (&tinsn->tok[0], 1);
- set_expr_const (&tinsn->tok[1], 1);
- set_expr_const (&tinsn->tok[2], 1);
- tinsn->ntok = 3;
- }
- else
- tinsn->opcode = xtensa_nop_opcode;
- gas_assert (tinsn->opcode != XTENSA_UNDEFINED);
- }
- }
- /* Assemble a NOP of the requested size in the buffer. User must have
- allocated "buf" with at least "size" bytes. */
- static void
- assemble_nop (int size, char *buf)
- {
- static xtensa_insnbuf insnbuf = NULL;
- TInsn tinsn;
- build_nop (&tinsn, size);
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
- tinsn_to_insnbuf (&tinsn, insnbuf);
- xtensa_insnbuf_to_chars (xtensa_default_isa, insnbuf,
- (unsigned char *) buf, 0);
- }
- /* Return the number of bytes for the offset of the expanded loop
- instruction. This should be incorporated into the relaxation
- specification but is hard-coded here. This is used to auto-align
- the loop instruction. It is invalid to call this function if the
- configuration does not have loops or if the opcode is not a loop
- opcode. */
- static addressT
- get_expanded_loop_offset (xtensa_opcode opcode)
- {
- /* This is the OFFSET of the loop instruction in the expanded loop.
- This MUST correspond directly to the specification of the loop
- expansion. It will be validated on fragment conversion. */
- gas_assert (opcode != XTENSA_UNDEFINED);
- if (opcode == xtensa_loop_opcode)
- return 0;
- if (opcode == xtensa_loopnez_opcode)
- return 3;
- if (opcode == xtensa_loopgtz_opcode)
- return 6;
- as_fatal (_("get_expanded_loop_offset: invalid opcode"));
- return 0;
- }
- static fragS *
- get_literal_pool_location (segT seg)
- {
- struct litpool_seg *lps = litpool_seg_list.next;
- struct litpool_frag *lpf;
- for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
- ;
- if (lps)
- {
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- { /* Skip "candidates" for now. */
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
- lpf->priority == 1)
- return lpf->fragP;
- }
- /* Must convert a lower-priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- {
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- return lpf->fragP;
- }
- /* Still no match -- try for a low priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- {
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- return lpf->fragP;
- }
- }
- return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
- }
- static void
- set_literal_pool_location (segT seg, fragS *literal_pool_loc)
- {
- seg_info (seg)->tc_segment_info_data.literal_pool_loc = literal_pool_loc;
- }
- /* Set frag assembly state should be called when a new frag is
- opened and after a frag has been closed. */
- static void
- xtensa_set_frag_assembly_state (fragS *fragP)
- {
- if (!density_supported)
- fragP->tc_frag_data.is_no_density = TRUE;
- /* This function is called from subsegs_finish, which is called
- after xtensa_end, so we can't use "use_transform" or
- "use_schedule" here. */
- if (!directive_state[directive_transform])
- fragP->tc_frag_data.is_no_transform = TRUE;
- if (directive_state[directive_longcalls])
- fragP->tc_frag_data.use_longcalls = TRUE;
- fragP->tc_frag_data.use_absolute_literals =
- directive_state[directive_absolute_literals];
- fragP->tc_frag_data.is_assembly_state_set = TRUE;
- }
- static bfd_boolean
- relaxable_section (asection *sec)
- {
- return ((sec->flags & SEC_DEBUGGING) == 0
- && strcmp (sec->name, ".eh_frame") != 0);
- }
- static void
- xtensa_mark_frags_for_org (void)
- {
- segT *seclist;
- /* Walk over each fragment of all of the current segments. If we find
- a .org frag in any of the segments, mark all frags prior to it as
- "no transform", which will prevent linker optimizations from messing
- up the .org distance. This should be done after
- xtensa_find_unmarked_state_frags, because we don't want to worry here
- about that function trashing the data we save here. */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segT sec = *seclist;
- segment_info_type *seginfo;
- fragS *fragP;
- flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
- if (flags & SEC_DEBUGGING)
- continue;
- if (!(flags & SEC_ALLOC))
- continue;
- seginfo = seg_info (sec);
- if (seginfo && seginfo->frchainP)
- {
- fragS *last_fragP = seginfo->frchainP->frch_root;
- for (fragP = seginfo->frchainP->frch_root; fragP;
- fragP = fragP->fr_next)
- {
- /* cvt_frag_to_fill has changed the fr_type of org frags to
- rs_fill, so use the value as cached in rs_subtype here. */
- if (fragP->fr_subtype == RELAX_ORG)
- {
- while (last_fragP != fragP->fr_next)
- {
- last_fragP->tc_frag_data.is_no_transform = TRUE;
- last_fragP = last_fragP->fr_next;
- }
- }
- }
- }
- }
- }
- static void
- xtensa_find_unmarked_state_frags (void)
- {
- segT *seclist;
- /* Walk over each fragment of all of the current segments. For each
- unmarked fragment, mark it with the same info as the previous
- fragment. */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segT sec = *seclist;
- segment_info_type *seginfo;
- fragS *fragP;
- flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
- if (flags & SEC_DEBUGGING)
- continue;
- if (!(flags & SEC_ALLOC))
- continue;
- seginfo = seg_info (sec);
- if (seginfo && seginfo->frchainP)
- {
- fragS *last_fragP = 0;
- for (fragP = seginfo->frchainP->frch_root; fragP;
- fragP = fragP->fr_next)
- {
- if (fragP->fr_fix != 0
- && !fragP->tc_frag_data.is_assembly_state_set)
- {
- if (last_fragP == 0)
- {
- as_warn_where (fragP->fr_file, fragP->fr_line,
- _("assembly state not set for first frag in section %s"),
- sec->name);
- }
- else
- {
- fragP->tc_frag_data.is_assembly_state_set = TRUE;
- fragP->tc_frag_data.is_no_density =
- last_fragP->tc_frag_data.is_no_density;
- fragP->tc_frag_data.is_no_transform =
- last_fragP->tc_frag_data.is_no_transform;
- fragP->tc_frag_data.use_longcalls =
- last_fragP->tc_frag_data.use_longcalls;
- fragP->tc_frag_data.use_absolute_literals =
- last_fragP->tc_frag_data.use_absolute_literals;
- }
- }
- if (fragP->tc_frag_data.is_assembly_state_set)
- last_fragP = fragP;
- }
- }
- }
- }
- static void
- xtensa_find_unaligned_branch_targets (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec,
- void *unused ATTRIBUTE_UNUSED)
- {
- flagword flags = bfd_get_section_flags (abfd, sec);
- segment_info_type *seginfo = seg_info (sec);
- fragS *frag = seginfo->frchainP->frch_root;
- if (flags & SEC_CODE)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
- while (frag != NULL)
- {
- if (frag->tc_frag_data.is_branch_target)
- {
- int op_size;
- addressT branch_align, frag_addr;
- xtensa_format fmt;
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- op_size = xtensa_format_length (isa, fmt);
- branch_align = 1 << branch_align_power (sec);
- frag_addr = frag->fr_address % branch_align;
- if (frag_addr + op_size > branch_align)
- as_warn_where (frag->fr_file, frag->fr_line,
- _("unaligned branch target: %d bytes at 0x%lx"),
- op_size, (long) frag->fr_address);
- }
- frag = frag->fr_next;
- }
- xtensa_insnbuf_free (isa, insnbuf);
- }
- }
- static void
- xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec,
- void *unused ATTRIBUTE_UNUSED)
- {
- flagword flags = bfd_get_section_flags (abfd, sec);
- segment_info_type *seginfo = seg_info (sec);
- fragS *frag = seginfo->frchainP->frch_root;
- xtensa_isa isa = xtensa_default_isa;
- if (flags & SEC_CODE)
- {
- xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc (isa);
- while (frag != NULL)
- {
- if (frag->tc_frag_data.is_first_loop_insn)
- {
- int op_size;
- addressT frag_addr;
- xtensa_format fmt;
- if (frag->fr_fix == 0)
- frag = next_non_empty_frag (frag);
- if (frag)
- {
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- op_size = xtensa_format_length (isa, fmt);
- frag_addr = frag->fr_address % xtensa_fetch_width;
- if (frag_addr + op_size > xtensa_fetch_width)
- as_warn_where (frag->fr_file, frag->fr_line,
- _("unaligned loop: %d bytes at 0x%lx"),
- op_size, (long) frag->fr_address);
- }
- }
- frag = frag->fr_next;
- }
- xtensa_insnbuf_free (isa, insnbuf);
- }
- }
- static int
- xg_apply_fix_value (fixS *fixP, valueT val)
- {
- xtensa_isa isa = xtensa_default_isa;
- static xtensa_insnbuf insnbuf = NULL;
- static xtensa_insnbuf slotbuf = NULL;
- xtensa_format fmt;
- int slot;
- bfd_boolean alt_reloc;
- xtensa_opcode opcode;
- char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
- if (decode_reloc (fixP->fx_r_type, &slot, &alt_reloc)
- || alt_reloc)
- as_fatal (_("unexpected fix"));
- if (!insnbuf)
- {
- insnbuf = xtensa_insnbuf_alloc (isa);
- slotbuf = xtensa_insnbuf_alloc (isa);
- }
- xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) fixpos, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- as_fatal (_("undecodable fix"));
- xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
- opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
- if (opcode == XTENSA_UNDEFINED)
- as_fatal (_("undecodable fix"));
- /* CONST16 immediates are not PC-relative, despite the fact that we
- reuse the normal PC-relative operand relocations for the low part
- of a CONST16 operand. */
- if (opcode == xtensa_const16_opcode)
- return 0;
- xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode,
- get_relaxable_immed (opcode), val,
- fixP->fx_file, fixP->fx_line);
- xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf);
- xtensa_insnbuf_to_chars (isa, insnbuf, (unsigned char *) fixpos, 0);
- return 1;
- }
- /* External Functions and Other GAS Hooks. */
- const char *
- xtensa_target_format (void)
- {
- return (target_big_endian ? "elf32-xtensa-be" : "elf32-xtensa-le");
- }
- void
- xtensa_file_arch_init (bfd *abfd)
- {
- bfd_set_private_flags (abfd, 0x100 | 0x200);
- }
- void
- md_number_to_chars (char *buf, valueT val, int n)
- {
- if (target_big_endian)
- number_to_chars_bigendian (buf, val, n);
- else
- number_to_chars_littleendian (buf, val, n);
- }
- /* This function is called once, at assembler startup time. It should
- set up all the tables, etc. that the MD part of the assembler will
- need. */
- void
- md_begin (void)
- {
- segT current_section = now_seg;
- int current_subsec = now_subseg;
- xtensa_isa isa;
- int i;
- xtensa_default_isa = xtensa_isa_init (0, 0);
- isa = xtensa_default_isa;
- linkrelax = 1;
- /* Set up the literal sections. */
- memset (&default_lit_sections, 0, sizeof (default_lit_sections));
- subseg_set (current_section, current_subsec);
- xtensa_addi_opcode = xtensa_opcode_lookup (isa, "addi");
- xtensa_addmi_opcode = xtensa_opcode_lookup (isa, "addmi");
- xtensa_call0_opcode = xtensa_opcode_lookup (isa, "call0");
- xtensa_call4_opcode = xtensa_opcode_lookup (isa, "call4");
- xtensa_call8_opcode = xtensa_opcode_lookup (isa, "call8");
- xtensa_call12_opcode = xtensa_opcode_lookup (isa, "call12");
- xtensa_callx0_opcode = xtensa_opcode_lookup (isa, "callx0");
- xtensa_callx4_opcode = xtensa_opcode_lookup (isa, "callx4");
- xtensa_callx8_opcode = xtensa_opcode_lookup (isa, "callx8");
- xtensa_callx12_opcode = xtensa_opcode_lookup (isa, "callx12");
- xtensa_const16_opcode = xtensa_opcode_lookup (isa, "const16");
- xtensa_entry_opcode = xtensa_opcode_lookup (isa, "entry");
- xtensa_extui_opcode = xtensa_opcode_lookup (isa, "extui");
- xtensa_movi_opcode = xtensa_opcode_lookup (isa, "movi");
- xtensa_movi_n_opcode = xtensa_opcode_lookup (isa, "movi.n");
- xtensa_isync_opcode = xtensa_opcode_lookup (isa, "isync");
- xtensa_j_opcode = xtensa_opcode_lookup (isa, "j");
- xtensa_jx_opcode = xtensa_opcode_lookup (isa, "jx");
- xtensa_l32r_opcode = xtensa_opcode_lookup (isa, "l32r");
- xtensa_loop_opcode = xtensa_opcode_lookup (isa, "loop");
- xtensa_loopnez_opcode = xtensa_opcode_lookup (isa, "loopnez");
- xtensa_loopgtz_opcode = xtensa_opcode_lookup (isa, "loopgtz");
- xtensa_nop_opcode = xtensa_opcode_lookup (isa, "nop");
- xtensa_nop_n_opcode = xtensa_opcode_lookup (isa, "nop.n");
- xtensa_or_opcode = xtensa_opcode_lookup (isa, "or");
- xtensa_ret_opcode = xtensa_opcode_lookup (isa, "ret");
- xtensa_ret_n_opcode = xtensa_opcode_lookup (isa, "ret.n");
- xtensa_retw_opcode = xtensa_opcode_lookup (isa, "retw");
- xtensa_retw_n_opcode = xtensa_opcode_lookup (isa, "retw.n");
- xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount");
- xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti");
- for (i = 0; i < xtensa_isa_num_formats (isa); i++)
- {
- int format_slots = xtensa_format_num_slots (isa, i);
- if (format_slots > config_max_slots)
- config_max_slots = format_slots;
- }
- xg_init_vinsn (&cur_vinsn);
- xtensa_num_pipe_stages = xtensa_isa_num_pipe_stages (isa);
- init_op_placement_info_table ();
- /* Set up the assembly state. */
- if (!frag_now->tc_frag_data.is_assembly_state_set)
- xtensa_set_frag_assembly_state (frag_now);
- }
- /* TC_INIT_FIX_DATA hook */
- void
- xtensa_init_fix_data (fixS *x)
- {
- x->tc_fix_data.slot = 0;
- x->tc_fix_data.X_add_symbol = NULL;
- x->tc_fix_data.X_add_number = 0;
- }
- /* tc_frob_label hook */
- void
- xtensa_frob_label (symbolS *sym)
- {
- float freq;
- if (cur_vinsn.inside_bundle)
- {
- as_bad (_("labels are not valid inside bundles"));
- return;
- }
- freq = get_subseg_target_freq (now_seg, now_subseg);
- /* Since the label was already attached to a frag associated with the
- previous basic block, it now needs to be reset to the current frag. */
- symbol_set_frag (sym, frag_now);
- S_SET_VALUE (sym, (valueT) frag_now_fix ());
- if (generating_literals)
- xtensa_add_literal_sym (sym);
- else
- xtensa_add_insn_label (sym);
- if (symbol_get_tc (sym)->is_loop_target)
- {
- if ((get_last_insn_flags (now_seg, now_subseg)
- & FLAG_IS_BAD_LOOPEND) != 0)
- as_bad (_("invalid last instruction for a zero-overhead loop"));
- xtensa_set_frag_assembly_state (frag_now);
- frag_var (rs_machine_dependent, 4, 4, RELAX_LOOP_END,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- xtensa_move_labels (frag_now, 0);
- }
- /* No target aligning in the absolute section. */
- if (now_seg != absolute_section
- && !is_unaligned_label (sym)
- && !generating_literals)
- {
- xtensa_set_frag_assembly_state (frag_now);
- if (do_align_targets ())
- frag_var (rs_machine_dependent, 0, (int) freq,
- RELAX_DESIRE_ALIGN_IF_TARGET, frag_now->fr_symbol,
- frag_now->fr_offset, NULL);
- else
- frag_var (rs_fill, 0, 0, frag_now->fr_subtype,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- xtensa_move_labels (frag_now, 0);
- }
- /* We need to mark the following properties even if we aren't aligning. */
- /* If the label is already known to be a branch target, i.e., a
- forward branch, mark the frag accordingly. Backward branches
- are handled by xg_add_branch_and_loop_targets. */
- if (symbol_get_tc (sym)->is_branch_target)
- symbol_get_frag (sym)->tc_frag_data.is_branch_target = TRUE;
- /* Loops only go forward, so they can be identified here. */
- if (symbol_get_tc (sym)->is_loop_target)
- symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE;
- dwarf2_emit_label (sym);
- }
- /* tc_unrecognized_line hook */
- int
- xtensa_unrecognized_line (int ch)
- {
- switch (ch)
- {
- case '{' :
- if (cur_vinsn.inside_bundle == 0)
- {
- /* PR8110: Cannot emit line number info inside a FLIX bundle
- when using --gstabs. Temporarily disable debug info. */
- generate_lineno_debug ();
- if (debug_type == DEBUG_STABS)
- {
- xt_saved_debug_type = debug_type;
- debug_type = DEBUG_NONE;
- }
- cur_vinsn.inside_bundle = 1;
- }
- else
- {
- as_bad (_("extra opening brace"));
- return 0;
- }
- break;
- case '}' :
- if (cur_vinsn.inside_bundle)
- finish_vinsn (&cur_vinsn);
- else
- {
- as_bad (_("extra closing brace"));
- return 0;
- }
- break;
- default:
- as_bad (_("syntax error"));
- return 0;
- }
- return 1;
- }
- /* md_flush_pending_output hook */
- void
- xtensa_flush_pending_output (void)
- {
- /* This line fixes a bug where automatically generated gstabs info
- separates a function label from its entry instruction, ending up
- with the literal position between the function label and the entry
- instruction and crashing code. It only happens with --gstabs and
- --text-section-literals, and when several other obscure relaxation
- conditions are met. */
- if (outputting_stabs_line_debug)
- return;
- if (cur_vinsn.inside_bundle)
- as_bad (_("missing closing brace"));
- /* If there is a non-zero instruction fragment, close it. */
- if (frag_now_fix () != 0 && frag_now->tc_frag_data.is_insn)
- {
- frag_wane (frag_now);
- frag_new (0);
- xtensa_set_frag_assembly_state (frag_now);
- }
- frag_now->tc_frag_data.is_insn = FALSE;
- xtensa_clear_insn_labels ();
- }
- /* We had an error while parsing an instruction. The string might look
- like this: "insn arg1, arg2 }". If so, we need to see the closing
- brace and reset some fields. Otherwise, the vinsn never gets closed
- and the num_slots field will grow past the end of the array of slots,
- and bad things happen. */
- static void
- error_reset_cur_vinsn (void)
- {
- if (cur_vinsn.inside_bundle)
- {
- if (*input_line_pointer == '}'
- || *(input_line_pointer - 1) == '}'
- || *(input_line_pointer - 2) == '}')
- xg_clear_vinsn (&cur_vinsn);
- }
- }
- void
- md_assemble (char *str)
- {
- xtensa_isa isa = xtensa_default_isa;
- char *opname;
- unsigned opnamelen;
- bfd_boolean has_underbar = FALSE;
- char *arg_strings[MAX_INSN_ARGS];
- int num_args;
- TInsn orig_insn; /* Original instruction from the input. */
- tinsn_init (&orig_insn);
- /* Split off the opcode. */
- opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/0123456789.");
- opname = xmalloc (opnamelen + 1);
- memcpy (opname, str, opnamelen);
- opname[opnamelen] = '\0';
- num_args = tokenize_arguments (arg_strings, str + opnamelen);
- if (num_args == -1)
- {
- as_bad (_("syntax error"));
- return;
- }
- if (xg_translate_idioms (&opname, &num_args, arg_strings))
- return;
- /* Check for an underbar prefix. */
- if (*opname == '_')
- {
- has_underbar = TRUE;
- opname += 1;
- }
- orig_insn.insn_type = ITYPE_INSN;
- orig_insn.ntok = 0;
- orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
- orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
- /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its
- extra argument and set the opcode to "CALLXn". */
- if (orig_insn.opcode == XTENSA_UNDEFINED
- && strncasecmp (opname, "callx", 5) == 0)
- {
- unsigned long window_size;
- char *suffix;
- window_size = strtoul (opname + 5, &suffix, 10);
- if (suffix != opname + 5
- && (window_size == 0
- || window_size == 4
- || window_size == 8
- || window_size == 12)
- && strcasecmp (suffix, ".tls") == 0)
- {
- switch (window_size)
- {
- case 0: orig_insn.opcode = xtensa_callx0_opcode; break;
- case 4: orig_insn.opcode = xtensa_callx4_opcode; break;
- case 8: orig_insn.opcode = xtensa_callx8_opcode; break;
- case 12: orig_insn.opcode = xtensa_callx12_opcode; break;
- }
- if (num_args != 2)
- as_bad (_("wrong number of operands for '%s'"), opname);
- else
- {
- bfd_reloc_code_real_type reloc;
- char *old_input_line_pointer;
- expressionS *tok = &orig_insn.extra_arg;
- old_input_line_pointer = input_line_pointer;
- input_line_pointer = arg_strings[num_args - 1];
- expression (tok);
- if (tok->X_op == O_symbol
- && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
- == BFD_RELOC_XTENSA_TLS_CALL))
- tok->X_op = map_suffix_reloc_to_operator (reloc);
- else
- as_bad (_("bad relocation expression for '%s'"), opname);
- input_line_pointer = old_input_line_pointer;
- num_args -= 1;
- }
- }
- }
- /* Special case: Check for "j.l" psuedo op. */
- if (orig_insn.opcode == XTENSA_UNDEFINED
- && strncasecmp (opname, "j.l", 3) == 0)
- {
- if (num_args != 2)
- as_bad (_("wrong number of operands for '%s'"), opname);
- else
- {
- char *old_input_line_pointer;
- expressionS *tok = &orig_insn.extra_arg;
- old_input_line_pointer = input_line_pointer;
- input_line_pointer = arg_strings[num_args - 1];
- expression_maybe_register (xtensa_jx_opcode, 0, tok);
- input_line_pointer = old_input_line_pointer;
- num_args -= 1;
- orig_insn.opcode = xtensa_j_opcode;
- }
- }
- if (orig_insn.opcode == XTENSA_UNDEFINED)
- {
- xtensa_format fmt = xtensa_format_lookup (isa, opname);
- if (fmt == XTENSA_UNDEFINED)
- {
- as_bad (_("unknown opcode or format name '%s'"), opname);
- error_reset_cur_vinsn ();
- return;
- }
- if (!cur_vinsn.inside_bundle)
- {
- as_bad (_("format names only valid inside bundles"));
- error_reset_cur_vinsn ();
- return;
- }
- if (cur_vinsn.format != XTENSA_UNDEFINED)
- as_warn (_("multiple formats specified for one bundle; using '%s'"),
- opname);
- cur_vinsn.format = fmt;
- free (has_underbar ? opname - 1 : opname);
- error_reset_cur_vinsn ();
- return;
- }
- /* Parse the arguments. */
- if (parse_arguments (&orig_insn, num_args, arg_strings))
- {
- as_bad (_("syntax error"));
- error_reset_cur_vinsn ();
- return;
- }
- /* Free the opcode and argument strings, now that they've been parsed. */
- free (has_underbar ? opname - 1 : opname);
- opname = 0;
- while (num_args-- > 0)
- free (arg_strings[num_args]);
- /* Get expressions for invisible operands. */
- if (get_invisible_operands (&orig_insn))
- {
- error_reset_cur_vinsn ();
- return;
- }
- /* Check for the right number and type of arguments. */
- if (tinsn_check_arguments (&orig_insn))
- {
- error_reset_cur_vinsn ();
- return;
- }
- /* Record the line number for each TInsn, because a FLIX bundle may be
- spread across multiple input lines and individual instructions may be
- moved around in some cases. */
- orig_insn.loc_directive_seen = dwarf2_loc_directive_seen;
- dwarf2_where (&orig_insn.debug_line);
- dwarf2_consume_line_info ();
- xg_add_branch_and_loop_targets (&orig_insn);
- /* Check that immediate value for ENTRY is >= 16. */
- if (orig_insn.opcode == xtensa_entry_opcode && orig_insn.ntok >= 3)
- {
- expressionS *exp = &orig_insn.tok[2];
- if (exp->X_op == O_constant && exp->X_add_number < 16)
- as_warn (_("entry instruction with stack decrement < 16"));
- }
- /* Finish it off:
- assemble_tokens (opcode, tok, ntok);
- expand the tokens from the orig_insn into the
- stack of instructions that will not expand
- unless required at relaxation time. */
- if (!cur_vinsn.inside_bundle)
- emit_single_op (&orig_insn);
- else /* We are inside a bundle. */
- {
- cur_vinsn.slots[cur_vinsn.num_slots] = orig_insn;
- cur_vinsn.num_slots++;
- if (*input_line_pointer == '}'
- || *(input_line_pointer - 1) == '}'
- || *(input_line_pointer - 2) == '}')
- finish_vinsn (&cur_vinsn);
- }
- /* We've just emitted a new instruction so clear the list of labels. */
- xtensa_clear_insn_labels ();
- xtensa_check_frag_count ();
- }
- /* HANDLE_ALIGN hook */
- /* For a .align directive, we mark the previous block with the alignment
- information. This will be placed in the object file in the
- property section corresponding to this section. */
- void
- xtensa_handle_align (fragS *fragP)
- {
- if (linkrelax
- && ! fragP->tc_frag_data.is_literal
- && (fragP->fr_type == rs_align
- || fragP->fr_type == rs_align_code)
- && fragP->fr_offset > 0
- && now_seg != bss_section)
- {
- fragP->tc_frag_data.is_align = TRUE;
- fragP->tc_frag_data.alignment = fragP->fr_offset;
- }
- if (fragP->fr_type == rs_align_test)
- {
- int count;
- count = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
- if (count != 0)
- as_bad_where (fragP->fr_file, fragP->fr_line,
- _("unaligned entry instruction"));
- }
- if (linkrelax && fragP->fr_type == rs_org)
- fragP->fr_subtype = RELAX_ORG;
- }
- /* TC_FRAG_INIT hook */
- void
- xtensa_frag_init (fragS *frag)
- {
- xtensa_set_frag_assembly_state (frag);
- }
- symbolS *
- md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
- {
- return NULL;
- }
- /* Round up a section size to the appropriate boundary. */
- valueT
- md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
- {
- return size; /* Byte alignment is fine. */
- }
- long
- md_pcrel_from (fixS *fixP)
- {
- char *insn_p;
- static xtensa_insnbuf insnbuf = NULL;
- static xtensa_insnbuf slotbuf = NULL;
- int opnum;
- uint32 opnd_value;
- xtensa_opcode opcode;
- xtensa_format fmt;
- int slot;
- xtensa_isa isa = xtensa_default_isa;
- valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
- bfd_boolean alt_reloc;
- if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND)
- return 0;
- if (fixP->fx_r_type == BFD_RELOC_32_PCREL)
- return addr;
- if (!insnbuf)
- {
- insnbuf = xtensa_insnbuf_alloc (isa);
- slotbuf = xtensa_insnbuf_alloc (isa);
- }
- insn_p = &fixP->fx_frag->fr_literal[fixP->fx_where];
- xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) insn_p, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- as_fatal (_("bad instruction format"));
- if (decode_reloc (fixP->fx_r_type, &slot, &alt_reloc) != 0)
- as_fatal (_("invalid relocation"));
- xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
- opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
- /* Check for "alternate" relocations (operand not specified). None
- of the current uses for these are really PC-relative. */
- if (alt_reloc || opcode == xtensa_const16_opcode)
- {
- if (opcode != xtensa_l32r_opcode
- && opcode != xtensa_const16_opcode)
- as_fatal (_("invalid relocation for '%s' instruction"),
- xtensa_opcode_name (isa, opcode));
- return 0;
- }
- opnum = get_relaxable_immed (opcode);
- opnd_value = 0;
- if (xtensa_operand_is_PCrelative (isa, opcode, opnum) != 1
- || xtensa_operand_do_reloc (isa, opcode, opnum, &opnd_value, addr))
- {
- as_bad_where (fixP->fx_file,
- fixP->fx_line,
- _("invalid relocation for operand %d of '%s'"),
- opnum, xtensa_opcode_name (isa, opcode));
- return 0;
- }
- return 0 - opnd_value;
- }
- /* TC_FORCE_RELOCATION hook */
- int
- xtensa_force_relocation (fixS *fix)
- {
- switch (fix->fx_r_type)
- {
- case BFD_RELOC_XTENSA_ASM_EXPAND:
- case BFD_RELOC_XTENSA_SLOT0_ALT:
- case BFD_RELOC_XTENSA_SLOT1_ALT:
- case BFD_RELOC_XTENSA_SLOT2_ALT:
- case BFD_RELOC_XTENSA_SLOT3_ALT:
- case BFD_RELOC_XTENSA_SLOT4_ALT:
- case BFD_RELOC_XTENSA_SLOT5_ALT:
- case BFD_RELOC_XTENSA_SLOT6_ALT:
- case BFD_RELOC_XTENSA_SLOT7_ALT:
- case BFD_RELOC_XTENSA_SLOT8_ALT:
- case BFD_RELOC_XTENSA_SLOT9_ALT:
- case BFD_RELOC_XTENSA_SLOT10_ALT:
- case BFD_RELOC_XTENSA_SLOT11_ALT:
- case BFD_RELOC_XTENSA_SLOT12_ALT:
- case BFD_RELOC_XTENSA_SLOT13_ALT:
- case BFD_RELOC_XTENSA_SLOT14_ALT:
- return 1;
- default:
- break;
- }
- if (linkrelax && fix->fx_addsy
- && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
- return 1;
- return generic_force_reloc (fix);
- }
- /* TC_VALIDATE_FIX_SUB hook */
- int
- xtensa_validate_fix_sub (fixS *fix)
- {
- segT add_symbol_segment, sub_symbol_segment;
- /* The difference of two symbols should be resolved by the assembler when
- linkrelax is not set. If the linker may relax the section containing
- the symbols, then an Xtensa DIFF relocation must be generated so that
- the linker knows to adjust the difference value. */
- if (!linkrelax || fix->fx_addsy == NULL)
- return 0;
- /* Make sure both symbols are in the same segment, and that segment is
- "normal" and relaxable. If the segment is not "normal", then the
- fix is not valid. If the segment is not "relaxable", then the fix
- should have been handled earlier. */
- add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
- if (! SEG_NORMAL (add_symbol_segment) ||
- ! relaxable_section (add_symbol_segment))
- return 0;
- sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
- return (sub_symbol_segment == add_symbol_segment);
- }
- /* NO_PSEUDO_DOT hook */
- /* This function has nothing to do with pseudo dots, but this is the
- nearest macro to where the check needs to take place. FIXME: This
- seems wrong. */
- bfd_boolean
- xtensa_check_inside_bundle (void)
- {
- if (cur_vinsn.inside_bundle && input_line_pointer[-1] == '.')
- as_bad (_("directives are not valid inside bundles"));
- /* This function must always return FALSE because it is called via a
- macro that has nothing to do with bundling. */
- return FALSE;
- }
- /* md_elf_section_change_hook */
- void
- xtensa_elf_section_change_hook (void)
- {
- /* Set up the assembly state. */
- if (!frag_now->tc_frag_data.is_assembly_state_set)
- xtensa_set_frag_assembly_state (frag_now);
- }
- /* tc_fix_adjustable hook */
- bfd_boolean
- xtensa_fix_adjustable (fixS *fixP)
- {
- /* We need the symbol name for the VTABLE entries. */
- if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- return 0;
- return 1;
- }
- /* tc_symbol_new_hook */
- symbolS *expr_symbols = NULL;
- void
- xtensa_symbol_new_hook (symbolS *sym)
- {
- if (is_leb128_expr && S_GET_SEGMENT (sym) == expr_section)
- {
- symbol_get_tc (sym)->next_expr_symbol = expr_symbols;
- expr_symbols = sym;
- }
- }
- void
- md_apply_fix (fixS *fixP, valueT *valP, segT seg)
- {
- char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
- valueT val = 0;
- /* Subtracted symbols are only allowed for a few relocation types, and
- unless linkrelax is enabled, they should not make it to this point. */
- if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32
- || fixP->fx_r_type == BFD_RELOC_16
- || fixP->fx_r_type == BFD_RELOC_8)))
- as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_32_PCREL:
- case BFD_RELOC_32:
- case BFD_RELOC_16:
- case BFD_RELOC_8:
- if (fixP->fx_subsy)
- {
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_8:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
- fixP->fx_signed = 1;
- break;
- case BFD_RELOC_16:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
- fixP->fx_signed = 1;
- break;
- case BFD_RELOC_32:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
- fixP->fx_signed = 1;
- break;
- default:
- break;
- }
- val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- - S_GET_VALUE (fixP->fx_subsy));
- /* The difference value gets written out, and the DIFF reloc
- identifies the address of the subtracted symbol (i.e., the one
- with the lowest address). */
- *valP = val;
- fixP->fx_offset -= val;
- fixP->fx_subsy = NULL;
- }
- else if (! fixP->fx_addsy)
- {
- val = *valP;
- fixP->fx_done = 1;
- }
- /* fall through */
- case BFD_RELOC_XTENSA_PLT:
- md_number_to_chars (fixpos, val, fixP->fx_size);
- fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
- break;
- case BFD_RELOC_XTENSA_TLSDESC_FN:
- case BFD_RELOC_XTENSA_TLSDESC_ARG:
- case BFD_RELOC_XTENSA_TLS_TPOFF:
- case BFD_RELOC_XTENSA_TLS_DTPOFF:
- S_SET_THREAD_LOCAL (fixP->fx_addsy);
- md_number_to_chars (fixpos, 0, fixP->fx_size);
- fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
- break;
- case BFD_RELOC_XTENSA_SLOT0_OP:
- case BFD_RELOC_XTENSA_SLOT1_OP:
- case BFD_RELOC_XTENSA_SLOT2_OP:
- case BFD_RELOC_XTENSA_SLOT3_OP:
- case BFD_RELOC_XTENSA_SLOT4_OP:
- case BFD_RELOC_XTENSA_SLOT5_OP:
- case BFD_RELOC_XTENSA_SLOT6_OP:
- case BFD_RELOC_XTENSA_SLOT7_OP:
- case BFD_RELOC_XTENSA_SLOT8_OP:
- case BFD_RELOC_XTENSA_SLOT9_OP:
- case BFD_RELOC_XTENSA_SLOT10_OP:
- case BFD_RELOC_XTENSA_SLOT11_OP:
- case BFD_RELOC_XTENSA_SLOT12_OP:
- case BFD_RELOC_XTENSA_SLOT13_OP:
- case BFD_RELOC_XTENSA_SLOT14_OP:
- if (linkrelax)
- {
- /* Write the tentative value of a PC-relative relocation to a
- local symbol into the instruction. The value will be ignored
- by the linker, and it makes the object file disassembly
- readable when all branch targets are encoded in relocations. */
- gas_assert (fixP->fx_addsy);
- if (S_GET_SEGMENT (fixP->fx_addsy) == seg
- && !S_FORCE_RELOC (fixP->fx_addsy, 1))
- {
- val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
- - md_pcrel_from (fixP));
- (void) xg_apply_fix_value (fixP, val);
- }
- }
- else if (! fixP->fx_addsy)
- {
- val = *valP;
- if (xg_apply_fix_value (fixP, val))
- fixP->fx_done = 1;
- }
- break;
- case BFD_RELOC_XTENSA_ASM_EXPAND:
- case BFD_RELOC_XTENSA_TLS_FUNC:
- case BFD_RELOC_XTENSA_TLS_ARG:
- case BFD_RELOC_XTENSA_TLS_CALL:
- case BFD_RELOC_XTENSA_SLOT0_ALT:
- case BFD_RELOC_XTENSA_SLOT1_ALT:
- case BFD_RELOC_XTENSA_SLOT2_ALT:
- case BFD_RELOC_XTENSA_SLOT3_ALT:
- case BFD_RELOC_XTENSA_SLOT4_ALT:
- case BFD_RELOC_XTENSA_SLOT5_ALT:
- case BFD_RELOC_XTENSA_SLOT6_ALT:
- case BFD_RELOC_XTENSA_SLOT7_ALT:
- case BFD_RELOC_XTENSA_SLOT8_ALT:
- case BFD_RELOC_XTENSA_SLOT9_ALT:
- case BFD_RELOC_XTENSA_SLOT10_ALT:
- case BFD_RELOC_XTENSA_SLOT11_ALT:
- case BFD_RELOC_XTENSA_SLOT12_ALT:
- case BFD_RELOC_XTENSA_SLOT13_ALT:
- case BFD_RELOC_XTENSA_SLOT14_ALT:
- /* These all need to be resolved at link-time. Do nothing now. */
- break;
- case BFD_RELOC_VTABLE_INHERIT:
- case BFD_RELOC_VTABLE_ENTRY:
- fixP->fx_done = 0;
- break;
- default:
- as_bad (_("unhandled local relocation fix %s"),
- bfd_get_reloc_code_name (fixP->fx_r_type));
- }
- }
- char *
- md_atof (int type, char *litP, int *sizeP)
- {
- return ieee_md_atof (type, litP, sizeP, target_big_endian);
- }
- int
- md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
- {
- return total_frag_text_expansion (fragP);
- }
- /* Translate internal representation of relocation info to BFD target
- format. */
- arelent *
- tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
- {
- arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
- /* Make sure none of our internal relocations make it this far.
- They'd better have been fully resolved by this point. */
- gas_assert ((int) fixp->fx_r_type > 0);
- reloc->addend = fixp->fx_offset;
- reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
- if (reloc->howto == NULL)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("cannot represent `%s' relocation in object file"),
- bfd_get_reloc_code_name (fixp->fx_r_type));
- free (reloc->sym_ptr_ptr);
- free (reloc);
- return NULL;
- }
- if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
- as_fatal (_("internal error; cannot generate `%s' relocation"),
- bfd_get_reloc_code_name (fixp->fx_r_type));
- return reloc;
- }
- /* Checks for resource conflicts between instructions. */
- /* The func unit stuff could be implemented as bit-vectors rather
- than the iterative approach here. If it ends up being too
- slow, we will switch it. */
- resource_table *
- new_resource_table (void *data,
- int cycles,
- int nu,
- unit_num_copies_func uncf,
- opcode_num_units_func onuf,
- opcode_funcUnit_use_unit_func ouuf,
- opcode_funcUnit_use_stage_func ousf)
- {
- int i;
- resource_table *rt = (resource_table *) xmalloc (sizeof (resource_table));
- rt->data = data;
- rt->cycles = cycles;
- rt->allocated_cycles = cycles;
- rt->num_units = nu;
- rt->unit_num_copies = uncf;
- rt->opcode_num_units = onuf;
- rt->opcode_unit_use = ouuf;
- rt->opcode_unit_stage = ousf;
- rt->units = (unsigned char **) xcalloc (cycles, sizeof (unsigned char *));
- for (i = 0; i < cycles; i++)
- rt->units[i] = (unsigned char *) xcalloc (nu, sizeof (unsigned char));
- return rt;
- }
- void
- clear_resource_table (resource_table *rt)
- {
- int i, j;
- for (i = 0; i < rt->allocated_cycles; i++)
- for (j = 0; j < rt->num_units; j++)
- rt->units[i][j] = 0;
- }
- /* We never shrink it, just fake it into thinking so. */
- void
- resize_resource_table (resource_table *rt, int cycles)
- {
- int i, old_cycles;
- rt->cycles = cycles;
- if (cycles <= rt->allocated_cycles)
- return;
- old_cycles = rt->allocated_cycles;
- rt->allocated_cycles = cycles;
- rt->units = xrealloc (rt->units,
- rt->allocated_cycles * sizeof (unsigned char *));
- for (i = 0; i < old_cycles; i++)
- rt->units[i] = xrealloc (rt->units[i],
- rt->num_units * sizeof (unsigned char));
- for (i = old_cycles; i < cycles; i++)
- rt->units[i] = xcalloc (rt->num_units, sizeof (unsigned char));
- }
- bfd_boolean
- resources_available (resource_table *rt, xtensa_opcode opcode, int cycle)
- {
- int i;
- int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
- {
- xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
- int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
- int copies_in_use = rt->units[stage + cycle][unit];
- int copies = (rt->unit_num_copies) (rt->data, unit);
- if (copies_in_use >= copies)
- return FALSE;
- }
- return TRUE;
- }
- void
- reserve_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
- {
- int i;
- int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
- {
- xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
- int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
- /* Note that this allows resources to be oversubscribed. That's
- essential to the way the optional scheduler works.
- resources_available reports when a resource is over-subscribed,
- so it's easy to tell. */
- rt->units[stage + cycle][unit]++;
- }
- }
- void
- release_resources (resource_table *rt, xtensa_opcode opcode, int cycle)
- {
- int i;
- int uses = (rt->opcode_num_units) (rt->data, opcode);
- for (i = 0; i < uses; i++)
- {
- xtensa_funcUnit unit = (rt->opcode_unit_use) (rt->data, opcode, i);
- int stage = (rt->opcode_unit_stage) (rt->data, opcode, i);
- gas_assert (rt->units[stage + cycle][unit] > 0);
- rt->units[stage + cycle][unit]--;
- }
- }
- /* Wrapper functions make parameterized resource reservation
- more convenient. */
- int
- opcode_funcUnit_use_unit (void *data, xtensa_opcode opcode, int idx)
- {
- xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
- return use->unit;
- }
- int
- opcode_funcUnit_use_stage (void *data, xtensa_opcode opcode, int idx)
- {
- xtensa_funcUnit_use *use = xtensa_opcode_funcUnit_use (data, opcode, idx);
- return use->stage;
- }
- /* Note that this function does not check issue constraints, but
- solely whether the hardware is available to execute the given
- instructions together. It also doesn't check if the tinsns
- write the same state, or access the same tieports. That is
- checked by check_t1_t2_reads_and_writes. */
- static bfd_boolean
- resources_conflict (vliw_insn *vinsn)
- {
- int i;
- static resource_table *rt = NULL;
- /* This is the most common case by far. Optimize it. */
- if (vinsn->num_slots == 1)
- return FALSE;
- if (rt == NULL)
- {
- xtensa_isa isa = xtensa_default_isa;
- rt = new_resource_table
- (isa, xtensa_num_pipe_stages,
- xtensa_isa_num_funcUnits (isa),
- (unit_num_copies_func) xtensa_funcUnit_num_copies,
- (opcode_num_units_func) xtensa_opcode_num_funcUnit_uses,
- opcode_funcUnit_use_unit,
- opcode_funcUnit_use_stage);
- }
- clear_resource_table (rt);
- for (i = 0; i < vinsn->num_slots; i++)
- {
- if (!resources_available (rt, vinsn->slots[i].opcode, 0))
- return TRUE;
- reserve_resources (rt, vinsn->slots[i].opcode, 0);
- }
- return FALSE;
- }
- /* finish_vinsn, emit_single_op and helper functions. */
- static bfd_boolean find_vinsn_conflicts (vliw_insn *);
- static xtensa_format xg_find_narrowest_format (vliw_insn *);
- static void xg_assemble_vliw_tokens (vliw_insn *);
- /* We have reached the end of a bundle; emit into the frag. */
- static void
- finish_vinsn (vliw_insn *vinsn)
- {
- IStack slotstack;
- int i;
- char *file_name;
- unsigned line;
- if (find_vinsn_conflicts (vinsn))
- {
- xg_clear_vinsn (vinsn);
- return;
- }
- /* First, find a format that works. */
- if (vinsn->format == XTENSA_UNDEFINED)
- vinsn->format = xg_find_narrowest_format (vinsn);
- if (xtensa_format_num_slots (xtensa_default_isa, vinsn->format) > 1
- && produce_flix == FLIX_NONE)
- {
- as_bad (_("The option \"--no-allow-flix\" prohibits multi-slot flix."));
- xg_clear_vinsn (vinsn);
- return;
- }
- if (vinsn->format == XTENSA_UNDEFINED)
- {
- as_where (&file_name, &line);
- as_bad_where (file_name, line,
- _("couldn't find a valid instruction format"));
- fprintf (stderr, _(" ops were: "));
- for (i = 0; i < vinsn->num_slots; i++)
- fprintf (stderr, _(" %s;"),
- xtensa_opcode_name (xtensa_default_isa,
- vinsn->slots[i].opcode));
- fprintf (stderr, _("\n"));
- xg_clear_vinsn (vinsn);
- return;
- }
- if (vinsn->num_slots
- != xtensa_format_num_slots (xtensa_default_isa, vinsn->format))
- {
- as_bad (_("format '%s' allows %d slots, but there are %d opcodes"),
- xtensa_format_name (xtensa_default_isa, vinsn->format),
- xtensa_format_num_slots (xtensa_default_isa, vinsn->format),
- vinsn->num_slots);
- xg_clear_vinsn (vinsn);
- return;
- }
- if (resources_conflict (vinsn))
- {
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
- fprintf (stderr, " ops were: ");
- for (i = 0; i < vinsn->num_slots; i++)
- fprintf (stderr, " %s;",
- xtensa_opcode_name (xtensa_default_isa,
- vinsn->slots[i].opcode));
- fprintf (stderr, "\n");
- xg_clear_vinsn (vinsn);
- return;
- }
- for (i = 0; i < vinsn->num_slots; i++)
- {
- if (vinsn->slots[i].opcode != XTENSA_UNDEFINED)
- {
- symbolS *lit_sym = NULL;
- int j;
- bfd_boolean e = FALSE;
- bfd_boolean saved_density = density_supported;
- /* We don't want to narrow ops inside multi-slot bundles. */
- if (vinsn->num_slots > 1)
- density_supported = FALSE;
- istack_init (&slotstack);
- if (vinsn->slots[i].opcode == xtensa_nop_opcode)
- {
- vinsn->slots[i].opcode =
- xtensa_format_slot_nop_opcode (xtensa_default_isa,
- vinsn->format, i);
- vinsn->slots[i].ntok = 0;
- }
- if (xg_expand_assembly_insn (&slotstack, &vinsn->slots[i]))
- {
- e = TRUE;
- continue;
- }
- density_supported = saved_density;
- if (e)
- {
- xg_clear_vinsn (vinsn);
- return;
- }
- for (j = 0; j < slotstack.ninsn; j++)
- {
- TInsn *insn = &slotstack.insn[j];
- if (insn->insn_type == ITYPE_LITERAL)
- {
- gas_assert (lit_sym == NULL);
- lit_sym = xg_assemble_literal (insn);
- }
- else
- {
- gas_assert (insn->insn_type == ITYPE_INSN);
- if (lit_sym)
- xg_resolve_literals (insn, lit_sym);
- if (j != slotstack.ninsn - 1)
- emit_single_op (insn);
- }
- }
- if (vinsn->num_slots > 1)
- {
- if (opcode_fits_format_slot
- (slotstack.insn[slotstack.ninsn - 1].opcode,
- vinsn->format, i))
- {
- vinsn->slots[i] = slotstack.insn[slotstack.ninsn - 1];
- }
- else
- {
- emit_single_op (&slotstack.insn[slotstack.ninsn - 1]);
- if (vinsn->format == XTENSA_UNDEFINED)
- vinsn->slots[i].opcode = xtensa_nop_opcode;
- else
- vinsn->slots[i].opcode
- = xtensa_format_slot_nop_opcode (xtensa_default_isa,
- vinsn->format, i);
- vinsn->slots[i].ntok = 0;
- }
- }
- else
- {
- vinsn->slots[0] = slotstack.insn[slotstack.ninsn - 1];
- vinsn->format = XTENSA_UNDEFINED;
- }
- }
- }
- /* Now check resource conflicts on the modified bundle. */
- if (resources_conflict (vinsn))
- {
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
- fprintf (stderr, " ops were: ");
- for (i = 0; i < vinsn->num_slots; i++)
- fprintf (stderr, " %s;",
- xtensa_opcode_name (xtensa_default_isa,
- vinsn->slots[i].opcode));
- fprintf (stderr, "\n");
- xg_clear_vinsn (vinsn);
- return;
- }
- /* First, find a format that works. */
- if (vinsn->format == XTENSA_UNDEFINED)
- vinsn->format = xg_find_narrowest_format (vinsn);
- xg_assemble_vliw_tokens (vinsn);
- xg_clear_vinsn (vinsn);
- xtensa_check_frag_count ();
- }
- /* Given an vliw instruction, what conflicts are there in register
- usage and in writes to states and queues?
- This function does two things:
- 1. Reports an error when a vinsn contains illegal combinations
- of writes to registers states or queues.
- 2. Marks individual tinsns as not relaxable if the combination
- contains antidependencies.
- Job 2 handles things like swap semantics in instructions that need
- to be relaxed. For example,
- addi a0, a1, 100000
- normally would be relaxed to
- l32r a0, some_label
- add a0, a1, a0
- _but_, if the above instruction is bundled with an a0 reader, e.g.,
- { addi a0, a1, 10000 ; add a2, a0, a4 ; }
- then we can't relax it into
- l32r a0, some_label
- { add a0, a1, a0 ; add a2, a0, a4 ; }
- because the value of a0 is trashed before the second add can read it. */
- static char check_t1_t2_reads_and_writes (TInsn *, TInsn *);
- static bfd_boolean
- find_vinsn_conflicts (vliw_insn *vinsn)
- {
- int i, j;
- int branches = 0;
- xtensa_isa isa = xtensa_default_isa;
- gas_assert (!past_xtensa_end);
- for (i = 0 ; i < vinsn->num_slots; i++)
- {
- TInsn *op1 = &vinsn->slots[i];
- if (op1->is_specific_opcode)
- op1->keep_wide = TRUE;
- else
- op1->keep_wide = FALSE;
- }
- for (i = 0 ; i < vinsn->num_slots; i++)
- {
- TInsn *op1 = &vinsn->slots[i];
- if (xtensa_opcode_is_branch (isa, op1->opcode) == 1)
- branches++;
- for (j = 0; j < vinsn->num_slots; j++)
- {
- if (i != j)
- {
- TInsn *op2 = &vinsn->slots[j];
- char conflict_type = check_t1_t2_reads_and_writes (op1, op2);
- switch (conflict_type)
- {
- case 'c':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same register"),
- xtensa_opcode_name (isa, op1->opcode), i,
- xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
- case 'd':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same state"),
- xtensa_opcode_name (isa, op1->opcode), i,
- xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
- case 'e':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) write the same port"),
- xtensa_opcode_name (isa, op1->opcode), i,
- xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
- case 'f':
- as_bad (_("opcodes '%s' (slot %d) and '%s' (slot %d) both have volatile port accesses"),
- xtensa_opcode_name (isa, op1->opcode), i,
- xtensa_opcode_name (isa, op2->opcode), j);
- return TRUE;
- default:
- /* Everything is OK. */
- break;
- }
- op2->is_specific_opcode = (op2->is_specific_opcode
- || conflict_type == 'a');
- }
- }
- }
- if (branches > 1)
- {
- as_bad (_("multiple branches or jumps in the same bundle"));
- return TRUE;
- }
- return FALSE;
- }
- /* Check how the state used by t1 and t2 relate.
- Cases found are:
- case A: t1 reads a register t2 writes (an antidependency within a bundle)
- case B: no relationship between what is read and written (both could
- read the same reg though)
- case C: t1 writes a register t2 writes (a register conflict within a
- bundle)
- case D: t1 writes a state that t2 also writes
- case E: t1 writes a tie queue that t2 also writes
- case F: two volatile queue accesses
- */
- static char
- check_t1_t2_reads_and_writes (TInsn *t1, TInsn *t2)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_regfile t1_regfile, t2_regfile;
- int t1_reg, t2_reg;
- int t1_base_reg, t1_last_reg;
- int t2_base_reg, t2_last_reg;
- char t1_inout, t2_inout;
- int i, j;
- char conflict = 'b';
- int t1_states;
- int t2_states;
- int t1_interfaces;
- int t2_interfaces;
- bfd_boolean t1_volatile = FALSE;
- bfd_boolean t2_volatile = FALSE;
- /* Check registers. */
- for (j = 0; j < t2->ntok; j++)
- {
- if (xtensa_operand_is_register (isa, t2->opcode, j) != 1)
- continue;
- t2_regfile = xtensa_operand_regfile (isa, t2->opcode, j);
- t2_base_reg = t2->tok[j].X_add_number;
- t2_last_reg = t2_base_reg + xtensa_operand_num_regs (isa, t2->opcode, j);
- for (i = 0; i < t1->ntok; i++)
- {
- if (xtensa_operand_is_register (isa, t1->opcode, i) != 1)
- continue;
- t1_regfile = xtensa_operand_regfile (isa, t1->opcode, i);
- if (t1_regfile != t2_regfile)
- continue;
- t1_inout = xtensa_operand_inout (isa, t1->opcode, i);
- t2_inout = xtensa_operand_inout (isa, t2->opcode, j);
- if (xtensa_operand_is_known_reg (isa, t1->opcode, i) == 0
- || xtensa_operand_is_known_reg (isa, t2->opcode, j) == 0)
- {
- if (t1_inout == 'm' || t1_inout == 'o'
- || t2_inout == 'm' || t2_inout == 'o')
- {
- conflict = 'a';
- continue;
- }
- }
- t1_base_reg = t1->tok[i].X_add_number;
- t1_last_reg = (t1_base_reg
- + xtensa_operand_num_regs (isa, t1->opcode, i));
- for (t1_reg = t1_base_reg; t1_reg < t1_last_reg; t1_reg++)
- {
- for (t2_reg = t2_base_reg; t2_reg < t2_last_reg; t2_reg++)
- {
- if (t1_reg != t2_reg)
- continue;
- if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o'))
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o'))
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout != 'i' && t2_inout != 'i')
- return 'c';
- }
- }
- }
- }
- /* Check states. */
- t1_states = xtensa_opcode_num_stateOperands (isa, t1->opcode);
- t2_states = xtensa_opcode_num_stateOperands (isa, t2->opcode);
- for (j = 0; j < t2_states; j++)
- {
- xtensa_state t2_so = xtensa_stateOperand_state (isa, t2->opcode, j);
- t2_inout = xtensa_stateOperand_inout (isa, t2->opcode, j);
- for (i = 0; i < t1_states; i++)
- {
- xtensa_state t1_so = xtensa_stateOperand_state (isa, t1->opcode, i);
- t1_inout = xtensa_stateOperand_inout (isa, t1->opcode, i);
- if (t1_so != t2_so || xtensa_state_is_shared_or (isa, t1_so) == 1)
- continue;
- if (t2_inout == 'i' && (t1_inout == 'm' || t1_inout == 'o'))
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout == 'i' && (t2_inout == 'm' || t2_inout == 'o'))
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout != 'i' && t2_inout != 'i')
- return 'd';
- }
- }
- /* Check tieports. */
- t1_interfaces = xtensa_opcode_num_interfaceOperands (isa, t1->opcode);
- t2_interfaces = xtensa_opcode_num_interfaceOperands (isa, t2->opcode);
- for (j = 0; j < t2_interfaces; j++)
- {
- xtensa_interface t2_int
- = xtensa_interfaceOperand_interface (isa, t2->opcode, j);
- int t2_class = xtensa_interface_class_id (isa, t2_int);
- t2_inout = xtensa_interface_inout (isa, t2_int);
- if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
- t2_volatile = TRUE;
- for (i = 0; i < t1_interfaces; i++)
- {
- xtensa_interface t1_int
- = xtensa_interfaceOperand_interface (isa, t1->opcode, j);
- int t1_class = xtensa_interface_class_id (isa, t1_int);
- t1_inout = xtensa_interface_inout (isa, t1_int);
- if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
- t1_volatile = TRUE;
- if (t1_volatile && t2_volatile && (t1_class == t2_class))
- return 'f';
- if (t1_int != t2_int)
- continue;
- if (t2_inout == 'i' && t1_inout == 'o')
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout == 'i' && t2_inout == 'o')
- {
- conflict = 'a';
- continue;
- }
- if (t1_inout != 'i' && t2_inout != 'i')
- return 'e';
- }
- }
- return conflict;
- }
- static xtensa_format
- xg_find_narrowest_format (vliw_insn *vinsn)
- {
- /* Right now we assume that the ops within the vinsn are properly
- ordered for the slots that the programmer wanted them in. In
- other words, we don't rearrange the ops in hopes of finding a
- better format. The scheduler handles that. */
- xtensa_isa isa = xtensa_default_isa;
- xtensa_format format;
- xtensa_opcode nop_opcode = xtensa_nop_opcode;
- if (vinsn->num_slots == 1)
- return xg_get_single_format (vinsn->slots[0].opcode);
- for (format = 0; format < xtensa_isa_num_formats (isa); format++)
- {
- vliw_insn v_copy;
- xg_copy_vinsn (&v_copy, vinsn);
- if (xtensa_format_num_slots (isa, format) == v_copy.num_slots)
- {
- int slot;
- int fit = 0;
- for (slot = 0; slot < v_copy.num_slots; slot++)
- {
- if (v_copy.slots[slot].opcode == nop_opcode)
- {
- v_copy.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, format, slot);
- v_copy.slots[slot].ntok = 0;
- }
- if (opcode_fits_format_slot (v_copy.slots[slot].opcode,
- format, slot))
- fit++;
- else if (v_copy.num_slots > 1)
- {
- TInsn widened;
- /* Try the widened version. */
- if (!v_copy.slots[slot].keep_wide
- && !v_copy.slots[slot].is_specific_opcode
- && xg_is_single_relaxable_insn (&v_copy.slots[slot],
- &widened, TRUE)
- && opcode_fits_format_slot (widened.opcode,
- format, slot))
- {
- v_copy.slots[slot] = widened;
- fit++;
- }
- }
- }
- if (fit == v_copy.num_slots)
- {
- xg_copy_vinsn (vinsn, &v_copy);
- xtensa_format_encode (isa, format, vinsn->insnbuf);
- vinsn->format = format;
- break;
- }
- }
- }
- if (format == xtensa_isa_num_formats (isa))
- return XTENSA_UNDEFINED;
- return format;
- }
- /* Return the additional space needed in a frag
- for possible relaxations of any ops in a VLIW insn.
- Also fill out the relaxations that might be required of
- each tinsn in the vinsn. */
- static int
- relaxation_requirements (vliw_insn *vinsn, bfd_boolean *pfinish_frag)
- {
- bfd_boolean finish_frag = FALSE;
- int extra_space = 0;
- int slot;
- for (slot = 0; slot < vinsn->num_slots; slot++)
- {
- TInsn *tinsn = &vinsn->slots[slot];
- if (!tinsn_has_symbolic_operands (tinsn))
- {
- /* A narrow instruction could be widened later to help
- alignment issues. */
- if (xg_is_single_relaxable_insn (tinsn, 0, TRUE)
- && !tinsn->is_specific_opcode
- && vinsn->num_slots == 1)
- {
- /* Difference in bytes between narrow and wide insns... */
- extra_space += 1;
- tinsn->subtype = RELAX_NARROW;
- }
- }
- else
- {
- if (workaround_b_j_loop_end
- && tinsn->opcode == xtensa_jx_opcode
- && use_transform ())
- {
- /* Add 2 of these. */
- extra_space += 3; /* for the nop size */
- tinsn->subtype = RELAX_ADD_NOP_IF_PRE_LOOP_END;
- }
- /* Need to assemble it with space for the relocation. */
- if (xg_is_relaxable_insn (tinsn, 0)
- && !tinsn->is_specific_opcode)
- {
- int max_size = xg_get_max_insn_widen_size (tinsn->opcode);
- int max_literal_size =
- xg_get_max_insn_widen_literal_size (tinsn->opcode);
- tinsn->literal_space = max_literal_size;
- tinsn->subtype = RELAX_IMMED;
- extra_space += max_size;
- }
- else
- {
- /* A fix record will be added for this instruction prior
- to relaxation, so make it end the frag. */
- finish_frag = TRUE;
- }
- }
- }
- *pfinish_frag = finish_frag;
- return extra_space;
- }
- static void
- bundle_tinsn (TInsn *tinsn, vliw_insn *vinsn)
- {
- xtensa_isa isa = xtensa_default_isa;
- int slot, chosen_slot;
- vinsn->format = xg_get_single_format (tinsn->opcode);
- gas_assert (vinsn->format != XTENSA_UNDEFINED);
- vinsn->num_slots = xtensa_format_num_slots (isa, vinsn->format);
- chosen_slot = xg_get_single_slot (tinsn->opcode);
- for (slot = 0; slot < vinsn->num_slots; slot++)
- {
- if (slot == chosen_slot)
- vinsn->slots[slot] = *tinsn;
- else
- {
- vinsn->slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, vinsn->format, slot);
- vinsn->slots[slot].ntok = 0;
- vinsn->slots[slot].insn_type = ITYPE_INSN;
- }
- }
- }
- static bfd_boolean
- emit_single_op (TInsn *orig_insn)
- {
- int i;
- IStack istack; /* put instructions into here */
- symbolS *lit_sym = NULL;
- symbolS *label_sym = NULL;
- istack_init (&istack);
- /* Special-case for "movi aX, foo" which is guaranteed to need relaxing.
- Because the scheduling and bundling characteristics of movi and
- l32r or const16 are so different, we can do much better if we relax
- it prior to scheduling and bundling, rather than after. */
- if ((orig_insn->opcode == xtensa_movi_opcode
- || orig_insn->opcode == xtensa_movi_n_opcode)
- && !cur_vinsn.inside_bundle
- && (orig_insn->tok[1].X_op == O_symbol
- || orig_insn->tok[1].X_op == O_pltrel
- || orig_insn->tok[1].X_op == O_tlsfunc
- || orig_insn->tok[1].X_op == O_tlsarg
- || orig_insn->tok[1].X_op == O_tpoff
- || orig_insn->tok[1].X_op == O_dtpoff)
- && !orig_insn->is_specific_opcode && use_transform ())
- xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0);
- else
- if (xg_expand_assembly_insn (&istack, orig_insn))
- return TRUE;
- for (i = 0; i < istack.ninsn; i++)
- {
- TInsn *insn = &istack.insn[i];
- switch (insn->insn_type)
- {
- case ITYPE_LITERAL:
- gas_assert (lit_sym == NULL);
- lit_sym = xg_assemble_literal (insn);
- break;
- case ITYPE_LABEL:
- {
- static int relaxed_sym_idx = 0;
- char *label = xmalloc (strlen (FAKE_LABEL_NAME) + 12);
- sprintf (label, "%s_rl_%x", FAKE_LABEL_NAME, relaxed_sym_idx++);
- colon (label);
- gas_assert (label_sym == NULL);
- label_sym = symbol_find_or_make (label);
- gas_assert (label_sym);
- free (label);
- }
- break;
- case ITYPE_INSN:
- {
- vliw_insn v;
- if (lit_sym)
- xg_resolve_literals (insn, lit_sym);
- if (label_sym)
- xg_resolve_labels (insn, label_sym);
- xg_init_vinsn (&v);
- bundle_tinsn (insn, &v);
- finish_vinsn (&v);
- xg_free_vinsn (&v);
- }
- break;
- default:
- gas_assert (0);
- break;
- }
- }
- return FALSE;
- }
- static int
- total_frag_text_expansion (fragS *fragP)
- {
- int slot;
- int total_expansion = 0;
- for (slot = 0; slot < config_max_slots; slot++)
- total_expansion += fragP->tc_frag_data.text_expansion[slot];
- return total_expansion;
- }
- /* Emit a vliw instruction to the current fragment. */
- static void
- xg_assemble_vliw_tokens (vliw_insn *vinsn)
- {
- bfd_boolean finish_frag;
- bfd_boolean is_jump = FALSE;
- bfd_boolean is_branch = FALSE;
- xtensa_isa isa = xtensa_default_isa;
- int insn_size;
- int extra_space;
- char *f = NULL;
- int slot;
- struct dwarf2_line_info debug_line;
- bfd_boolean loc_directive_seen = FALSE;
- TInsn *tinsn;
- memset (&debug_line, 0, sizeof (struct dwarf2_line_info));
- if (generating_literals)
- {
- static int reported = 0;
- if (reported < 4)
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
- _("cannot assemble into a literal fragment"));
- if (reported == 3)
- as_bad (_("..."));
- reported++;
- return;
- }
- if (frag_now_fix () != 0
- && (! frag_now->tc_frag_data.is_insn
- || (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- || (!use_transform ()) != frag_now->tc_frag_data.is_no_transform
- || (directive_state[directive_longcalls]
- != frag_now->tc_frag_data.use_longcalls)
- || (directive_state[directive_absolute_literals]
- != frag_now->tc_frag_data.use_absolute_literals)))
- {
- frag_wane (frag_now);
- frag_new (0);
- xtensa_set_frag_assembly_state (frag_now);
- }
- if (workaround_a0_b_retw
- && vinsn->num_slots == 1
- && (get_last_insn_flags (now_seg, now_subseg) & FLAG_IS_A0_WRITER) != 0
- && xtensa_opcode_is_branch (isa, vinsn->slots[0].opcode) == 1
- && use_transform ())
- {
- has_a0_b_retw = TRUE;
- /* Mark this fragment with the special RELAX_ADD_NOP_IF_A0_B_RETW.
- After the first assembly pass we will check all of them and
- add a nop if needed. */
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 4, 4,
- RELAX_ADD_NOP_IF_A0_B_RETW,
- frag_now->fr_symbol,
- frag_now->fr_offset,
- NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 4, 4,
- RELAX_ADD_NOP_IF_A0_B_RETW,
- frag_now->fr_symbol,
- frag_now->fr_offset,
- NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- for (slot = 0; slot < vinsn->num_slots; slot++)
- {
- tinsn = &vinsn->slots[slot];
- /* See if the instruction implies an aligned section. */
- if (xtensa_opcode_is_loop (isa, tinsn->opcode) == 1)
- record_alignment (now_seg, 2);
- /* Determine the best line number for debug info. */
- if ((tinsn->loc_directive_seen || !loc_directive_seen)
- && (tinsn->debug_line.filenum != debug_line.filenum
- || tinsn->debug_line.line < debug_line.line
- || tinsn->debug_line.column < debug_line.column))
- debug_line = tinsn->debug_line;
- if (tinsn->loc_directive_seen)
- loc_directive_seen = TRUE;
- }
- /* Special cases for instructions that force an alignment... */
- /* None of these opcodes are bundle-able. */
- if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1)
- {
- int max_fill;
- /* Remember the symbol that marks the end of the loop in the frag
- that marks the start of the loop. This way we can easily find
- the end of the loop at the beginning, without adding special code
- to mark the loop instructions themselves. */
- symbolS *target_sym = NULL;
- if (vinsn->slots[0].tok[1].X_op == O_symbol)
- target_sym = vinsn->slots[0].tok[1].X_add_symbol;
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
- max_fill = get_text_align_max_fill_size
- (get_text_align_power (xtensa_fetch_width),
- TRUE, frag_now->tc_frag_data.is_no_density);
- if (use_transform ())
- frag_var (rs_machine_dependent, max_fill, max_fill,
- RELAX_ALIGN_NEXT_OPCODE, target_sym, 0, NULL);
- else
- frag_var (rs_machine_dependent, 0, 0,
- RELAX_CHECK_ALIGN_NEXT_OPCODE, target_sym, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- if (vinsn->slots[0].opcode == xtensa_entry_opcode
- && !vinsn->slots[0].is_specific_opcode)
- {
- xtensa_mark_literal_pool_location ();
- xtensa_move_labels (frag_now, 0);
- frag_var (rs_align_test, 1, 1, 0, NULL, 2, NULL);
- }
- if (vinsn->num_slots == 1)
- {
- if (workaround_a0_b_retw && use_transform ())
- set_last_insn_flags (now_seg, now_subseg, FLAG_IS_A0_WRITER,
- is_register_writer (&vinsn->slots[0], "a", 0));
- set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND,
- is_bad_loopend_opcode (&vinsn->slots[0]));
- }
- else
- set_last_insn_flags (now_seg, now_subseg, FLAG_IS_BAD_LOOPEND, FALSE);
- insn_size = xtensa_format_length (isa, vinsn->format);
- extra_space = relaxation_requirements (vinsn, &finish_frag);
- /* vinsn_to_insnbuf will produce the error. */
- if (vinsn->format != XTENSA_UNDEFINED)
- {
- f = frag_more (insn_size + extra_space);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.is_insn = TRUE;
- }
- vinsn_to_insnbuf (vinsn, f, frag_now, FALSE);
- if (vinsn->format == XTENSA_UNDEFINED)
- return;
- xtensa_insnbuf_to_chars (isa, vinsn->insnbuf, (unsigned char *) f, 0);
- if (debug_type == DEBUG_DWARF2 || loc_directive_seen)
- dwarf2_gen_line_info (frag_now_fix () - (insn_size + extra_space),
- &debug_line);
- for (slot = 0; slot < vinsn->num_slots; slot++)
- {
- tinsn = &vinsn->slots[slot];
- frag_now->tc_frag_data.slot_subtypes[slot] = tinsn->subtype;
- frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
- frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
- frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
- if (tinsn->opcode == xtensa_l32r_opcode)
- {
- frag_now->tc_frag_data.literal_frags[slot] =
- tinsn->tok[1].X_add_symbol->sy_frag;
- }
- if (tinsn->literal_space != 0)
- xg_assemble_literal_space (tinsn->literal_space, slot);
- frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
- if (tinsn->subtype == RELAX_NARROW)
- gas_assert (vinsn->num_slots == 1);
- if (xtensa_opcode_is_jump (isa, tinsn->opcode) == 1)
- is_jump = TRUE;
- if (xtensa_opcode_is_branch (isa, tinsn->opcode) == 1)
- is_branch = TRUE;
- if (tinsn->subtype || tinsn->symbol || tinsn->offset
- || tinsn->literal_frag || is_jump || is_branch)
- finish_frag = TRUE;
- }
- if (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- frag_now->tc_frag_data.is_specific_opcode = TRUE;
- if (finish_frag)
- {
- frag_variant (rs_machine_dependent,
- extra_space, extra_space, RELAX_SLOTS,
- frag_now->fr_symbol, frag_now->fr_offset, f);
- xtensa_set_frag_assembly_state (frag_now);
- }
- /* Special cases for loops:
- close_loop_end should be inserted AFTER short_loop.
- Make sure that CLOSE loops are processed BEFORE short_loops
- when converting them. */
- /* "short_loop": Add a NOP if the loop is < 4 bytes. */
- if (xtensa_opcode_is_loop (isa, vinsn->slots[0].opcode) == 1
- && !vinsn->slots[0].is_specific_opcode)
- {
- if (workaround_short_loop && use_transform ())
- {
- maybe_has_short_loop = TRUE;
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 4, 4,
- RELAX_ADD_NOP_IF_SHORT_LOOP,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 4, 4,
- RELAX_ADD_NOP_IF_SHORT_LOOP,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- }
- /* "close_loop_end": Add up to 12 bytes of NOPs to keep a
- loop at least 12 bytes away from another loop's end. */
- if (workaround_close_loop_end && use_transform ())
- {
- maybe_has_close_loop_end = TRUE;
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 12, 12,
- RELAX_ADD_NOP_IF_CLOSE_LOOP_END,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- }
- }
- if (use_transform ())
- {
- if (is_jump)
- {
- gas_assert (finish_frag);
- frag_var (rs_machine_dependent,
- xtensa_fetch_width, xtensa_fetch_width,
- RELAX_UNREACHABLE,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- xtensa_maybe_create_trampoline_frag ();
- /* Always create one here. */
- xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
- }
- else if (is_branch && do_align_targets ())
- {
- gas_assert (finish_frag);
- frag_var (rs_machine_dependent,
- xtensa_fetch_width, xtensa_fetch_width,
- RELAX_MAYBE_UNREACHABLE,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_var (rs_machine_dependent,
- 0, 0,
- RELAX_MAYBE_DESIRE_ALIGN,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- }
- /* Now, if the original opcode was a call... */
- if (do_align_targets ()
- && xtensa_opcode_is_call (isa, vinsn->slots[0].opcode) == 1)
- {
- float freq = get_subseg_total_freq (now_seg, now_subseg);
- frag_now->tc_frag_data.is_insn = TRUE;
- frag_var (rs_machine_dependent, 4, (int) freq, RELAX_DESIRE_ALIGN,
- frag_now->fr_symbol, frag_now->fr_offset, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- if (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- {
- frag_wane (frag_now);
- frag_new (0);
- xtensa_set_frag_assembly_state (frag_now);
- }
- }
- /* xtensa_end and helper functions. */
- static void xtensa_cleanup_align_frags (void);
- static void xtensa_fix_target_frags (void);
- static void xtensa_mark_narrow_branches (void);
- static void xtensa_mark_zcl_first_insns (void);
- static void xtensa_mark_difference_of_two_symbols (void);
- static void xtensa_fix_a0_b_retw_frags (void);
- static void xtensa_fix_b_j_loop_end_frags (void);
- static void xtensa_fix_close_loop_end_frags (void);
- static void xtensa_fix_short_loop_frags (void);
- static void xtensa_sanity_check (void);
- static void xtensa_add_config_info (void);
- void
- xtensa_end (void)
- {
- directive_balance ();
- xtensa_flush_pending_output ();
- past_xtensa_end = TRUE;
- xtensa_move_literals ();
- xtensa_reorder_segments ();
- xtensa_cleanup_align_frags ();
- xtensa_fix_target_frags ();
- if (workaround_a0_b_retw && has_a0_b_retw)
- xtensa_fix_a0_b_retw_frags ();
- if (workaround_b_j_loop_end)
- xtensa_fix_b_j_loop_end_frags ();
- /* "close_loop_end" should be processed BEFORE "short_loop". */
- if (workaround_close_loop_end && maybe_has_close_loop_end)
- xtensa_fix_close_loop_end_frags ();
- if (workaround_short_loop && maybe_has_short_loop)
- xtensa_fix_short_loop_frags ();
- if (align_targets)
- xtensa_mark_narrow_branches ();
- xtensa_mark_zcl_first_insns ();
- xtensa_sanity_check ();
- xtensa_add_config_info ();
- xtensa_check_frag_count ();
- }
- struct trampoline_frag
- {
- struct trampoline_frag *next;
- bfd_boolean needs_jump_around;
- fragS *fragP;
- fixS *fixP;
- };
- struct trampoline_seg
- {
- struct trampoline_seg *next;
- asection *seg;
- struct trampoline_frag trampoline_list;
- };
- static struct trampoline_seg trampoline_seg_list;
- #define J_RANGE (128 * 1024)
- static int unreachable_count = 0;
- static void
- xtensa_maybe_create_trampoline_frag (void)
- {
- if (!use_trampolines)
- return;
- /* We create an area for possible trampolines every 10 unreachable frags.
- These are preferred over the ones not preceded by an unreachable frag,
- because we don't have to jump around them. This function is called after
- each RELAX_UNREACHABLE frag is created. */
- if (++unreachable_count > 10)
- {
- xtensa_create_trampoline_frag (FALSE);
- clear_frag_count ();
- unreachable_count = 0;
- }
- }
- static void
- xtensa_check_frag_count (void)
- {
- if (!use_trampolines || frag_now->tc_frag_data.is_no_transform)
- return;
- /* We create an area for possible trampolines every 8000 frags or so. This
- is an estimate based on the max range of a "j" insn (+/-128K) divided
- by a typical frag byte count (16), minus a few for safety. This function
- is called after each source line is processed. */
- if (get_frag_count () > 8000)
- {
- xtensa_create_trampoline_frag (TRUE);
- clear_frag_count ();
- unreachable_count = 0;
- }
- /* We create an area for a possible literal pool every N (default 5000)
- frags or so. */
- xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
- }
- static xtensa_insnbuf trampoline_buf = NULL;
- static xtensa_insnbuf trampoline_slotbuf = NULL;
- static xtensa_insnbuf litpool_buf = NULL;
- static xtensa_insnbuf litpool_slotbuf = NULL;
- #define TRAMPOLINE_FRAG_SIZE 3000
- static void
- xtensa_create_trampoline_frag (bfd_boolean needs_jump_around)
- {
- /* Emit a frag where we can place intermediate jump instructions,
- in case we need to jump farther than 128K bytes.
- Each jump instruction takes three bytes.
- We allocate enough for 1000 trampolines in each frag.
- If that's not enough, oh well. */
- struct trampoline_seg *ts = trampoline_seg_list.next;
- struct trampoline_frag *tf;
- char *varP;
- fragS *fragP;
- int size = TRAMPOLINE_FRAG_SIZE;
- for ( ; ts; ts = ts->next)
- {
- if (ts->seg == now_seg)
- break;
- }
- if (ts == NULL)
- {
- ts = (struct trampoline_seg *)xcalloc(sizeof (struct trampoline_seg), 1);
- ts->next = trampoline_seg_list.next;
- trampoline_seg_list.next = ts;
- ts->seg = now_seg;
- }
- frag_wane (frag_now);
- frag_new (0);
- xtensa_set_frag_assembly_state (frag_now);
- varP = frag_var (rs_machine_dependent, size, size, RELAX_TRAMPOLINE, NULL, 0, NULL);
- fragP = (fragS *)(varP - SIZEOF_STRUCT_FRAG);
- if (trampoline_buf == NULL)
- {
- trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa);
- trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
- }
- tf = (struct trampoline_frag *)xmalloc(sizeof (struct trampoline_frag));
- tf->next = ts->trampoline_list.next;
- ts->trampoline_list.next = tf;
- tf->needs_jump_around = needs_jump_around;
- tf->fragP = fragP;
- tf->fixP = NULL;
- }
- static struct trampoline_seg *
- find_trampoline_seg (asection *seg)
- {
- struct trampoline_seg *ts = trampoline_seg_list.next;
- for ( ; ts; ts = ts->next)
- {
- if (ts->seg == seg)
- return ts;
- }
- return NULL;
- }
- void dump_trampolines (void);
- void
- dump_trampolines (void)
- {
- struct trampoline_seg *ts = trampoline_seg_list.next;
- for ( ; ts; ts = ts->next)
- {
- asection *seg = ts->seg;
- if (seg == NULL)
- continue;
- fprintf(stderr, "SECTION %s\n", seg->name);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- for ( ; tf; tf = tf->next)
- {
- if (tf->fragP == NULL)
- continue;
- fprintf(stderr, " 0x%08x: fix=%d, jump_around=%s\n",
- (int)tf->fragP->fr_address, (int)tf->fragP->fr_fix,
- tf->needs_jump_around ? "T" : "F");
- }
- }
- }
- static void dump_litpools (void) __attribute__ ((unused));
- static void
- dump_litpools (void)
- {
- struct litpool_seg *lps = litpool_seg_list.next;
- struct litpool_frag *lpf;
- for ( ; lps ; lps = lps->next )
- {
- printf("litpool seg %s\n", lps->seg->name);
- for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
- {
- fragS *litfrag = lpf->fragP->fr_next;
- int count = 0;
- while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
- {
- if (litfrag->fr_fix == 4)
- count++;
- litfrag = litfrag->fr_next;
- }
- printf(" %ld <%d:%d> (%d) [%d]: ",
- lpf->addr, lpf->priority, lpf->original_priority,
- lpf->fragP->fr_line, count);
- //dump_frag(lpf->fragP);
- }
- }
- }
- static void
- xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
- bfd_boolean only_if_needed)
- {
- struct litpool_seg *lps = litpool_seg_list.next;
- fragS *fragP;
- struct litpool_frag *lpf;
- bfd_boolean needed = FALSE;
- if (use_literal_section || !auto_litpools)
- return;
- for ( ; lps ; lps = lps->next )
- {
- if (lps->seg == now_seg)
- break;
- }
- if (lps == NULL)
- {
- lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
- lps->next = litpool_seg_list.next;
- litpool_seg_list.next = lps;
- lps->seg = now_seg;
- lps->frag_list.next = &lps->frag_list;
- lps->frag_list.prev = &lps->frag_list;
- }
- lps->frag_count++;
- if (create)
- {
- if (only_if_needed)
- {
- if (past_xtensa_end || !use_transform() ||
- frag_now->tc_frag_data.is_no_transform)
- {
- return;
- }
- if (auto_litpool_limit <= 0)
- {
- /* Don't create a litpool based only on frag count. */
- return;
- }
- else if (lps->frag_count > auto_litpool_limit)
- {
- needed = TRUE;
- }
- else
- {
- return;
- }
- }
- else
- {
- needed = TRUE;
- }
- }
- if (needed)
- {
- int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn. */
- /* Create a potential site for a literal pool. */
- frag_wane (frag_now);
- frag_new (0);
- xtensa_set_frag_assembly_state (frag_now);
- fragP = frag_now;
- fragP->tc_frag_data.lit_frchain = frchain_now;
- fragP->tc_frag_data.literal_frag = fragP;
- frag_var (rs_machine_dependent, size, size,
- (only_if_needed) ?
- RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
- RELAX_LITERAL_POOL_BEGIN,
- NULL, 0, NULL);
- frag_now->tc_frag_data.lit_seg = now_seg;
- frag_variant (rs_machine_dependent, 0, 0,
- RELAX_LITERAL_POOL_END, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- else
- {
- /* RELAX_LITERAL_POOL_BEGIN frag is being created;
- just record it here. */
- fragP = frag_now;
- }
- lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
- /* Insert at tail of circular list. */
- lpf->addr = 0;
- lps->frag_list.prev->next = lpf;
- lpf->next = &lps->frag_list;
- lpf->prev = lps->frag_list.prev;
- lps->frag_list.prev = lpf;
- lpf->fragP = fragP;
- lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
- lpf->original_priority = lpf->priority;
- lps->frag_count = 0;
- }
- static void
- xtensa_cleanup_align_frags (void)
- {
- frchainS *frchP;
- asection *s;
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if ((fragP->fr_type == rs_align
- || fragP->fr_type == rs_align_code
- || (fragP->fr_type == rs_machine_dependent
- && (fragP->fr_subtype == RELAX_DESIRE_ALIGN
- || fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)))
- && fragP->fr_fix == 0)
- {
- fragS *next = fragP->fr_next;
- while (next
- && next->fr_fix == 0
- && next->fr_type == rs_machine_dependent
- && next->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
- {
- frag_wane (next);
- next = next->fr_next;
- }
- }
- /* If we don't widen branch targets, then they
- will be easier to align. */
- if (fragP->tc_frag_data.is_branch_target
- && fragP->fr_opcode == fragP->fr_literal
- && fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_SLOTS
- && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
- frag_wane (fragP);
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_UNREACHABLE)
- fragP->tc_frag_data.is_unreachable = TRUE;
- }
- }
- }
- /* Re-process all of the fragments looking to convert all of the
- RELAX_DESIRE_ALIGN_IF_TARGET fragments. If there is a branch
- target in the next fragment, convert this to RELAX_DESIRE_ALIGN.
- Otherwise, convert to a .fill 0. */
- static void
- xtensa_fix_target_frags (void)
- {
- frchainS *frchP;
- asection *s;
- /* When this routine is called, all of the subsections are still intact
- so we walk over subsections instead of sections. */
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_DESIRE_ALIGN_IF_TARGET)
- {
- if (next_frag_is_branch_target (fragP))
- fragP->fr_subtype = RELAX_DESIRE_ALIGN;
- else
- frag_wane (fragP);
- }
- }
- }
- }
- static bfd_boolean is_narrow_branch_guaranteed_in_range (fragS *, TInsn *);
- static void
- xtensa_mark_narrow_branches (void)
- {
- frchainS *frchP;
- asection *s;
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_SLOTS
- && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
- {
- vliw_insn vinsn;
- vinsn_from_chars (&vinsn, fragP->fr_opcode);
- tinsn_immed_from_frag (&vinsn.slots[0], fragP, 0);
- if (vinsn.num_slots == 1
- && xtensa_opcode_is_branch (xtensa_default_isa,
- vinsn.slots[0].opcode) == 1
- && xg_get_single_size (vinsn.slots[0].opcode) == 2
- && is_narrow_branch_guaranteed_in_range (fragP,
- &vinsn.slots[0]))
- {
- fragP->fr_subtype = RELAX_SLOTS;
- fragP->tc_frag_data.slot_subtypes[0] = RELAX_NARROW;
- fragP->tc_frag_data.is_aligning_branch = 1;
- }
- }
- }
- }
- }
- /* A branch is typically widened only when its target is out of
- range. However, we would like to widen them to align a subsequent
- branch target when possible.
- Because the branch relaxation code is so convoluted, the optimal solution
- (combining the two cases) is difficult to get right in all circumstances.
- We therefore go with an "almost as good" solution, where we only
- use for alignment narrow branches that definitely will not expand to a
- jump and a branch. These functions find and mark these cases. */
- /* The range in bytes of BNEZ.N and BEQZ.N. The target operand is encoded
- as PC + 4 + imm6, where imm6 is a 6-bit immediate ranging from 0 to 63.
- We start counting beginning with the frag after the 2-byte branch, so the
- maximum offset is (4 - 2) + 63 = 65. */
- #define MAX_IMMED6 65
- static offsetT unrelaxed_frag_max_size (fragS *);
- static bfd_boolean
- is_narrow_branch_guaranteed_in_range (fragS *fragP, TInsn *tinsn)
- {
- const expressionS *exp = &tinsn->tok[1];
- symbolS *symbolP = exp->X_add_symbol;
- offsetT max_distance = exp->X_add_number;
- fragS *target_frag;
- if (exp->X_op != O_symbol)
- return FALSE;
- target_frag = symbol_get_frag (symbolP);
- max_distance += (S_GET_VALUE (symbolP) - target_frag->fr_address);
- if (is_branch_jmp_to_next (tinsn, fragP))
- return FALSE;
- /* The branch doesn't branch over it's own frag,
- but over the subsequent ones. */
- fragP = fragP->fr_next;
- while (fragP != NULL && fragP != target_frag && max_distance <= MAX_IMMED6)
- {
- max_distance += unrelaxed_frag_max_size (fragP);
- fragP = fragP->fr_next;
- }
- if (max_distance <= MAX_IMMED6 && fragP == target_frag)
- return TRUE;
- return FALSE;
- }
- static void
- xtensa_mark_zcl_first_insns (void)
- {
- frchainS *frchP;
- asection *s;
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
- || fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE))
- {
- /* Find the loop frag. */
- fragS *loop_frag = next_non_empty_frag (fragP);
- /* Find the first insn frag. */
- fragS *targ_frag = next_non_empty_frag (loop_frag);
- /* Handle a corner case that comes up in hardware
- diagnostics. The original assembly looks like this:
- loop aX, LabelA
- <empty_frag>--not found by next_non_empty_frag
- loop aY, LabelB
- Depending on the start address, the assembler may or
- may not change it to look something like this:
- loop aX, LabelA
- nop--frag isn't empty anymore
- loop aY, LabelB
- So set up to check the alignment of the nop if it
- exists */
- while (loop_frag != targ_frag)
- {
- if (loop_frag->fr_type == rs_machine_dependent
- && (loop_frag->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
- || loop_frag->fr_subtype
- == RELAX_CHECK_ALIGN_NEXT_OPCODE))
- targ_frag = loop_frag;
- else
- loop_frag = loop_frag->fr_next;
- }
- /* Of course, sometimes (mostly for toy test cases) a
- zero-cost loop instruction is the last in a section. */
- if (targ_frag)
- {
- targ_frag->tc_frag_data.is_first_loop_insn = TRUE;
- /* Do not widen a frag that is the first instruction of a
- zero-cost loop. It makes that loop harder to align. */
- if (targ_frag->fr_type == rs_machine_dependent
- && targ_frag->fr_subtype == RELAX_SLOTS
- && (targ_frag->tc_frag_data.slot_subtypes[0]
- == RELAX_NARROW))
- {
- if (targ_frag->tc_frag_data.is_aligning_branch)
- targ_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED;
- else
- {
- frag_wane (targ_frag);
- targ_frag->tc_frag_data.slot_subtypes[0] = 0;
- }
- }
- }
- if (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)
- frag_wane (fragP);
- }
- }
- }
- }
- /* When a difference-of-symbols expression is encoded as a uleb128 or
- sleb128 value, the linker is unable to adjust that value to account for
- link-time relaxation. Mark all the code between such symbols so that
- its size cannot be changed by linker relaxation. */
- static void
- xtensa_mark_difference_of_two_symbols (void)
- {
- symbolS *expr_sym;
- for (expr_sym = expr_symbols; expr_sym;
- expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
- {
- expressionS *exp = symbol_get_value_expression (expr_sym);
- if (exp->X_op == O_subtract)
- {
- symbolS *left = exp->X_add_symbol;
- symbolS *right = exp->X_op_symbol;
- /* Difference of two symbols not in the same section
- are handled with relocations in the linker. */
- if (S_GET_SEGMENT (left) == S_GET_SEGMENT (right))
- {
- fragS *start;
- fragS *end;
- fragS *walk;
- if (symbol_get_frag (left)->fr_address
- <= symbol_get_frag (right)->fr_address)
- {
- start = symbol_get_frag (left);
- end = symbol_get_frag (right);
- }
- else
- {
- start = symbol_get_frag (right);
- end = symbol_get_frag (left);
- }
- if (start->tc_frag_data.no_transform_end != NULL)
- walk = start->tc_frag_data.no_transform_end;
- else
- walk = start;
- do
- {
- walk->tc_frag_data.is_no_transform = 1;
- walk = walk->fr_next;
- }
- while (walk && walk->fr_address < end->fr_address);
- start->tc_frag_data.no_transform_end = walk;
- }
- }
- }
- }
- /* Re-process all of the fragments looking to convert all of the
- RELAX_ADD_NOP_IF_A0_B_RETW. If the next instruction is a
- conditional branch or a retw/retw.n, convert this frag to one that
- will generate a NOP. In any case close it off with a .fill 0. */
- static bfd_boolean next_instrs_are_b_retw (fragS *);
- static void
- xtensa_fix_a0_b_retw_frags (void)
- {
- frchainS *frchP;
- asection *s;
- /* When this routine is called, all of the subsections are still intact
- so we walk over subsections instead of sections. */
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_ADD_NOP_IF_A0_B_RETW)
- {
- if (next_instrs_are_b_retw (fragP))
- {
- if (fragP->tc_frag_data.is_no_transform)
- as_bad (_("instruction sequence (write a0, branch, retw) may trigger hardware errata"));
- else
- relax_frag_add_nop (fragP);
- }
- frag_wane (fragP);
- }
- }
- }
- }
- static bfd_boolean
- next_instrs_are_b_retw (fragS *fragP)
- {
- xtensa_opcode opcode;
- xtensa_format fmt;
- const fragS *next_fragP = next_non_empty_frag (fragP);
- static xtensa_insnbuf insnbuf = NULL;
- static xtensa_insnbuf slotbuf = NULL;
- xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
- int slot;
- bfd_boolean branch_seen = FALSE;
- if (!insnbuf)
- {
- insnbuf = xtensa_insnbuf_alloc (isa);
- slotbuf = xtensa_insnbuf_alloc (isa);
- }
- if (next_fragP == NULL)
- return FALSE;
- /* Check for the conditional branch. */
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- return FALSE;
- for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
- {
- xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
- opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
- branch_seen = (branch_seen
- || xtensa_opcode_is_branch (isa, opcode) == 1);
- }
- if (!branch_seen)
- return FALSE;
- offset += xtensa_format_length (isa, fmt);
- if (offset == next_fragP->fr_fix)
- {
- next_fragP = next_non_empty_frag (next_fragP);
- offset = 0;
- }
- if (next_fragP == NULL)
- return FALSE;
- /* Check for the retw/retw.n. */
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) &next_fragP->fr_literal[offset], 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- /* Because RETW[.N] is not bundleable, a VLIW bundle here means that we
- have no problems. */
- if (fmt == XTENSA_UNDEFINED
- || xtensa_format_num_slots (isa, fmt) != 1)
- return FALSE;
- xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf);
- opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
- if (opcode == xtensa_retw_opcode || opcode == xtensa_retw_n_opcode)
- return TRUE;
- return FALSE;
- }
- /* Re-process all of the fragments looking to convert all of the
- RELAX_ADD_NOP_IF_PRE_LOOP_END. If there is one instruction and a
- loop end label, convert this frag to one that will generate a NOP.
- In any case close it off with a .fill 0. */
- static bfd_boolean next_instr_is_loop_end (fragS *);
- static void
- xtensa_fix_b_j_loop_end_frags (void)
- {
- frchainS *frchP;
- asection *s;
- /* When this routine is called, all of the subsections are still intact
- so we walk over subsections instead of sections. */
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_ADD_NOP_IF_PRE_LOOP_END)
- {
- if (next_instr_is_loop_end (fragP))
- {
- if (fragP->tc_frag_data.is_no_transform)
- as_bad (_("branching or jumping to a loop end may trigger hardware errata"));
- else
- relax_frag_add_nop (fragP);
- }
- frag_wane (fragP);
- }
- }
- }
- }
- static bfd_boolean
- next_instr_is_loop_end (fragS *fragP)
- {
- const fragS *next_fragP;
- if (next_frag_is_loop_target (fragP))
- return FALSE;
- next_fragP = next_non_empty_frag (fragP);
- if (next_fragP == NULL)
- return FALSE;
- if (!next_frag_is_loop_target (next_fragP))
- return FALSE;
- /* If the size is >= 3 then there is more than one instruction here.
- The hardware bug will not fire. */
- if (next_fragP->fr_fix > 3)
- return FALSE;
- return TRUE;
- }
- /* Re-process all of the fragments looking to convert all of the
- RELAX_ADD_NOP_IF_CLOSE_LOOP_END. If there is an loop end that is
- not MY loop's loop end within 12 bytes, add enough nops here to
- make it at least 12 bytes away. In any case close it off with a
- .fill 0. */
- static offsetT min_bytes_to_other_loop_end
- (fragS *, fragS *, offsetT);
- static void
- xtensa_fix_close_loop_end_frags (void)
- {
- frchainS *frchP;
- asection *s;
- /* When this routine is called, all of the subsections are still intact
- so we walk over subsections instead of sections. */
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- fragS *current_target = NULL;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && ((fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE)
- || (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)))
- current_target = symbol_get_frag (fragP->fr_symbol);
- if (current_target
- && fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_ADD_NOP_IF_CLOSE_LOOP_END)
- {
- offsetT min_bytes;
- int bytes_added = 0;
- #define REQUIRED_LOOP_DIVIDING_BYTES 12
- /* Max out at 12. */
- min_bytes = min_bytes_to_other_loop_end
- (fragP->fr_next, current_target, REQUIRED_LOOP_DIVIDING_BYTES);
- if (min_bytes < REQUIRED_LOOP_DIVIDING_BYTES)
- {
- if (fragP->tc_frag_data.is_no_transform)
- as_bad (_("loop end too close to another loop end may trigger hardware errata"));
- else
- {
- while (min_bytes + bytes_added
- < REQUIRED_LOOP_DIVIDING_BYTES)
- {
- int length = 3;
- if (fragP->fr_var < length)
- as_fatal (_("fr_var %lu < length %d"),
- (long) fragP->fr_var, length);
- else
- {
- assemble_nop (length,
- fragP->fr_literal + fragP->fr_fix);
- fragP->fr_fix += length;
- fragP->fr_var -= length;
- }
- bytes_added += length;
- }
- }
- }
- frag_wane (fragP);
- }
- gas_assert (fragP->fr_type != rs_machine_dependent
- || fragP->fr_subtype != RELAX_ADD_NOP_IF_CLOSE_LOOP_END);
- }
- }
- }
- static offsetT unrelaxed_frag_min_size (fragS *);
- static offsetT
- min_bytes_to_other_loop_end (fragS *fragP,
- fragS *current_target,
- offsetT max_size)
- {
- offsetT offset = 0;
- fragS *current_fragP;
- for (current_fragP = fragP;
- current_fragP;
- current_fragP = current_fragP->fr_next)
- {
- if (current_fragP->tc_frag_data.is_loop_target
- && current_fragP != current_target)
- return offset;
- offset += unrelaxed_frag_min_size (current_fragP);
- if (offset >= max_size)
- return max_size;
- }
- return max_size;
- }
- static offsetT
- unrelaxed_frag_min_size (fragS *fragP)
- {
- offsetT size = fragP->fr_fix;
- /* Add fill size. */
- if (fragP->fr_type == rs_fill)
- size += fragP->fr_offset;
- return size;
- }
- static offsetT
- unrelaxed_frag_max_size (fragS *fragP)
- {
- offsetT size = fragP->fr_fix;
- switch (fragP->fr_type)
- {
- case 0:
- /* Empty frags created by the obstack allocation scheme
- end up with type 0. */
- break;
- case rs_fill:
- case rs_org:
- case rs_space:
- size += fragP->fr_offset;
- break;
- case rs_align:
- case rs_align_code:
- case rs_align_test:
- case rs_leb128:
- case rs_cfa:
- case rs_dwarf2dbg:
- /* No further adjustments needed. */
- break;
- case rs_machine_dependent:
- if (fragP->fr_subtype != RELAX_DESIRE_ALIGN)
- size += fragP->fr_var;
- break;
- default:
- /* We had darn well better know how big it is. */
- gas_assert (0);
- break;
- }
- return size;
- }
- /* Re-process all of the fragments looking to convert all
- of the RELAX_ADD_NOP_IF_SHORT_LOOP. If:
- A)
- 1) the instruction size count to the loop end label
- is too short (<= 2 instructions),
- 2) loop has a jump or branch in it
- or B)
- 1) workaround_all_short_loops is TRUE
- 2) The generating loop was a 'loopgtz' or 'loopnez'
- 3) the instruction size count to the loop end label is too short
- (<= 2 instructions)
- then convert this frag (and maybe the next one) to generate a NOP.
- In any case close it off with a .fill 0. */
- static int count_insns_to_loop_end (fragS *, bfd_boolean, int);
- static bfd_boolean branch_before_loop_end (fragS *);
- static void
- xtensa_fix_short_loop_frags (void)
- {
- frchainS *frchP;
- asection *s;
- /* When this routine is called, all of the subsections are still intact
- so we walk over subsections instead of sections. */
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- xtensa_opcode current_opcode = XTENSA_UNDEFINED;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && ((fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE)
- || (fragP->fr_subtype == RELAX_CHECK_ALIGN_NEXT_OPCODE)))
- {
- TInsn t_insn;
- fragS *loop_frag = next_non_empty_frag (fragP);
- tinsn_from_chars (&t_insn, loop_frag->fr_opcode, 0);
- current_opcode = t_insn.opcode;
- gas_assert (xtensa_opcode_is_loop (xtensa_default_isa,
- current_opcode) == 1);
- }
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_ADD_NOP_IF_SHORT_LOOP)
- {
- if (count_insns_to_loop_end (fragP->fr_next, TRUE, 3) < 3
- && (branch_before_loop_end (fragP->fr_next)
- || (workaround_all_short_loops
- && current_opcode != XTENSA_UNDEFINED
- && current_opcode != xtensa_loop_opcode)))
- {
- if (fragP->tc_frag_data.is_no_transform)
- as_bad (_("loop containing less than three instructions may trigger hardware errata"));
- else
- relax_frag_add_nop (fragP);
- }
- frag_wane (fragP);
- }
- }
- }
- }
- static int unrelaxed_frag_min_insn_count (fragS *);
- static int
- count_insns_to_loop_end (fragS *base_fragP,
- bfd_boolean count_relax_add,
- int max_count)
- {
- fragS *fragP = NULL;
- int insn_count = 0;
- fragP = base_fragP;
- for (; fragP && !fragP->tc_frag_data.is_loop_target; fragP = fragP->fr_next)
- {
- insn_count += unrelaxed_frag_min_insn_count (fragP);
- if (insn_count >= max_count)
- return max_count;
- if (count_relax_add)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_ADD_NOP_IF_SHORT_LOOP)
- {
- /* In order to add the appropriate number of
- NOPs, we count an instruction for downstream
- occurrences. */
- insn_count++;
- if (insn_count >= max_count)
- return max_count;
- }
- }
- }
- return insn_count;
- }
- static int
- unrelaxed_frag_min_insn_count (fragS *fragP)
- {
- xtensa_isa isa = xtensa_default_isa;
- static xtensa_insnbuf insnbuf = NULL;
- int insn_count = 0;
- int offset = 0;
- if (!fragP->tc_frag_data.is_insn)
- return insn_count;
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
- /* Decode the fixed instructions. */
- while (offset < fragP->fr_fix)
- {
- xtensa_format fmt;
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- {
- as_fatal (_("undecodable instruction in instruction frag"));
- return insn_count;
- }
- offset += xtensa_format_length (isa, fmt);
- insn_count++;
- }
- return insn_count;
- }
- static bfd_boolean unrelaxed_frag_has_b_j (fragS *);
- static bfd_boolean
- branch_before_loop_end (fragS *base_fragP)
- {
- fragS *fragP;
- for (fragP = base_fragP;
- fragP && !fragP->tc_frag_data.is_loop_target;
- fragP = fragP->fr_next)
- {
- if (unrelaxed_frag_has_b_j (fragP))
- return TRUE;
- }
- return FALSE;
- }
- static bfd_boolean
- unrelaxed_frag_has_b_j (fragS *fragP)
- {
- static xtensa_insnbuf insnbuf = NULL;
- xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
- if (!fragP->tc_frag_data.is_insn)
- return FALSE;
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
- /* Decode the fixed instructions. */
- while (offset < fragP->fr_fix)
- {
- xtensa_format fmt;
- int slot;
- xtensa_insnbuf_from_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_literal + offset, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- return FALSE;
- for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
- {
- xtensa_opcode opcode =
- get_opcode_from_buf (fragP->fr_literal + offset, slot);
- if (xtensa_opcode_is_branch (isa, opcode) == 1
- || xtensa_opcode_is_jump (isa, opcode) == 1)
- return TRUE;
- }
- offset += xtensa_format_length (isa, fmt);
- }
- return FALSE;
- }
- /* Checks to be made after initial assembly but before relaxation. */
- static bfd_boolean is_empty_loop (const TInsn *, fragS *);
- static bfd_boolean is_local_forward_loop (const TInsn *, fragS *);
- static void
- xtensa_sanity_check (void)
- {
- char *file_name;
- unsigned line;
- frchainS *frchP;
- asection *s;
- as_where (&file_name, &line);
- for (s = stdoutput->sections; s; s = s->next)
- for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- /* Walk over all of the fragments in a subsection. */
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_SLOTS
- && fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
- {
- static xtensa_insnbuf insnbuf = NULL;
- TInsn t_insn;
- if (fragP->fr_opcode != NULL)
- {
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
- tinsn_from_chars (&t_insn, fragP->fr_opcode, 0);
- tinsn_immed_from_frag (&t_insn, fragP, 0);
- if (xtensa_opcode_is_loop (xtensa_default_isa,
- t_insn.opcode) == 1)
- {
- if (is_empty_loop (&t_insn, fragP))
- {
- new_logical_line (fragP->fr_file, fragP->fr_line);
- as_bad (_("invalid empty loop"));
- }
- if (!is_local_forward_loop (&t_insn, fragP))
- {
- new_logical_line (fragP->fr_file, fragP->fr_line);
- as_bad (_("loop target does not follow "
- "loop instruction in section"));
- }
- }
- }
- }
- }
- }
- new_logical_line (file_name, line);
- }
- #define LOOP_IMMED_OPN 1
- /* Return TRUE if the loop target is the next non-zero fragment. */
- static bfd_boolean
- is_empty_loop (const TInsn *insn, fragS *fragP)
- {
- const expressionS *exp;
- symbolS *symbolP;
- fragS *next_fragP;
- if (insn->insn_type != ITYPE_INSN)
- return FALSE;
- if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
- return FALSE;
- if (insn->ntok <= LOOP_IMMED_OPN)
- return FALSE;
- exp = &insn->tok[LOOP_IMMED_OPN];
- if (exp->X_op != O_symbol)
- return FALSE;
- symbolP = exp->X_add_symbol;
- if (!symbolP)
- return FALSE;
- if (symbol_get_frag (symbolP) == NULL)
- return FALSE;
- if (S_GET_VALUE (symbolP) != 0)
- return FALSE;
- /* Walk through the zero-size fragments from this one. If we find
- the target fragment, then this is a zero-size loop. */
- for (next_fragP = fragP->fr_next;
- next_fragP != NULL;
- next_fragP = next_fragP->fr_next)
- {
- if (next_fragP == symbol_get_frag (symbolP))
- return TRUE;
- if (next_fragP->fr_fix != 0)
- return FALSE;
- }
- return FALSE;
- }
- static bfd_boolean
- is_local_forward_loop (const TInsn *insn, fragS *fragP)
- {
- const expressionS *exp;
- symbolS *symbolP;
- fragS *next_fragP;
- if (insn->insn_type != ITYPE_INSN)
- return FALSE;
- if (xtensa_opcode_is_loop (xtensa_default_isa, insn->opcode) != 1)
- return FALSE;
- if (insn->ntok <= LOOP_IMMED_OPN)
- return FALSE;
- exp = &insn->tok[LOOP_IMMED_OPN];
- if (exp->X_op != O_symbol)
- return FALSE;
- symbolP = exp->X_add_symbol;
- if (!symbolP)
- return FALSE;
- if (symbol_get_frag (symbolP) == NULL)
- return FALSE;
- /* Walk through fragments until we find the target.
- If we do not find the target, then this is an invalid loop. */
- for (next_fragP = fragP->fr_next;
- next_fragP != NULL;
- next_fragP = next_fragP->fr_next)
- {
- if (next_fragP == symbol_get_frag (symbolP))
- return TRUE;
- }
- return FALSE;
- }
- #define XTINFO_NAME "Xtensa_Info"
- #define XTINFO_NAMESZ 12
- #define XTINFO_TYPE 1
- static void
- xtensa_add_config_info (void)
- {
- asection *info_sec;
- char *data, *p;
- int sz;
- info_sec = subseg_new (".xtensa.info", 0);
- bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
- data = xmalloc (100);
- sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
- XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
- sz = strlen (data) + 1;
- /* Add enough null terminators to pad to a word boundary. */
- do
- data[sz++] = 0;
- while ((sz & 3) != 0);
- /* Follow the standard note section layout:
- First write the length of the name string. */
- p = frag_more (4);
- md_number_to_chars (p, (valueT) XTINFO_NAMESZ, 4);
- /* Next comes the length of the "descriptor", i.e., the actual data. */
- p = frag_more (4);
- md_number_to_chars (p, (valueT) sz, 4);
- /* Write the note type. */
- p = frag_more (4);
- md_number_to_chars (p, (valueT) XTINFO_TYPE, 4);
- /* Write the name field. */
- p = frag_more (XTINFO_NAMESZ);
- memcpy (p, XTINFO_NAME, XTINFO_NAMESZ);
- /* Finally, write the descriptor. */
- p = frag_more (sz);
- memcpy (p, data, sz);
- free (data);
- }
- /* Alignment Functions. */
- static int
- get_text_align_power (unsigned target_size)
- {
- if (target_size <= 4)
- return 2;
- if (target_size <= 8)
- return 3;
- if (target_size <= 16)
- return 4;
- if (target_size <= 32)
- return 5;
- if (target_size <= 64)
- return 6;
- if (target_size <= 128)
- return 7;
- if (target_size <= 256)
- return 8;
- if (target_size <= 512)
- return 9;
- if (target_size <= 1024)
- return 10;
- gas_assert (0);
- return 0;
- }
- static int
- get_text_align_max_fill_size (int align_pow,
- bfd_boolean use_nops,
- bfd_boolean use_no_density)
- {
- if (!use_nops)
- return (1 << align_pow);
- if (use_no_density)
- return 3 * (1 << align_pow);
- return 1 + (1 << align_pow);
- }
- /* Calculate the minimum bytes of fill needed at "address" to align a
- target instruction of size "target_size" so that it does not cross a
- power-of-two boundary specified by "align_pow". If "use_nops" is FALSE,
- the fill can be an arbitrary number of bytes. Otherwise, the space must
- be filled by NOP instructions. */
- static int
- get_text_align_fill_size (addressT address,
- int align_pow,
- int target_size,
- bfd_boolean use_nops,
- bfd_boolean use_no_density)
- {
- addressT alignment, fill, fill_limit, fill_step;
- bfd_boolean skip_one = FALSE;
- alignment = (1 << align_pow);
- gas_assert (target_size > 0 && alignment >= (addressT) target_size);
- if (!use_nops)
- {
- fill_limit = alignment;
- fill_step = 1;
- }
- else if (!use_no_density)
- {
- /* Combine 2- and 3-byte NOPs to fill anything larger than one. */
- fill_limit = alignment * 2;
- fill_step = 1;
- skip_one = TRUE;
- }
- else
- {
- /* Fill with 3-byte NOPs -- can only fill multiples of 3. */
- fill_limit = alignment * 3;
- fill_step = 3;
- }
- /* Try all fill sizes until finding one that works. */
- for (fill = 0; fill < fill_limit; fill += fill_step)
- {
- if (skip_one && fill == 1)
- continue;
- if ((address + fill) >> align_pow
- == (address + fill + target_size - 1) >> align_pow)
- return fill;
- }
- gas_assert (0);
- return 0;
- }
- static int
- branch_align_power (segT sec)
- {
- /* If the Xtensa processor has a fetch width of X, and
- the section is aligned to at least that boundary, then a branch
- target need only fit within that aligned block of memory to avoid
- a stall. Otherwise, try to fit branch targets within 4-byte
- aligned blocks (which may be insufficient, e.g., if the section
- has no alignment, but it's good enough). */
- int fetch_align = get_text_align_power(xtensa_fetch_width);
- int sec_align = get_recorded_alignment (sec);
- if (sec_align >= fetch_align)
- return fetch_align;
- return 2;
- }
- /* This will assert if it is not possible. */
- static int
- get_text_align_nop_count (offsetT fill_size, bfd_boolean use_no_density)
- {
- int count = 0;
- if (use_no_density)
- {
- gas_assert (fill_size % 3 == 0);
- return (fill_size / 3);
- }
- gas_assert (fill_size != 1); /* Bad argument. */
- while (fill_size > 1)
- {
- int insn_size = 3;
- if (fill_size == 2 || fill_size == 4)
- insn_size = 2;
- fill_size -= insn_size;
- count++;
- }
- gas_assert (fill_size != 1); /* Bad algorithm. */
- return count;
- }
- static int
- get_text_align_nth_nop_size (offsetT fill_size,
- int n,
- bfd_boolean use_no_density)
- {
- int count = 0;
- if (use_no_density)
- return 3;
- gas_assert (fill_size != 1); /* Bad argument. */
- while (fill_size > 1)
- {
- int insn_size = 3;
- if (fill_size == 2 || fill_size == 4)
- insn_size = 2;
- fill_size -= insn_size;
- count++;
- if (n + 1 == count)
- return insn_size;
- }
- gas_assert (0);
- return 0;
- }
- /* For the given fragment, find the appropriate address
- for it to begin at if we are using NOPs to align it. */
- static addressT
- get_noop_aligned_address (fragS *fragP, addressT address)
- {
- /* The rule is: get next fragment's FIRST instruction. Find
- the smallest number of bytes that need to be added to
- ensure that the next fragment's FIRST instruction will fit
- in a single word.
- E.G., 2 bytes : 0, 1, 2 mod 4
- 3 bytes: 0, 1 mod 4
- If the FIRST instruction MIGHT be relaxed,
- assume that it will become a 3-byte instruction.
- Note again here that LOOP instructions are not bundleable,
- and this relaxation only applies to LOOP opcodes. */
- int fill_size = 0;
- int first_insn_size;
- int loop_insn_size;
- addressT pre_opcode_bytes;
- int align_power;
- fragS *first_insn;
- xtensa_opcode opcode;
- bfd_boolean is_loop;
- gas_assert (fragP->fr_type == rs_machine_dependent);
- gas_assert (fragP->fr_subtype == RELAX_ALIGN_NEXT_OPCODE);
- /* Find the loop frag. */
- first_insn = next_non_empty_frag (fragP);
- /* Now find the first insn frag. */
- first_insn = next_non_empty_frag (first_insn);
- is_loop = next_frag_opcode_is_loop (fragP, &opcode);
- gas_assert (is_loop);
- loop_insn_size = xg_get_single_size (opcode);
- pre_opcode_bytes = next_frag_pre_opcode_bytes (fragP);
- pre_opcode_bytes += loop_insn_size;
- /* For loops, the alignment depends on the size of the
- instruction following the loop, not the LOOP instruction. */
- if (first_insn == NULL)
- first_insn_size = xtensa_fetch_width;
- else
- first_insn_size = get_loop_align_size (frag_format_size (first_insn));
- /* If it was 8, then we'll need a larger alignment for the section. */
- align_power = get_text_align_power (first_insn_size);
- record_alignment (now_seg, align_power);
- fill_size = get_text_align_fill_size
- (address + pre_opcode_bytes, align_power, first_insn_size, TRUE,
- fragP->tc_frag_data.is_no_density);
- return address + fill_size;
- }
- /* 3 mechanisms for relaxing an alignment:
- Align to a power of 2.
- Align so the next fragment's instruction does not cross a word boundary.
- Align the current instruction so that if the next instruction
- were 3 bytes, it would not cross a word boundary.
- We can align with:
- zeros - This is easy; always insert zeros.
- nops - 3-byte and 2-byte instructions
- 2 - 2-byte nop
- 3 - 3-byte nop
- 4 - 2 2-byte nops
- >=5 : 3-byte instruction + fn (n-3)
- widening - widen previous instructions. */
- static offsetT
- get_aligned_diff (fragS *fragP, addressT address, offsetT *max_diff)
- {
- addressT target_address, loop_insn_offset;
- int target_size;
- xtensa_opcode loop_opcode;
- bfd_boolean is_loop;
- int align_power;
- offsetT opt_diff;
- offsetT branch_align;
- fragS *loop_frag;
- gas_assert (fragP->fr_type == rs_machine_dependent);
- switch (fragP->fr_subtype)
- {
- case RELAX_DESIRE_ALIGN:
- target_size = next_frag_format_size (fragP);
- if (target_size == XTENSA_UNDEFINED)
- target_size = 3;
- align_power = branch_align_power (now_seg);
- branch_align = 1 << align_power;
- /* Don't count on the section alignment being as large as the target. */
- if (target_size > branch_align)
- target_size = branch_align;
- opt_diff = get_text_align_fill_size (address, align_power,
- target_size, FALSE, FALSE);
- *max_diff = (opt_diff + branch_align
- - (target_size + ((address + opt_diff) % branch_align)));
- gas_assert (*max_diff >= opt_diff);
- return opt_diff;
- case RELAX_ALIGN_NEXT_OPCODE:
- /* The next non-empty frag after this one holds the LOOP instruction
- that needs to be aligned. The required alignment depends on the
- size of the next non-empty frag after the loop frag, i.e., the
- first instruction in the loop. */
- loop_frag = next_non_empty_frag (fragP);
- target_size = get_loop_align_size (next_frag_format_size (loop_frag));
- loop_insn_offset = 0;
- is_loop = next_frag_opcode_is_loop (fragP, &loop_opcode);
- gas_assert (is_loop);
- /* If the loop has been expanded then the LOOP instruction
- could be at an offset from this fragment. */
- if (loop_frag->tc_frag_data.slot_subtypes[0] != RELAX_IMMED)
- loop_insn_offset = get_expanded_loop_offset (loop_opcode);
- /* In an ideal world, which is what we are shooting for here,
- we wouldn't need to use any NOPs immediately prior to the
- LOOP instruction. If this approach fails, relax_frag_loop_align
- will call get_noop_aligned_address. */
- target_address =
- address + loop_insn_offset + xg_get_single_size (loop_opcode);
- align_power = get_text_align_power (target_size);
- opt_diff = get_text_align_fill_size (target_address, align_power,
- target_size, FALSE, FALSE);
- *max_diff = xtensa_fetch_width
- - ((target_address + opt_diff) % xtensa_fetch_width)
- - target_size + opt_diff;
- gas_assert (*max_diff >= opt_diff);
- return opt_diff;
- default:
- break;
- }
- gas_assert (0);
- return 0;
- }
- /* md_relax_frag Hook and Helper Functions. */
- static long relax_frag_loop_align (fragS *, long);
- static long relax_frag_for_align (fragS *, long);
- static long relax_frag_immed
- (segT, fragS *, long, int, xtensa_format, int, int *, bfd_boolean);
- typedef struct cached_fixup cached_fixupS;
- struct cached_fixup
- {
- int addr;
- int target;
- int delta;
- fixS *fixP;
- };
- typedef struct fixup_cache fixup_cacheS;
- struct fixup_cache
- {
- cached_fixupS *fixups;
- unsigned n_fixups;
- unsigned n_max;
- segT seg;
- fragS *first_frag;
- };
- static int fixup_order (const void *a, const void *b)
- {
- const cached_fixupS *pa = a;
- const cached_fixupS *pb = b;
- if (pa->addr == pb->addr)
- {
- if (pa->target == pb->target)
- {
- if (pa->fixP->fx_r_type == pb->fixP->fx_r_type)
- return 0;
- return pa->fixP->fx_r_type < pb->fixP->fx_r_type ? -1 : 1;
- }
- return pa->target - pb->target;
- }
- return pa->addr - pb->addr;
- }
- static bfd_boolean xtensa_make_cached_fixup (cached_fixupS *o, fixS *fixP)
- {
- xtensa_isa isa = xtensa_default_isa;
- int addr = fixP->fx_frag->fr_address;
- int target;
- int delta;
- symbolS *s = fixP->fx_addsy;
- int slot;
- xtensa_format fmt;
- xtensa_opcode opcode;
- if (fixP->fx_r_type < BFD_RELOC_XTENSA_SLOT0_OP ||
- fixP->fx_r_type > BFD_RELOC_XTENSA_SLOT14_OP)
- return FALSE;
- target = S_GET_VALUE (s);
- delta = target - addr;
- if (abs(delta) < J_RANGE / 2)
- return FALSE;
- xtensa_insnbuf_from_chars (isa, trampoline_buf,
- (unsigned char *) fixP->fx_frag->fr_literal +
- fixP->fx_where, 0);
- fmt = xtensa_format_decode (isa, trampoline_buf);
- gas_assert (fmt != XTENSA_UNDEFINED);
- slot = fixP->tc_fix_data.slot;
- xtensa_format_get_slot (isa, fmt, slot, trampoline_buf, trampoline_slotbuf);
- opcode = xtensa_opcode_decode (isa, fmt, slot, trampoline_slotbuf);
- if (opcode != xtensa_j_opcode)
- return FALSE;
- o->addr = addr;
- o->target = target;
- o->delta = delta;
- o->fixP = fixP;
- return TRUE;
- }
- static void xtensa_realloc_fixup_cache (fixup_cacheS *cache, unsigned add)
- {
- if (cache->n_fixups + add > cache->n_max)
- {
- cache->n_max = (cache->n_fixups + add) * 2;
- cache->fixups = xrealloc (cache->fixups,
- sizeof (*cache->fixups) * cache->n_max);
- }
- }
- static void xtensa_cache_relaxable_fixups (fixup_cacheS *cache,
- segment_info_type *seginfo)
- {
- fixS *fixP;
- cache->n_fixups = 0;
- for (fixP = seginfo->fix_root; fixP ; fixP = fixP->fx_next)
- {
- xtensa_realloc_fixup_cache (cache, 1);
- if (xtensa_make_cached_fixup (cache->fixups + cache->n_fixups, fixP))
- ++cache->n_fixups;
- }
- qsort (cache->fixups, cache->n_fixups, sizeof (*cache->fixups), fixup_order);
- }
- static unsigned xtensa_find_first_cached_fixup (const fixup_cacheS *cache,
- int addr)
- {
- unsigned a = 0;
- unsigned b = cache->n_fixups;
- while (b - a > 1)
- {
- unsigned c = (a + b) / 2;
- if (cache->fixups[c].addr < addr)
- a = c;
- else
- b = c;
- }
- return a;
- }
- static void xtensa_delete_cached_fixup (fixup_cacheS *cache, unsigned i)
- {
- memmove (cache->fixups + i, cache->fixups + i + 1,
- (cache->n_fixups - i - 1) * sizeof (*cache->fixups));
- --cache->n_fixups;
- }
- static bfd_boolean xtensa_add_cached_fixup (fixup_cacheS *cache, fixS *fixP)
- {
- cached_fixupS o;
- unsigned i;
- if (!xtensa_make_cached_fixup (&o, fixP))
- return FALSE;
- xtensa_realloc_fixup_cache (cache, 1);
- i = xtensa_find_first_cached_fixup (cache, o.addr);
- if (i < cache->n_fixups)
- {
- ++i;
- memmove (cache->fixups + i + 1, cache->fixups + i,
- (cache->n_fixups - i) * sizeof (*cache->fixups));
- }
- cache->fixups[i] = o;
- ++cache->n_fixups;
- return TRUE;
- }
- /* Return the number of bytes added to this fragment, given that the
- input has been stretched already by "stretch". */
- long
- xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
- {
- xtensa_isa isa = xtensa_default_isa;
- int unreported = fragP->tc_frag_data.unreported_expansion;
- long new_stretch = 0;
- char *file_name;
- unsigned line;
- int lit_size;
- static xtensa_insnbuf vbuf = NULL;
- int slot, num_slots;
- xtensa_format fmt;
- as_where (&file_name, &line);
- new_logical_line (fragP->fr_file, fragP->fr_line);
- fragP->tc_frag_data.unreported_expansion = 0;
- switch (fragP->fr_subtype)
- {
- case RELAX_ALIGN_NEXT_OPCODE:
- /* Always convert. */
- if (fragP->tc_frag_data.relax_seen)
- new_stretch = relax_frag_loop_align (fragP, stretch);
- break;
- case RELAX_LOOP_END:
- /* Do nothing. */
- break;
- case RELAX_LOOP_END_ADD_NOP:
- /* Add a NOP and switch to .fill 0. */
- new_stretch = relax_frag_add_nop (fragP);
- frag_wane (fragP);
- break;
- case RELAX_DESIRE_ALIGN:
- /* Do nothing. The narrowing before this frag will either align
- it or not. */
- break;
- case RELAX_LITERAL:
- case RELAX_LITERAL_FINAL:
- return 0;
- case RELAX_LITERAL_NR:
- lit_size = 4;
- fragP->fr_subtype = RELAX_LITERAL_FINAL;
- gas_assert (unreported == lit_size);
- memset (&fragP->fr_literal[fragP->fr_fix], 0, 4);
- fragP->fr_var -= lit_size;
- fragP->fr_fix += lit_size;
- new_stretch = 4;
- break;
- case RELAX_SLOTS:
- if (vbuf == NULL)
- vbuf = xtensa_insnbuf_alloc (isa);
- xtensa_insnbuf_from_chars
- (isa, vbuf, (unsigned char *) fragP->fr_opcode, 0);
- fmt = xtensa_format_decode (isa, vbuf);
- num_slots = xtensa_format_num_slots (isa, fmt);
- for (slot = 0; slot < num_slots; slot++)
- {
- switch (fragP->tc_frag_data.slot_subtypes[slot])
- {
- case RELAX_NARROW:
- if (fragP->tc_frag_data.relax_seen)
- new_stretch += relax_frag_for_align (fragP, stretch);
- break;
- case RELAX_IMMED:
- case RELAX_IMMED_STEP1:
- case RELAX_IMMED_STEP2:
- case RELAX_IMMED_STEP3:
- /* Place the immediate. */
- new_stretch += relax_frag_immed
- (now_seg, fragP, stretch,
- fragP->tc_frag_data.slot_subtypes[slot] - RELAX_IMMED,
- fmt, slot, stretched_p, FALSE);
- break;
- default:
- /* This is OK; see the note in xg_assemble_vliw_tokens. */
- break;
- }
- }
- break;
- case RELAX_LITERAL_POOL_BEGIN:
- if (fragP->fr_var != 0)
- {
- /* We have a converted "candidate" literal pool;
- assemble a jump around it. */
- TInsn insn;
- if (!litpool_slotbuf)
- {
- litpool_buf = xtensa_insnbuf_alloc (isa);
- litpool_slotbuf = xtensa_insnbuf_alloc (isa);
- }
- new_stretch += 3;
- fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
- fragP->tc_frag_data.is_insn = TRUE;
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
- fragP->fr_fix);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
- xtensa_insnbuf_to_chars (isa, litpool_buf,
- (unsigned char *)fragP->fr_literal +
- fragP->fr_fix, 3);
- fragP->fr_fix += 3;
- fragP->fr_var -= 3;
- /* Add a fix-up. */
- fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
- BFD_RELOC_XTENSA_SLOT0_OP);
- }
- break;
- case RELAX_LITERAL_POOL_END:
- case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
- case RELAX_MAYBE_UNREACHABLE:
- case RELAX_MAYBE_DESIRE_ALIGN:
- /* No relaxation required. */
- break;
- case RELAX_FILL_NOP:
- case RELAX_UNREACHABLE:
- if (fragP->tc_frag_data.relax_seen)
- new_stretch += relax_frag_for_align (fragP, stretch);
- break;
- case RELAX_TRAMPOLINE:
- if (fragP->tc_frag_data.relax_seen)
- {
- static fixup_cacheS fixup_cache;
- segment_info_type *seginfo = seg_info (now_seg);
- int trampaddr = fragP->fr_address + fragP->fr_fix;
- int searchaddr = trampaddr < J_RANGE ? 0 : trampaddr - J_RANGE;
- unsigned i;
- if (now_seg != fixup_cache.seg ||
- fragP == fixup_cache.first_frag ||
- fixup_cache.first_frag == NULL)
- {
- xtensa_cache_relaxable_fixups (&fixup_cache, seginfo);
- fixup_cache.seg = now_seg;
- fixup_cache.first_frag = fragP;
- }
- /* Scan for jumps that will not reach. */
- for (i = xtensa_find_first_cached_fixup (&fixup_cache, searchaddr);
- i < fixup_cache.n_fixups; ++i)
- {
- fixS *fixP = fixup_cache.fixups[i].fixP;
- int target = fixup_cache.fixups[i].target;
- int addr = fixup_cache.fixups[i].addr;
- int delta = fixup_cache.fixups[i].delta + stretch;
- trampaddr = fragP->fr_address + fragP->fr_fix;
- if (addr + J_RANGE < trampaddr)
- continue;
- if (addr > trampaddr + J_RANGE)
- break;
- if (abs (delta) < J_RANGE)
- continue;
- slot = fixP->tc_fix_data.slot;
- if (delta > J_RANGE || delta < -1 * J_RANGE)
- { /* Found an out-of-range jump; scan the list of trampolines for the best match. */
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- struct trampoline_frag *prev = &ts->trampoline_list;
- int lower = (target < addr) ? target : addr;
- int upper = (target > addr) ? target : addr;
- int midpoint = lower + (upper - lower) / 2;
- if ((upper - lower) > 2 * J_RANGE)
- {
- /* One trampoline won't suffice; we need multiple jumps.
- Jump to the trampoline that's farthest, but still in
- range relative to the original "j" instruction. */
- for ( ; tf; prev = tf, tf = tf->next )
- {
- int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0 ;
- if (addr == lower)
- {
- /* Forward jump. */
- if (this_addr - addr < J_RANGE)
- break;
- }
- else
- {
- /* Backward jump. */
- if (next_addr == 0 || addr - next_addr > J_RANGE)
- break;
- }
- }
- }
- else
- {
- struct trampoline_frag *best_tf = NULL;
- int best_delta = 0;
- for ( ; tf; prev = tf, tf = tf->next )
- {
- int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- int this_delta = abs (this_addr - midpoint);
- if (!best_tf || this_delta < best_delta)
- {
- best_tf = tf;
- best_delta = this_delta;
- }
- }
- tf = best_tf;
- }
- if (tf->fragP == fragP)
- {
- if (abs (addr - trampaddr) < J_RANGE)
- { /* The trampoline is in range of original; fix it! */
- fixS *newfixP;
- int offset;
- TInsn insn;
- symbolS *lsym;
- fragS *fP; /* The out-of-range jump. */
- new_stretch += init_trampoline_frag (tf);
- offset = fragP->fr_fix; /* Where to assemble the j insn. */
- lsym = fragP->fr_symbol;
- fP = fixP->fx_frag;
- /* Assemble a jump to the target label here. */
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], lsym, offset);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fragP->fr_literal + offset, 3);
- fragP->fr_fix += 3;
- fragP->fr_var -= 3;
- /* Add a fix-up for the original j insn. */
- newfixP = fix_new (fP, fixP->fx_where, fixP->fx_size, lsym, fragP->fr_fix - 3, TRUE, fixP->fx_r_type);
- newfixP->fx_no_overflow = 1;
- newfixP->tc_fix_data.X_add_symbol = lsym;
- newfixP->tc_fix_data.X_add_number = offset;
- newfixP->tc_fix_data.slot = slot;
- xtensa_delete_cached_fixup (&fixup_cache, i);
- xtensa_add_cached_fixup (&fixup_cache, newfixP);
- /* Move the fix-up from the original j insn to this one. */
- fixP->fx_frag = fragP;
- fixP->fx_where = fragP->fr_fix - 3;
- fixP->tc_fix_data.slot = 0;
- xtensa_add_cached_fixup (&fixup_cache, fixP);
- /* re-do current fixup */
- --i;
- /* Adjust the jump around this trampoline (if present). */
- if (tf->fixP != NULL)
- {
- tf->fixP->fx_offset += 3;
- }
- new_stretch += 3;
- fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
- /* Do we have room for more? */
- if (fragP->fr_var < 3)
- { /* No, convert to fill. */
- frag_wane (fragP);
- fragP->fr_subtype = 0;
- /* Remove from the trampoline_list. */
- prev->next = tf->next;
- if (fragP == fixup_cache.first_frag)
- fixup_cache.first_frag = NULL;
- break;
- }
- }
- }
- }
- }
- }
- break;
- default:
- as_bad (_("bad relaxation state"));
- }
- /* Tell gas we need another relaxation pass. */
- if (! fragP->tc_frag_data.relax_seen)
- {
- fragP->tc_frag_data.relax_seen = TRUE;
- *stretched_p = 1;
- }
- new_logical_line (file_name, line);
- return new_stretch;
- }
- static long
- relax_frag_loop_align (fragS *fragP, long stretch)
- {
- addressT old_address, old_next_address, old_size;
- addressT new_address, new_next_address, new_size;
- addressT growth;
- /* All the frags with relax_frag_for_alignment prior to this one in the
- section have been done, hopefully eliminating the need for a NOP here.
- But, this will put it in if necessary. */
- /* Calculate the old address of this fragment and the next fragment. */
- old_address = fragP->fr_address - stretch;
- old_next_address = (fragP->fr_address - stretch + fragP->fr_fix +
- fragP->tc_frag_data.text_expansion[0]);
- old_size = old_next_address - old_address;
- /* Calculate the new address of this fragment and the next fragment. */
- new_address = fragP->fr_address;
- new_next_address =
- get_noop_aligned_address (fragP, fragP->fr_address + fragP->fr_fix);
- new_size = new_next_address - new_address;
- growth = new_size - old_size;
- /* Fix up the text_expansion field and return the new growth. */
- fragP->tc_frag_data.text_expansion[0] += growth;
- return growth;
- }
- /* Add a NOP instruction. */
- static long
- relax_frag_add_nop (fragS *fragP)
- {
- char *nop_buf = fragP->fr_literal + fragP->fr_fix;
- int length = fragP->tc_frag_data.is_no_density ? 3 : 2;
- assemble_nop (length, nop_buf);
- fragP->tc_frag_data.is_insn = TRUE;
- if (fragP->fr_var < length)
- {
- as_fatal (_("fr_var (%ld) < length (%d)"), (long) fragP->fr_var, length);
- return 0;
- }
- fragP->fr_fix += length;
- fragP->fr_var -= length;
- return length;
- }
- static long future_alignment_required (fragS *, long);
- static long
- relax_frag_for_align (fragS *fragP, long stretch)
- {
- /* Overview of the relaxation procedure for alignment:
- We can widen with NOPs or by widening instructions or by filling
- bytes after jump instructions. Find the opportune places and widen
- them if necessary. */
- long stretch_me;
- long diff;
- gas_assert (fragP->fr_subtype == RELAX_FILL_NOP
- || fragP->fr_subtype == RELAX_UNREACHABLE
- || (fragP->fr_subtype == RELAX_SLOTS
- && fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW));
- stretch_me = future_alignment_required (fragP, stretch);
- diff = stretch_me - fragP->tc_frag_data.text_expansion[0];
- if (diff == 0)
- return 0;
- if (diff < 0)
- {
- /* We expanded on a previous pass. Can we shrink now? */
- long shrink = fragP->tc_frag_data.text_expansion[0] - stretch_me;
- if (shrink <= stretch && stretch > 0)
- {
- fragP->tc_frag_data.text_expansion[0] = stretch_me;
- return -shrink;
- }
- return 0;
- }
- /* Below here, diff > 0. */
- fragP->tc_frag_data.text_expansion[0] = stretch_me;
- return diff;
- }
- /* Return the address of the next frag that should be aligned.
- By "address" we mean the address it _would_ be at if there
- is no action taken to align it between here and the target frag.
- In other words, if no narrows and no fill nops are used between
- here and the frag to align, _even_if_ some of the frags we use
- to align targets have already expanded on a previous relaxation
- pass.
- Also, count each frag that may be used to help align the target.
- Return 0 if there are no frags left in the chain that need to be
- aligned. */
- static addressT
- find_address_of_next_align_frag (fragS **fragPP,
- int *wide_nops,
- int *narrow_nops,
- int *widens,
- bfd_boolean *paddable)
- {
- fragS *fragP = *fragPP;
- addressT address = fragP->fr_address;
- /* Do not reset the counts to 0. */
- while (fragP)
- {
- /* Limit this to a small search. */
- if (*widens >= (int) xtensa_fetch_width)
- {
- *fragPP = fragP;
- return 0;
- }
- address += fragP->fr_fix;
- if (fragP->fr_type == rs_fill)
- address += fragP->fr_offset * fragP->fr_var;
- else if (fragP->fr_type == rs_machine_dependent)
- {
- switch (fragP->fr_subtype)
- {
- case RELAX_UNREACHABLE:
- *paddable = TRUE;
- break;
- case RELAX_FILL_NOP:
- (*wide_nops)++;
- if (!fragP->tc_frag_data.is_no_density)
- (*narrow_nops)++;
- break;
- case RELAX_SLOTS:
- if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
- {
- (*widens)++;
- break;
- }
- address += total_frag_text_expansion (fragP);
- break;
- case RELAX_IMMED:
- address += fragP->tc_frag_data.text_expansion[0];
- break;
- case RELAX_ALIGN_NEXT_OPCODE:
- case RELAX_DESIRE_ALIGN:
- *fragPP = fragP;
- return address;
- case RELAX_MAYBE_UNREACHABLE:
- case RELAX_MAYBE_DESIRE_ALIGN:
- /* Do nothing. */
- break;
- default:
- /* Just punt if we don't know the type. */
- *fragPP = fragP;
- return 0;
- }
- }
- else
- {
- /* Just punt if we don't know the type. */
- *fragPP = fragP;
- return 0;
- }
- fragP = fragP->fr_next;
- }
- *fragPP = fragP;
- return 0;
- }
- static long bytes_to_stretch (fragS *, int, int, int, int);
- static long
- future_alignment_required (fragS *fragP, long stretch ATTRIBUTE_UNUSED)
- {
- fragS *this_frag = fragP;
- long address;
- int num_widens = 0;
- int wide_nops = 0;
- int narrow_nops = 0;
- bfd_boolean paddable = FALSE;
- offsetT local_opt_diff;
- offsetT opt_diff;
- offsetT max_diff;
- int stretch_amount = 0;
- int local_stretch_amount;
- int global_stretch_amount;
- address = find_address_of_next_align_frag
- (&fragP, &wide_nops, &narrow_nops, &num_widens, &paddable);
- if (!address)
- {
- if (this_frag->tc_frag_data.is_aligning_branch)
- this_frag->tc_frag_data.slot_subtypes[0] = RELAX_IMMED;
- else
- frag_wane (this_frag);
- }
- else
- {
- local_opt_diff = get_aligned_diff (fragP, address, &max_diff);
- opt_diff = local_opt_diff;
- gas_assert (opt_diff >= 0);
- gas_assert (max_diff >= opt_diff);
- if (max_diff == 0)
- return 0;
- if (fragP)
- fragP = fragP->fr_next;
- while (fragP && opt_diff < max_diff && address)
- {
- /* We only use these to determine if we can exit early
- because there will be plenty of ways to align future
- align frags. */
- int glob_widens = 0;
- int dnn = 0;
- int dw = 0;
- bfd_boolean glob_pad = 0;
- address = find_address_of_next_align_frag
- (&fragP, &glob_widens, &dnn, &dw, &glob_pad);
- /* If there is a padable portion, then skip. */
- if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
- address = 0;
- if (address)
- {
- offsetT next_m_diff;
- offsetT next_o_diff;
- /* Downrange frags haven't had stretch added to them yet. */
- address += stretch;
- /* The address also includes any text expansion from this
- frag in a previous pass, but we don't want that. */
- address -= this_frag->tc_frag_data.text_expansion[0];
- /* Assume we are going to move at least opt_diff. In
- reality, we might not be able to, but assuming that
- we will helps catch cases where moving opt_diff pushes
- the next target from aligned to unaligned. */
- address += opt_diff;
- next_o_diff = get_aligned_diff (fragP, address, &next_m_diff);
- /* Now cleanup for the adjustments to address. */
- next_o_diff += opt_diff;
- next_m_diff += opt_diff;
- if (next_o_diff <= max_diff && next_o_diff > opt_diff)
- opt_diff = next_o_diff;
- if (next_m_diff < max_diff)
- max_diff = next_m_diff;
- fragP = fragP->fr_next;
- }
- }
- /* If there are enough wideners in between, do it. */
- if (paddable)
- {
- if (this_frag->fr_subtype == RELAX_UNREACHABLE)
- {
- gas_assert (opt_diff <= (signed) xtensa_fetch_width);
- return opt_diff;
- }
- return 0;
- }
- local_stretch_amount
- = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
- num_widens, local_opt_diff);
- global_stretch_amount
- = bytes_to_stretch (this_frag, wide_nops, narrow_nops,
- num_widens, opt_diff);
- /* If the condition below is true, then the frag couldn't
- stretch the correct amount for the global case, so we just
- optimize locally. We'll rely on the subsequent frags to get
- the correct alignment in the global case. */
- if (global_stretch_amount < local_stretch_amount)
- stretch_amount = local_stretch_amount;
- else
- stretch_amount = global_stretch_amount;
- if (this_frag->fr_subtype == RELAX_SLOTS
- && this_frag->tc_frag_data.slot_subtypes[0] == RELAX_NARROW)
- gas_assert (stretch_amount <= 1);
- else if (this_frag->fr_subtype == RELAX_FILL_NOP)
- {
- if (this_frag->tc_frag_data.is_no_density)
- gas_assert (stretch_amount == 3 || stretch_amount == 0);
- else
- gas_assert (stretch_amount <= 3);
- }
- }
- return stretch_amount;
- }
- /* The idea: widen everything you can to get a target or loop aligned,
- then start using NOPs.
- wide_nops = the number of wide NOPs available for aligning
- narrow_nops = the number of narrow NOPs available for aligning
- (a subset of wide_nops)
- widens = the number of narrow instructions that should be widened
- */
- static long
- bytes_to_stretch (fragS *this_frag,
- int wide_nops,
- int narrow_nops,
- int num_widens,
- int desired_diff)
- {
- int nops_needed;
- int nop_bytes;
- int extra_bytes;
- int bytes_short = desired_diff - num_widens;
- gas_assert (desired_diff >= 0
- && desired_diff < (signed) xtensa_fetch_width);
- if (desired_diff == 0)
- return 0;
- gas_assert (wide_nops > 0 || num_widens > 0);
- /* Always prefer widening to NOP-filling. */
- if (bytes_short < 0)
- {
- /* There are enough RELAX_NARROW frags after this one
- to align the target without widening this frag in any way. */
- return 0;
- }
- if (bytes_short == 0)
- {
- /* Widen every narrow between here and the align target
- and the align target will be properly aligned. */
- if (this_frag->fr_subtype == RELAX_FILL_NOP)
- return 0;
- else
- return 1;
- }
- /* From here we will need at least one NOP to get an alignment.
- However, we may not be able to align at all, in which case,
- don't widen. */
- nops_needed = desired_diff / 3;
- /* If there aren't enough nops, don't widen. */
- if (nops_needed > wide_nops)
- return 0;
- /* First try it with all wide nops. */
- nop_bytes = nops_needed * 3;
- extra_bytes = desired_diff - nop_bytes;
- if (nop_bytes + num_widens >= desired_diff)
- {
- if (this_frag->fr_subtype == RELAX_FILL_NOP)
- return 3;
- else if (num_widens == extra_bytes)
- return 1;
- return 0;
- }
- /* Add a narrow nop. */
- nops_needed++;
- nop_bytes += 2;
- extra_bytes -= 2;
- if (narrow_nops == 0 || nops_needed > wide_nops)
- return 0;
- if (nop_bytes + num_widens >= desired_diff && extra_bytes >= 0)
- {
- if (this_frag->fr_subtype == RELAX_FILL_NOP)
- return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
- else if (num_widens == extra_bytes)
- return 1;
- return 0;
- }
- /* Replace a wide nop with a narrow nop--we can get here if
- extra_bytes was negative in the previous conditional. */
- if (narrow_nops == 1)
- return 0;
- nop_bytes--;
- extra_bytes++;
- if (nop_bytes + num_widens >= desired_diff)
- {
- if (this_frag->fr_subtype == RELAX_FILL_NOP)
- return !this_frag->tc_frag_data.is_no_density ? 2 : 3;
- else if (num_widens == extra_bytes)
- return 1;
- return 0;
- }
- /* If we can't satisfy any of the above cases, then we can't align
- using padding or fill nops. */
- return 0;
- }
- static struct trampoline_frag *
- search_trampolines (TInsn *tinsn, fragS *fragP, bfd_boolean unreachable_only)
- {
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = (ts) ? ts->trampoline_list.next : NULL;
- struct trampoline_frag *best_tf = NULL;
- int best_delta = 0;
- int best_addr = 0;
- symbolS *sym = tinsn->tok[0].X_add_symbol;
- offsetT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
- offsetT addr = fragP->fr_address;
- offsetT lower = (addr < target) ? addr : target;
- offsetT upper = (addr > target) ? addr : target;
- int delta = upper - lower;
- offsetT midpoint = lower + delta / 2;
- int this_delta = -1;
- int this_addr = -1;
- if (delta > 2 * J_RANGE)
- {
- /* One trampoline won't do; we need multiple.
- Choose the farthest trampoline that's still in range of the original
- and let a later pass finish the job. */
- for ( ; tf; tf = tf->next)
- {
- int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0;
- this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- if (lower == addr)
- {
- /* Forward jump. */
- if (this_addr - addr < J_RANGE)
- break;
- }
- else
- {
- /* Backward jump. */
- if (next_addr == 0 || addr - next_addr > J_RANGE)
- break;
- }
- }
- if (abs (addr - this_addr) < J_RANGE)
- return tf;
- return NULL;
- }
- for ( ; tf; tf = tf->next)
- {
- this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
- this_delta = abs (this_addr - midpoint);
- if (unreachable_only && tf->needs_jump_around)
- continue;
- if (!best_tf || this_delta < best_delta)
- {
- best_tf = tf;
- best_delta = this_delta;
- best_addr = this_addr;
- }
- }
- if (best_tf &&
- best_delta < J_RANGE &&
- abs(best_addr - lower) < J_RANGE &&
- abs(best_addr - upper) < J_RANGE)
- return best_tf;
- return NULL; /* No suitable trampoline found. */
- }
- static struct trampoline_frag *
- get_best_trampoline (TInsn *tinsn, fragS *fragP)
- {
- struct trampoline_frag *tf = NULL;
- tf = search_trampolines (tinsn, fragP, TRUE); /* Try unreachable first. */
- if (tf == NULL)
- tf = search_trampolines (tinsn, fragP, FALSE); /* Try ones needing a jump-around, too. */
- return tf;
- }
- static void
- check_and_update_trampolines (void)
- {
- struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- struct trampoline_frag *tf = ts->trampoline_list.next;
- struct trampoline_frag *prev = &ts->trampoline_list;
- for ( ; tf; prev = tf, tf = tf->next)
- {
- if (tf->fragP->fr_var < 3)
- {
- frag_wane (tf->fragP);
- prev->next = tf->next;
- tf->fragP = NULL;
- }
- }
- }
- static int
- init_trampoline_frag (struct trampoline_frag *trampP)
- {
- fragS *fp = trampP->fragP;
- int growth = 0;
- if (fp->fr_fix == 0)
- {
- symbolS *lsym;
- char label[10 + 2 * sizeof(fp)];
- sprintf (label, ".L0_TR_%p", fp);
- lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
- fp->fr_symbol = lsym;
- if (trampP->needs_jump_around)
- {
- /* Add a jump around this block of jumps, in case
- control flows into this block. */
- fixS *fixP;
- TInsn insn;
- xtensa_format fmt;
- xtensa_isa isa = xtensa_default_isa;
- fp->tc_frag_data.is_insn = 1;
- /* Assemble a jump insn. */
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], lsym, 3);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fp->fr_literal, 3);
- fp->fr_fix += 3;
- fp->fr_var -= 3;
- growth = 3;
- fixP = fix_new (fp, 0, 3, lsym, 3, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
- trampP->fixP = fixP;
- }
- }
- return growth;
- }
- static int
- add_jump_to_trampoline (struct trampoline_frag *trampP, fragS *origfrag)
- {
- fragS *tramp = trampP->fragP;
- fixS *fixP;
- int offset = tramp->fr_fix; /* Where to assemble the j insn. */
- TInsn insn;
- symbolS *lsym;
- symbolS *tsym;
- int toffset;
- xtensa_format fmt;
- xtensa_isa isa = xtensa_default_isa;
- int growth = 0;
- lsym = tramp->fr_symbol;
- /* Assemble a jump to the target label in the trampoline frag. */
- tsym = origfrag->tc_frag_data.slot_symbols[0];
- toffset = origfrag-> tc_frag_data.slot_offsets[0];
- tinsn_init (&insn);
- insn.insn_type = ITYPE_INSN;
- insn.opcode = xtensa_j_opcode;
- insn.ntok = 1;
- set_expr_symbol_offset (&insn.tok[0], tsym, toffset);
- fmt = xg_get_single_format (xtensa_j_opcode);
- tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
- xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
- xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)tramp->fr_literal + offset, 3);
- tramp->fr_fix += 3;
- tramp->fr_var -= 3;
- growth = 3;
- /* add a fix-up for the trampoline jump. */
- fixP = fix_new (tramp, tramp->fr_fix - 3, 3, tsym, toffset, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
- /* Modify the jump at the start of this trampoline to point past the newly-added jump. */
- fixP = trampP->fixP;
- if (fixP)
- fixP->fx_offset += 3;
- /* Modify the original j to point here. */
- origfrag->tc_frag_data.slot_symbols[0] = lsym;
- origfrag->tc_frag_data.slot_offsets[0] = tramp->fr_fix - 3;
- /* If trampoline is full, remove it from the list. */
- check_and_update_trampolines ();
- return growth;
- }
- static long
- relax_frag_immed (segT segP,
- fragS *fragP,
- long stretch,
- int min_steps,
- xtensa_format fmt,
- int slot,
- int *stretched_p,
- bfd_boolean estimate_only)
- {
- TInsn tinsn;
- int old_size;
- bfd_boolean negatable_branch = FALSE;
- bfd_boolean branch_jmp_to_next = FALSE;
- bfd_boolean from_wide_insn = FALSE;
- xtensa_isa isa = xtensa_default_isa;
- IStack istack;
- offsetT frag_offset;
- int num_steps;
- int num_text_bytes, num_literal_bytes;
- int literal_diff, total_text_diff, this_text_diff;
- gas_assert (fragP->fr_opcode != NULL);
- xg_clear_vinsn (&cur_vinsn);
- vinsn_from_chars (&cur_vinsn, fragP->fr_opcode);
- if (cur_vinsn.num_slots > 1)
- from_wide_insn = TRUE;
- tinsn = cur_vinsn.slots[slot];
- tinsn_immed_from_frag (&tinsn, fragP, slot);
- if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode) == 1)
- return 0;
- if (workaround_b_j_loop_end && ! fragP->tc_frag_data.is_no_transform)
- branch_jmp_to_next = is_branch_jmp_to_next (&tinsn, fragP);
- negatable_branch = (xtensa_opcode_is_branch (isa, tinsn.opcode) == 1);
- old_size = xtensa_format_length (isa, fmt);
- /* Special case: replace a branch to the next instruction with a NOP.
- This is required to work around a hardware bug in T1040.0 and also
- serves as an optimization. */
- if (branch_jmp_to_next
- && ((old_size == 2) || (old_size == 3))
- && !next_frag_is_loop_target (fragP))
- return 0;
- /* Here is the fun stuff: Get the immediate field from this
- instruction. If it fits, we are done. If not, find the next
- instruction sequence that fits. */
- frag_offset = fragP->fr_opcode - fragP->fr_literal;
- istack_init (&istack);
- num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP, frag_offset,
- min_steps, stretch);
- gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
- fragP->tc_frag_data.slot_subtypes[slot] = (int) RELAX_IMMED + num_steps;
- /* Figure out the number of bytes needed. */
- num_literal_bytes = get_num_stack_literal_bytes (&istack);
- literal_diff
- = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
- num_text_bytes = get_num_stack_text_bytes (&istack);
- if (from_wide_insn)
- {
- int first = 0;
- while (istack.insn[first].opcode == XTENSA_UNDEFINED)
- first++;
- num_text_bytes += old_size;
- if (opcode_fits_format_slot (istack.insn[first].opcode, fmt, slot))
- num_text_bytes -= xg_get_single_size (istack.insn[first].opcode);
- else
- {
- /* The first instruction in the relaxed sequence will go after
- the current wide instruction, and thus its symbolic immediates
- might not fit. */
- istack_init (&istack);
- num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP,
- frag_offset + old_size,
- min_steps, stretch + old_size);
- gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
- fragP->tc_frag_data.slot_subtypes[slot]
- = (int) RELAX_IMMED + num_steps;
- num_literal_bytes = get_num_stack_literal_bytes (&istack);
- literal_diff
- = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
- num_text_bytes = get_num_stack_text_bytes (&istack) + old_size;
- }
- }
- total_text_diff = num_text_bytes - old_size;
- this_text_diff = total_text_diff - fragP->tc_frag_data.text_expansion[slot];
- /* It MUST get larger. If not, we could get an infinite loop. */
- gas_assert (num_text_bytes >= 0);
- gas_assert (literal_diff >= 0);
- gas_assert (total_text_diff >= 0);
- fragP->tc_frag_data.text_expansion[slot] = total_text_diff;
- fragP->tc_frag_data.literal_expansion[slot] = num_literal_bytes;
- gas_assert (fragP->tc_frag_data.text_expansion[slot] >= 0);
- gas_assert (fragP->tc_frag_data.literal_expansion[slot] >= 0);
- /* Find the associated expandable literal for this. */
- if (literal_diff != 0)
- {
- fragS *lit_fragP = fragP->tc_frag_data.literal_frags[slot];
- if (lit_fragP)
- {
- gas_assert (literal_diff == 4);
- lit_fragP->tc_frag_data.unreported_expansion += literal_diff;
- /* We expect that the literal section state has NOT been
- modified yet. */
- gas_assert (lit_fragP->fr_type == rs_machine_dependent
- && lit_fragP->fr_subtype == RELAX_LITERAL);
- lit_fragP->fr_subtype = RELAX_LITERAL_NR;
- /* We need to mark this section for another iteration
- of relaxation. */
- (*stretched_p)++;
- }
- }
- if (negatable_branch && istack.ninsn > 1)
- update_next_frag_state (fragP);
- /* If last insn is a jump, and it cannot reach its target, try to find a trampoline. */
- if (istack.ninsn > 2 &&
- istack.insn[istack.ninsn - 1].insn_type == ITYPE_LABEL &&
- istack.insn[istack.ninsn - 2].insn_type == ITYPE_INSN &&
- istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode)
- {
- TInsn *jinsn = &istack.insn[istack.ninsn - 2];
- if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, total_text_diff))
- {
- struct trampoline_frag *tf = get_best_trampoline (jinsn, fragP);
- if (tf)
- {
- this_text_diff += init_trampoline_frag (tf);
- this_text_diff += add_jump_to_trampoline (tf, fragP);
- }
- else
- {
- /* If target symbol is undefined, assume it will reach once linked. */
- expressionS *exp = &istack.insn[istack.ninsn - 2].tok[0];
- if (exp->X_op == O_symbol && S_IS_DEFINED (exp->X_add_symbol))
- {
- as_bad_where (fragP->fr_file, fragP->fr_line,
- _("jump target out of range; no usable trampoline found"));
- }
- }
- }
- }
- return this_text_diff;
- }
- /* md_convert_frag Hook and Helper Functions. */
- static void convert_frag_align_next_opcode (fragS *);
- static void convert_frag_narrow (segT, fragS *, xtensa_format, int);
- static void convert_frag_fill_nop (fragS *);
- static void convert_frag_immed (segT, fragS *, int, xtensa_format, int);
- void
- md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
- {
- static xtensa_insnbuf vbuf = NULL;
- xtensa_isa isa = xtensa_default_isa;
- int slot;
- int num_slots;
- xtensa_format fmt;
- char *file_name;
- unsigned line;
- as_where (&file_name, &line);
- new_logical_line (fragp->fr_file, fragp->fr_line);
- switch (fragp->fr_subtype)
- {
- case RELAX_ALIGN_NEXT_OPCODE:
- /* Always convert. */
- convert_frag_align_next_opcode (fragp);
- break;
- case RELAX_DESIRE_ALIGN:
- /* Do nothing. If not aligned already, too bad. */
- break;
- case RELAX_LITERAL:
- case RELAX_LITERAL_FINAL:
- break;
- case RELAX_SLOTS:
- if (vbuf == NULL)
- vbuf = xtensa_insnbuf_alloc (isa);
- xtensa_insnbuf_from_chars
- (isa, vbuf, (unsigned char *) fragp->fr_opcode, 0);
- fmt = xtensa_format_decode (isa, vbuf);
- num_slots = xtensa_format_num_slots (isa, fmt);
- for (slot = 0; slot < num_slots; slot++)
- {
- switch (fragp->tc_frag_data.slot_subtypes[slot])
- {
- case RELAX_NARROW:
- convert_frag_narrow (sec, fragp, fmt, slot);
- break;
- case RELAX_IMMED:
- case RELAX_IMMED_STEP1:
- case RELAX_IMMED_STEP2:
- case RELAX_IMMED_STEP3:
- /* Place the immediate. */
- convert_frag_immed
- (sec, fragp,
- fragp->tc_frag_data.slot_subtypes[slot] - RELAX_IMMED,
- fmt, slot);
- break;
- default:
- /* This is OK because some slots could have
- relaxations and others have none. */
- break;
- }
- }
- break;
- case RELAX_UNREACHABLE:
- memset (&fragp->fr_literal[fragp->fr_fix], 0, fragp->fr_var);
- fragp->fr_fix += fragp->tc_frag_data.text_expansion[0];
- fragp->fr_var -= fragp->tc_frag_data.text_expansion[0];
- frag_wane (fragp);
- break;
- case RELAX_MAYBE_UNREACHABLE:
- case RELAX_MAYBE_DESIRE_ALIGN:
- frag_wane (fragp);
- break;
- case RELAX_FILL_NOP:
- convert_frag_fill_nop (fragp);
- break;
- case RELAX_LITERAL_NR:
- if (use_literal_section)
- {
- /* This should have been handled during relaxation. When
- relaxing a code segment, literals sometimes need to be
- added to the corresponding literal segment. If that
- literal segment has already been relaxed, then we end up
- in this situation. Marking the literal segments as data
- would make this happen less often (since GAS always relaxes
- code before data), but we could still get into trouble if
- there are instructions in a segment that is not marked as
- containing code. Until we can implement a better solution,
- cheat and adjust the addresses of all the following frags.
- This could break subsequent alignments, but the linker's
- literal coalescing will do that anyway. */
- fragS *f;
- fragp->fr_subtype = RELAX_LITERAL_FINAL;
- gas_assert (fragp->tc_frag_data.unreported_expansion == 4);
- memset (&fragp->fr_literal[fragp->fr_fix], 0, 4);
- fragp->fr_var -= 4;
- fragp->fr_fix += 4;
- for (f = fragp->fr_next; f; f = f->fr_next)
- f->fr_address += 4;
- }
- else
- as_bad (_("invalid relaxation fragment result"));
- break;
- case RELAX_TRAMPOLINE:
- break;
- }
- fragp->fr_var = 0;
- new_logical_line (file_name, line);
- }
- static void
- convert_frag_align_next_opcode (fragS *fragp)
- {
- char *nop_buf; /* Location for Writing. */
- bfd_boolean use_no_density = fragp->tc_frag_data.is_no_density;
- addressT aligned_address;
- offsetT fill_size;
- int nop, nop_count;
- aligned_address = get_noop_aligned_address (fragp, fragp->fr_address +
- fragp->fr_fix);
- fill_size = aligned_address - (fragp->fr_address + fragp->fr_fix);
- nop_count = get_text_align_nop_count (fill_size, use_no_density);
- nop_buf = fragp->fr_literal + fragp->fr_fix;
- for (nop = 0; nop < nop_count; nop++)
- {
- int nop_size;
- nop_size = get_text_align_nth_nop_size (fill_size, nop, use_no_density);
- assemble_nop (nop_size, nop_buf);
- nop_buf += nop_size;
- }
- fragp->fr_fix += fill_size;
- fragp->fr_var -= fill_size;
- }
- static void
- convert_frag_narrow (segT segP, fragS *fragP, xtensa_format fmt, int slot)
- {
- TInsn tinsn, single_target;
- int size, old_size, diff;
- offsetT frag_offset;
- gas_assert (slot == 0);
- tinsn_from_chars (&tinsn, fragP->fr_opcode, 0);
- if (fragP->tc_frag_data.is_aligning_branch == 1)
- {
- gas_assert (fragP->tc_frag_data.text_expansion[0] == 1
- || fragP->tc_frag_data.text_expansion[0] == 0);
- convert_frag_immed (segP, fragP, fragP->tc_frag_data.text_expansion[0],
- fmt, slot);
- return;
- }
- if (fragP->tc_frag_data.text_expansion[0] == 0)
- {
- /* No conversion. */
- fragP->fr_var = 0;
- return;
- }
- gas_assert (fragP->fr_opcode != NULL);
- /* Frags in this relaxation state should only contain
- single instruction bundles. */
- tinsn_immed_from_frag (&tinsn, fragP, 0);
- /* Just convert it to a wide form.... */
- size = 0;
- old_size = xg_get_single_size (tinsn.opcode);
- tinsn_init (&single_target);
- frag_offset = fragP->fr_opcode - fragP->fr_literal;
- if (! xg_is_single_relaxable_insn (&tinsn, &single_target, FALSE))
- {
- as_bad (_("unable to widen instruction"));
- return;
- }
- size = xg_get_single_size (single_target.opcode);
- xg_emit_insn_to_buf (&single_target, fragP->fr_opcode, fragP,
- frag_offset, TRUE);
- diff = size - old_size;
- gas_assert (diff >= 0);
- gas_assert (diff <= fragP->fr_var);
- fragP->fr_var -= diff;
- fragP->fr_fix += diff;
- /* clean it up */
- fragP->fr_var = 0;
- }
- static void
- convert_frag_fill_nop (fragS *fragP)
- {
- char *loc = &fragP->fr_literal[fragP->fr_fix];
- int size = fragP->tc_frag_data.text_expansion[0];
- gas_assert ((unsigned) size == (fragP->fr_next->fr_address
- - fragP->fr_address - fragP->fr_fix));
- if (size == 0)
- {
- /* No conversion. */
- fragP->fr_var = 0;
- return;
- }
- assemble_nop (size, loc);
- fragP->tc_frag_data.is_insn = TRUE;
- fragP->fr_var -= size;
- fragP->fr_fix += size;
- frag_wane (fragP);
- }
- static fixS *fix_new_exp_in_seg
- (segT, subsegT, fragS *, int, int, expressionS *, int,
- bfd_reloc_code_real_type);
- static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *);
- static void
- convert_frag_immed (segT segP,
- fragS *fragP,
- int min_steps,
- xtensa_format fmt,
- int slot)
- {
- char *immed_instr = fragP->fr_opcode;
- TInsn orig_tinsn;
- bfd_boolean expanded = FALSE;
- bfd_boolean branch_jmp_to_next = FALSE;
- char *fr_opcode = fragP->fr_opcode;
- xtensa_isa isa = xtensa_default_isa;
- bfd_boolean from_wide_insn = FALSE;
- int bytes;
- bfd_boolean is_loop;
- gas_assert (fr_opcode != NULL);
- xg_clear_vinsn (&cur_vinsn);
- vinsn_from_chars (&cur_vinsn, fr_opcode);
- if (cur_vinsn.num_slots > 1)
- from_wide_insn = TRUE;
- orig_tinsn = cur_vinsn.slots[slot];
- tinsn_immed_from_frag (&orig_tinsn, fragP, slot);
- is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1;
- if (workaround_b_j_loop_end && ! fragP->tc_frag_data.is_no_transform)
- branch_jmp_to_next = is_branch_jmp_to_next (&orig_tinsn, fragP);
- if (branch_jmp_to_next && !next_frag_is_loop_target (fragP))
- {
- /* Conversion just inserts a NOP and marks the fix as completed. */
- bytes = xtensa_format_length (isa, fmt);
- if (bytes >= 4)
- {
- cur_vinsn.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, cur_vinsn.format, slot);
- cur_vinsn.slots[slot].ntok = 0;
- }
- else
- {
- bytes += fragP->tc_frag_data.text_expansion[0];
- gas_assert (bytes == 2 || bytes == 3);
- build_nop (&cur_vinsn.slots[0], bytes);
- fragP->fr_fix += fragP->tc_frag_data.text_expansion[0];
- }
- vinsn_to_insnbuf (&cur_vinsn, fr_opcode, frag_now, TRUE);
- xtensa_insnbuf_to_chars
- (isa, cur_vinsn.insnbuf, (unsigned char *) fr_opcode, 0);
- fragP->fr_var = 0;
- }
- else
- {
- /* Here is the fun stuff: Get the immediate field from this
- instruction. If it fits, we're done. If not, find the next
- instruction sequence that fits. */
- IStack istack;
- int i;
- symbolS *lit_sym = NULL;
- int total_size = 0;
- int target_offset = 0;
- int old_size;
- int diff;
- symbolS *gen_label = NULL;
- offsetT frag_offset;
- bfd_boolean first = TRUE;
- /* It does not fit. Find something that does and
- convert immediately. */
- frag_offset = fr_opcode - fragP->fr_literal;
- istack_init (&istack);
- xg_assembly_relax (&istack, &orig_tinsn,
- segP, fragP, frag_offset, min_steps, 0);
- old_size = xtensa_format_length (isa, fmt);
- /* Assemble this right inline. */
- /* First, create the mapping from a label name to the REAL label. */
- target_offset = 0;
- for (i = 0; i < istack.ninsn; i++)
- {
- TInsn *tinsn = &istack.insn[i];
- fragS *lit_frag;
- switch (tinsn->insn_type)
- {
- case ITYPE_LITERAL:
- if (lit_sym != NULL)
- as_bad (_("multiple literals in expansion"));
- /* First find the appropriate space in the literal pool. */
- lit_frag = fragP->tc_frag_data.literal_frags[slot];
- if (lit_frag == NULL)
- as_bad (_("no registered fragment for literal"));
- if (tinsn->ntok != 1)
- as_bad (_("number of literal tokens != 1"));
- /* Set the literal symbol and add a fixup. */
- lit_sym = lit_frag->fr_symbol;
- break;
- case ITYPE_LABEL:
- if (align_targets && !is_loop)
- {
- fragS *unreach = fragP->fr_next;
- while (!(unreach->fr_type == rs_machine_dependent
- && (unreach->fr_subtype == RELAX_MAYBE_UNREACHABLE
- || unreach->fr_subtype == RELAX_UNREACHABLE)))
- {
- unreach = unreach->fr_next;
- }
- gas_assert (unreach->fr_type == rs_machine_dependent
- && (unreach->fr_subtype == RELAX_MAYBE_UNREACHABLE
- || unreach->fr_subtype == RELAX_UNREACHABLE));
- target_offset += unreach->tc_frag_data.text_expansion[0];
- }
- gas_assert (gen_label == NULL);
- gen_label = symbol_new (FAKE_LABEL_NAME, now_seg,
- fr_opcode - fragP->fr_literal
- + target_offset, fragP);
- break;
- case ITYPE_INSN:
- if (first && from_wide_insn)
- {
- target_offset += xtensa_format_length (isa, fmt);
- first = FALSE;
- if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
- target_offset += xg_get_single_size (tinsn->opcode);
- }
- else
- target_offset += xg_get_single_size (tinsn->opcode);
- break;
- }
- }
- total_size = 0;
- first = TRUE;
- for (i = 0; i < istack.ninsn; i++)
- {
- TInsn *tinsn = &istack.insn[i];
- fragS *lit_frag;
- int size;
- segT target_seg;
- bfd_reloc_code_real_type reloc_type;
- switch (tinsn->insn_type)
- {
- case ITYPE_LITERAL:
- lit_frag = fragP->tc_frag_data.literal_frags[slot];
- /* Already checked. */
- gas_assert (lit_frag != NULL);
- gas_assert (lit_sym != NULL);
- gas_assert (tinsn->ntok == 1);
- /* Add a fixup. */
- target_seg = S_GET_SEGMENT (lit_sym);
- gas_assert (target_seg);
- reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op, TRUE);
- fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4,
- &tinsn->tok[0], FALSE, reloc_type);
- break;
- case ITYPE_LABEL:
- break;
- case ITYPE_INSN:
- xg_resolve_labels (tinsn, gen_label);
- xg_resolve_literals (tinsn, lit_sym);
- if (from_wide_insn && first)
- {
- first = FALSE;
- if (opcode_fits_format_slot (tinsn->opcode, fmt, slot))
- {
- cur_vinsn.slots[slot] = *tinsn;
- }
- else
- {
- cur_vinsn.slots[slot].opcode =
- xtensa_format_slot_nop_opcode (isa, fmt, slot);
- cur_vinsn.slots[slot].ntok = 0;
- }
- vinsn_to_insnbuf (&cur_vinsn, immed_instr, fragP, TRUE);
- xtensa_insnbuf_to_chars (isa, cur_vinsn.insnbuf,
- (unsigned char *) immed_instr, 0);
- fragP->tc_frag_data.is_insn = TRUE;
- size = xtensa_format_length (isa, fmt);
- if (!opcode_fits_format_slot (tinsn->opcode, fmt, slot))
- {
- xg_emit_insn_to_buf
- (tinsn, immed_instr + size, fragP,
- immed_instr - fragP->fr_literal + size, TRUE);
- size += xg_get_single_size (tinsn->opcode);
- }
- }
- else
- {
- size = xg_get_single_size (tinsn->opcode);
- xg_emit_insn_to_buf (tinsn, immed_instr, fragP,
- immed_instr - fragP->fr_literal, TRUE);
- }
- immed_instr += size;
- total_size += size;
- break;
- }
- }
- diff = total_size - old_size;
- gas_assert (diff >= 0);
- if (diff != 0)
- expanded = TRUE;
- gas_assert (diff <= fragP->fr_var);
- fragP->fr_var -= diff;
- fragP->fr_fix += diff;
- }
- /* Check for undefined immediates in LOOP instructions. */
- if (is_loop)
- {
- symbolS *sym;
- sym = orig_tinsn.tok[1].X_add_symbol;
- if (sym != NULL && !S_IS_DEFINED (sym))
- {
- as_bad (_("unresolved loop target symbol: %s"), S_GET_NAME (sym));
- return;
- }
- sym = orig_tinsn.tok[1].X_op_symbol;
- if (sym != NULL && !S_IS_DEFINED (sym))
- {
- as_bad (_("unresolved loop target symbol: %s"), S_GET_NAME (sym));
- return;
- }
- }
- if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1)
- convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn);
- if (expanded && is_direct_call_opcode (orig_tinsn.opcode))
- {
- /* Add an expansion note on the expanded instruction. */
- fix_new_exp_in_seg (now_seg, 0, fragP, fr_opcode - fragP->fr_literal, 4,
- &orig_tinsn.tok[0], TRUE,
- BFD_RELOC_XTENSA_ASM_EXPAND);
- }
- }
- /* Add a new fix expression into the desired segment. We have to
- switch to that segment to do this. */
- static fixS *
- fix_new_exp_in_seg (segT new_seg,
- subsegT new_subseg,
- fragS *frag,
- int where,
- int size,
- expressionS *exp,
- int pcrel,
- bfd_reloc_code_real_type r_type)
- {
- fixS *new_fix;
- segT seg = now_seg;
- subsegT subseg = now_subseg;
- gas_assert (new_seg != 0);
- subseg_set (new_seg, new_subseg);
- new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
- subseg_set (seg, subseg);
- return new_fix;
- }
- /* Relax a loop instruction so that it can span loop >256 bytes.
- loop as, .L1
- .L0:
- rsr as, LEND
- wsr as, LBEG
- addi as, as, lo8 (label-.L1)
- addmi as, as, mid8 (label-.L1)
- wsr as, LEND
- isync
- rsr as, LCOUNT
- addi as, as, 1
- .L1:
- <<body>>
- label:
- */
- static void
- convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
- {
- TInsn loop_insn;
- TInsn addi_insn;
- TInsn addmi_insn;
- unsigned long target;
- static xtensa_insnbuf insnbuf = NULL;
- unsigned int loop_length, loop_length_hi, loop_length_lo;
- xtensa_isa isa = xtensa_default_isa;
- addressT loop_offset;
- addressT addi_offset = 9;
- addressT addmi_offset = 12;
- fragS *next_fragP;
- int target_count;
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
- /* Get the loop offset. */
- loop_offset = get_expanded_loop_offset (tinsn->opcode);
- /* Validate that there really is a LOOP at the loop_offset. Because
- loops are not bundleable, we can assume that the instruction will be
- in slot 0. */
- tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0);
- tinsn_immed_from_frag (&loop_insn, fragP, 0);
- gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
- addi_offset += loop_offset;
- addmi_offset += loop_offset;
- gas_assert (tinsn->ntok == 2);
- if (tinsn->tok[1].X_op == O_constant)
- target = tinsn->tok[1].X_add_number;
- else if (tinsn->tok[1].X_op == O_symbol)
- {
- /* Find the fragment. */
- symbolS *sym = tinsn->tok[1].X_add_symbol;
- gas_assert (S_GET_SEGMENT (sym) == segP
- || S_GET_SEGMENT (sym) == absolute_section);
- target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number);
- }
- else
- {
- as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op);
- target = 0;
- }
- loop_length = target - (fragP->fr_address + fragP->fr_fix);
- loop_length_hi = loop_length & ~0x0ff;
- loop_length_lo = loop_length & 0x0ff;
- if (loop_length_lo >= 128)
- {
- loop_length_lo -= 256;
- loop_length_hi += 256;
- }
- /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most
- 32512. If the loop is larger than that, then we just fail. */
- if (loop_length_hi > 32512)
- as_bad_where (fragP->fr_file, fragP->fr_line,
- _("loop too long for LOOP instruction"));
- tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0);
- gas_assert (addi_insn.opcode == xtensa_addi_opcode);
- tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
- gas_assert (addmi_insn.opcode == xtensa_addmi_opcode);
- set_expr_const (&addi_insn.tok[2], loop_length_lo);
- tinsn_to_insnbuf (&addi_insn, insnbuf);
- fragP->tc_frag_data.is_insn = TRUE;
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0);
- set_expr_const (&addmi_insn.tok[2], loop_length_hi);
- tinsn_to_insnbuf (&addmi_insn, insnbuf);
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0);
- /* Walk through all of the frags from here to the loop end
- and mark them as no_transform to keep them from being modified
- by the linker. If we ever have a relocation for the
- addi/addmi of the difference of two symbols we can remove this. */
- target_count = 0;
- for (next_fragP = fragP; next_fragP != NULL;
- next_fragP = next_fragP->fr_next)
- {
- next_fragP->tc_frag_data.is_no_transform = TRUE;
- if (next_fragP->tc_frag_data.is_loop_target)
- target_count++;
- if (target_count == 2)
- break;
- }
- }
- /* A map that keeps information on a per-subsegment basis. This is
- maintained during initial assembly, but is invalid once the
- subsegments are smashed together. I.E., it cannot be used during
- the relaxation. */
- typedef struct subseg_map_struct
- {
- /* the key */
- segT seg;
- subsegT subseg;
- /* the data */
- unsigned flags;
- float total_freq; /* fall-through + branch target frequency */
- float target_freq; /* branch target frequency alone */
- struct subseg_map_struct *next;
- } subseg_map;
- static subseg_map *sseg_map = NULL;
- static subseg_map *
- get_subseg_info (segT seg, subsegT subseg)
- {
- subseg_map *subseg_e;
- for (subseg_e = sseg_map; subseg_e; subseg_e = subseg_e->next)
- {
- if (seg == subseg_e->seg && subseg == subseg_e->subseg)
- break;
- }
- return subseg_e;
- }
- static subseg_map *
- add_subseg_info (segT seg, subsegT subseg)
- {
- subseg_map *subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map));
- memset (subseg_e, 0, sizeof (subseg_map));
- subseg_e->seg = seg;
- subseg_e->subseg = subseg;
- subseg_e->flags = 0;
- /* Start off considering every branch target very important. */
- subseg_e->target_freq = 1.0;
- subseg_e->total_freq = 1.0;
- subseg_e->next = sseg_map;
- sseg_map = subseg_e;
- return subseg_e;
- }
- static unsigned
- get_last_insn_flags (segT seg, subsegT subseg)
- {
- subseg_map *subseg_e = get_subseg_info (seg, subseg);
- if (subseg_e)
- return subseg_e->flags;
- return 0;
- }
- static void
- set_last_insn_flags (segT seg,
- subsegT subseg,
- unsigned fl,
- bfd_boolean val)
- {
- subseg_map *subseg_e = get_subseg_info (seg, subseg);
- if (! subseg_e)
- subseg_e = add_subseg_info (seg, subseg);
- if (val)
- subseg_e->flags |= fl;
- else
- subseg_e->flags &= ~fl;
- }
- static float
- get_subseg_total_freq (segT seg, subsegT subseg)
- {
- subseg_map *subseg_e = get_subseg_info (seg, subseg);
- if (subseg_e)
- return subseg_e->total_freq;
- return 1.0;
- }
- static float
- get_subseg_target_freq (segT seg, subsegT subseg)
- {
- subseg_map *subseg_e = get_subseg_info (seg, subseg);
- if (subseg_e)
- return subseg_e->target_freq;
- return 1.0;
- }
- static void
- set_subseg_freq (segT seg, subsegT subseg, float total_f, float target_f)
- {
- subseg_map *subseg_e = get_subseg_info (seg, subseg);
- if (! subseg_e)
- subseg_e = add_subseg_info (seg, subseg);
- subseg_e->total_freq = total_f;
- subseg_e->target_freq = target_f;
- }
- /* Segment Lists and emit_state Stuff. */
- static void
- xtensa_move_seg_list_to_beginning (seg_list *head)
- {
- head = head->next;
- while (head)
- {
- segT literal_section = head->seg;
- /* Move the literal section to the front of the section list. */
- gas_assert (literal_section);
- if (literal_section != stdoutput->sections)
- {
- bfd_section_list_remove (stdoutput, literal_section);
- bfd_section_list_prepend (stdoutput, literal_section);
- }
- head = head->next;
- }
- }
- static void mark_literal_frags (seg_list *);
- static void
- xtensa_move_literals (void)
- {
- seg_list *segment;
- frchainS *frchain_from, *frchain_to;
- fragS *search_frag, *next_frag, *literal_pool, *insert_after;
- fragS **frag_splice;
- emit_state state;
- segT dest_seg;
- fixS *fix, *next_fix, **fix_splice;
- sym_list *lit;
- struct litpool_seg *lps;
- mark_literal_frags (literal_head->next);
- if (use_literal_section)
- return;
- /* Assign addresses (rough estimates) to the potential literal pool locations
- and create new ones if the gaps are too large. */
- for (lps = litpool_seg_list.next; lps; lps = lps->next)
- {
- frchainS *frchP = seg_info (lps->seg)->frchainP;
- struct litpool_frag *lpf = lps->frag_list.next;
- addressT addr = 0;
- for ( ; frchP; frchP = frchP->frch_next)
- {
- fragS *fragP;
- for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (lpf && fragP == lpf->fragP)
- {
- gas_assert(fragP->fr_type == rs_machine_dependent &&
- (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
- fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
- /* Found a litpool location. */
- lpf->addr = addr;
- lpf = lpf->next;
- }
- if (fragP->fr_type == rs_machine_dependent &&
- fragP->fr_subtype == RELAX_SLOTS)
- {
- int slot;
- for (slot = 0; slot < MAX_SLOTS; slot++)
- {
- if (fragP->tc_frag_data.literal_frags[slot])
- {
- /* L32R; point its literal to the nearest litpool
- preferring non-"candidate" positions to avoid
- the jump-around. */
- fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
- struct litpool_frag *lp = lpf->prev;
- if (!lp->fragP)
- {
- break;
- }
- while (lp->fragP->fr_subtype ==
- RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- {
- lp = lp->prev;
- if (lp->fragP == NULL)
- {
- /* End of list; have to bite the bullet.
- Take the nearest. */
- lp = lpf->prev;
- break;
- }
- /* Does it (conservatively) reach? */
- if (addr - lp->addr <= 128 * 1024)
- {
- if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- {
- /* Found a good one. */
- break;
- }
- else if (lp->prev->fragP &&
- addr - lp->prev->addr > 128 * 1024)
- {
- /* This is still a "candidate" but the next one
- will be too far away, so revert to the nearest
- one, convert it and add the jump around. */
- fragS *poolbeg;
- fragS *poolend;
- symbolS *lsym;
- char label[10 + 2 * sizeof (fragS *)];
- lp = lpf->prev;
- poolbeg = lp->fragP;
- lp->priority = 1;
- poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
- poolend = poolbeg->fr_next;
- gas_assert (poolend->fr_type == rs_machine_dependent &&
- poolend->fr_subtype == RELAX_LITERAL_POOL_END);
- /* Create a local symbol pointing to the
- end of the pool. */
- sprintf (label, ".L0_LT_%p", poolbeg);
- lsym = (symbolS *)local_symbol_make (label, lps->seg,
- 0, poolend);
- poolbeg->fr_symbol = lsym;
- /* Rest is done in xtensa_relax_frag. */
- }
- }
- }
- if (! litfrag->tc_frag_data.literal_frag)
- {
- /* Take earliest use of this literal to avoid
- forward refs. */
- litfrag->tc_frag_data.literal_frag = lp->fragP;
- }
- }
- }
- }
- addr += fragP->fr_fix;
- if (fragP->fr_type == rs_fill)
- addr += fragP->fr_offset;
- }
- }
- }
- for (segment = literal_head->next; segment; segment = segment->next)
- {
- /* Keep the literals for .init and .fini in separate sections. */
- if (!strcmp (segment_name (segment->seg), INIT_SECTION_NAME)
- || !strcmp (segment_name (segment->seg), FINI_SECTION_NAME))
- continue;
- frchain_from = seg_info (segment->seg)->frchainP;
- search_frag = frchain_from->frch_root;
- literal_pool = NULL;
- frchain_to = NULL;
- frag_splice = &(frchain_from->frch_root);
- while (search_frag && !search_frag->tc_frag_data.literal_frag)
- {
- gas_assert (search_frag->fr_fix == 0
- || search_frag->fr_type == rs_align);
- search_frag = search_frag->fr_next;
- }
- if (!search_frag)
- {
- search_frag = frchain_from->frch_root;
- as_bad_where (search_frag->fr_file, search_frag->fr_line,
- _("literal pool location required for text-section-literals; specify with .literal_position"));
- continue;
- }
- gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
- == RELAX_LITERAL_POOL_BEGIN);
- xtensa_switch_section_emit_state (&state, segment->seg, 0);
- /* Make sure that all the frags in this series are closed, and
- that there is at least one left over of zero-size. This
- prevents us from making a segment with an frchain without any
- frags in it. */
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- while (search_frag != frag_now)
- {
- next_frag = search_frag->fr_next;
- if (search_frag->tc_frag_data.literal_frag)
- {
- literal_pool = search_frag->tc_frag_data.literal_frag;
- gas_assert (literal_pool->fr_subtype == RELAX_LITERAL_POOL_BEGIN);
- frchain_to = literal_pool->tc_frag_data.lit_frchain;
- gas_assert (frchain_to);
- }
- if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
- {
- /* Skip empty fill frags. */
- *frag_splice = next_frag;
- search_frag = next_frag;
- continue;
- }
- if (search_frag->fr_type == rs_align)
- {
- /* Skip alignment frags, because the pool as a whole will be
- aligned if used, and we don't want to force alignment if the
- pool is unused. */
- *frag_splice = next_frag;
- search_frag = next_frag;
- continue;
- }
- /* First, move the frag out of the literal section and
- to the appropriate place. */
- /* Insert an aligmnent frag at start of pool. */
- if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
- literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
- {
- segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
- emit_state prev_state;
- fragS *prev_frag;
- fragS *align_frag;
- xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
- prev_frag = frag_now;
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- align_frag = frag_now;
- frag_align (2, 0, 0);
- /* Splice it into the right place. */
- prev_frag->fr_next = align_frag->fr_next;
- align_frag->fr_next = literal_pool->fr_next;
- literal_pool->fr_next = align_frag;
- /* Insert after this one. */
- literal_pool->tc_frag_data.literal_frag = align_frag;
- xtensa_restore_emit_state (&prev_state);
- }
- insert_after = literal_pool->tc_frag_data.literal_frag;
- dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
- /* Skip align frag. */
- if (insert_after->fr_next->fr_type == rs_align)
- {
- insert_after = insert_after->fr_next;
- }
- *frag_splice = next_frag;
- search_frag->fr_next = insert_after->fr_next;
- insert_after->fr_next = search_frag;
- search_frag->tc_frag_data.lit_seg = dest_seg;
- literal_pool->tc_frag_data.literal_frag = search_frag;
- /* Now move any fixups associated with this frag to the
- right section. */
- fix = frchain_from->fix_root;
- fix_splice = &(frchain_from->fix_root);
- while (fix)
- {
- next_fix = fix->fx_next;
- if (fix->fx_frag == search_frag)
- {
- *fix_splice = next_fix;
- fix->fx_next = frchain_to->fix_root;
- frchain_to->fix_root = fix;
- if (frchain_to->fix_tail == NULL)
- frchain_to->fix_tail = fix;
- }
- else
- fix_splice = &(fix->fx_next);
- fix = next_fix;
- }
- search_frag = next_frag;
- }
- if (frchain_from->fix_root != NULL)
- {
- frchain_from = seg_info (segment->seg)->frchainP;
- as_warn (_("fixes not all moved from %s"), segment->seg->name);
- gas_assert (frchain_from->fix_root == NULL);
- }
- frchain_from->fix_tail = NULL;
- xtensa_restore_emit_state (&state);
- }
- /* Now fix up the SEGMENT value for all the literal symbols. */
- for (lit = literal_syms; lit; lit = lit->next)
- {
- symbolS *lit_sym = lit->sym;
- segT dseg = symbol_get_frag (lit_sym)->tc_frag_data.lit_seg;
- if (dseg)
- S_SET_SEGMENT (lit_sym, dseg);
- }
- }
- /* Walk over all the frags for segments in a list and mark them as
- containing literals. As clunky as this is, we can't rely on frag_var
- and frag_variant to get called in all situations. */
- static void
- mark_literal_frags (seg_list *segment)
- {
- frchainS *frchain_from;
- fragS *search_frag;
- while (segment)
- {
- frchain_from = seg_info (segment->seg)->frchainP;
- search_frag = frchain_from->frch_root;
- while (search_frag)
- {
- search_frag->tc_frag_data.is_literal = TRUE;
- search_frag = search_frag->fr_next;
- }
- segment = segment->next;
- }
- }
- static void
- xtensa_reorder_seg_list (seg_list *head, segT after)
- {
- /* Move all of the sections in the section list to come
- after "after" in the gnu segment list. */
- head = head->next;
- while (head)
- {
- segT literal_section = head->seg;
- /* Move the literal section after "after". */
- gas_assert (literal_section);
- if (literal_section != after)
- {
- bfd_section_list_remove (stdoutput, literal_section);
- bfd_section_list_insert_after (stdoutput, after, literal_section);
- }
- head = head->next;
- }
- }
- /* Push all the literal segments to the end of the gnu list. */
- static void
- xtensa_reorder_segments (void)
- {
- segT sec;
- segT last_sec = 0;
- int old_count = 0;
- int new_count = 0;
- for (sec = stdoutput->sections; sec != NULL; sec = sec->next)
- {
- last_sec = sec;
- old_count++;
- }
- /* Now that we have the last section, push all the literal
- sections to the end. */
- xtensa_reorder_seg_list (literal_head, last_sec);
- /* Now perform the final error check. */
- for (sec = stdoutput->sections; sec != NULL; sec = sec->next)
- new_count++;
- gas_assert (new_count == old_count);
- }
- /* Change the emit state (seg, subseg, and frag related stuff) to the
- correct location. Return a emit_state which can be passed to
- xtensa_restore_emit_state to return to current fragment. */
- static void
- xtensa_switch_to_literal_fragment (emit_state *result)
- {
- if (directive_state[directive_absolute_literals])
- {
- segT lit4_seg = cache_literal_section (TRUE);
- xtensa_switch_section_emit_state (result, lit4_seg, 0);
- }
- else
- xtensa_switch_to_non_abs_literal_fragment (result);
- /* Do a 4-byte align here. */
- frag_align (2, 0, 0);
- record_alignment (now_seg, 2);
- }
- static void
- xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
- {
- static bfd_boolean recursive = FALSE;
- fragS *pool_location = get_literal_pool_location (now_seg);
- segT lit_seg;
- bfd_boolean is_init =
- (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
- bfd_boolean is_fini =
- (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
- if (pool_location == NULL
- && !use_literal_section
- && !recursive
- && !is_init && ! is_fini)
- {
- if (!auto_litpools)
- {
- as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
- }
- /* When we mark a literal pool location, we want to put a frag in
- the literal pool that points to it. But to do that, we want to
- switch_to_literal_fragment. But literal sections don't have
- literal pools, so their location is always null, so we would
- recurse forever. This is kind of hacky, but it works. */
- recursive = TRUE;
- xtensa_mark_literal_pool_location ();
- recursive = FALSE;
- }
- lit_seg = cache_literal_section (FALSE);
- xtensa_switch_section_emit_state (result, lit_seg, 0);
- if (!use_literal_section
- && !is_init && !is_fini
- && get_literal_pool_location (now_seg) != pool_location)
- {
- /* Close whatever frag is there. */
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.literal_frag = pool_location;
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- }
- }
- /* Call this function before emitting data into the literal section.
- This is a helper function for xtensa_switch_to_literal_fragment.
- This is similar to a .section new_now_seg subseg. */
- static void
- xtensa_switch_section_emit_state (emit_state *state,
- segT new_now_seg,
- subsegT new_now_subseg)
- {
- state->name = now_seg->name;
- state->now_seg = now_seg;
- state->now_subseg = now_subseg;
- state->generating_literals = generating_literals;
- generating_literals++;
- subseg_set (new_now_seg, new_now_subseg);
- }
- /* Use to restore the emitting into the normal place. */
- static void
- xtensa_restore_emit_state (emit_state *state)
- {
- generating_literals = state->generating_literals;
- subseg_set (state->now_seg, state->now_subseg);
- }
- /* Predicate function used to look up a section in a particular group. */
- static bfd_boolean
- match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
- {
- const char *gname = inf;
- const char *group_name = elf_group_name (sec);
- return (group_name == gname
- || (group_name != NULL
- && gname != NULL
- && strcmp (group_name, gname) == 0));
- }
- /* Get the literal section to be used for the current text section.
- The result may be cached in the default_lit_sections structure. */
- static segT
- cache_literal_section (bfd_boolean use_abs_literals)
- {
- const char *text_name, *group_name = 0;
- char *base_name, *name, *suffix;
- segT *pcached;
- segT seg, current_section;
- int current_subsec;
- bfd_boolean linkonce = FALSE;
- /* Save the current section/subsection. */
- current_section = now_seg;
- current_subsec = now_subseg;
- /* Clear the cached values if they are no longer valid. */
- if (now_seg != default_lit_sections.current_text_seg)
- {
- default_lit_sections.current_text_seg = now_seg;
- default_lit_sections.lit_seg = NULL;
- default_lit_sections.lit4_seg = NULL;
- }
- /* Check if the literal section is already cached. */
- if (use_abs_literals)
- pcached = &default_lit_sections.lit4_seg;
- else
- pcached = &default_lit_sections.lit_seg;
- if (*pcached)
- return *pcached;
- text_name = default_lit_sections.lit_prefix;
- if (! text_name || ! *text_name)
- {
- text_name = segment_name (current_section);
- group_name = elf_group_name (current_section);
- linkonce = (current_section->flags & SEC_LINK_ONCE) != 0;
- }
- base_name = use_abs_literals ? ".lit4" : ".literal";
- if (group_name)
- {
- name = xmalloc (strlen (base_name) + strlen (group_name) + 2);
- sprintf (name, "%s.%s", base_name, group_name);
- }
- else if (strncmp (text_name, ".gnu.linkonce.", linkonce_len) == 0)
- {
- suffix = strchr (text_name + linkonce_len, '.');
- name = xmalloc (linkonce_len + strlen (base_name) + 1
- + (suffix ? strlen (suffix) : 0));
- strcpy (name, ".gnu.linkonce");
- strcat (name, base_name);
- if (suffix)
- strcat (name, suffix);
- linkonce = TRUE;
- }
- else
- {
- /* If the section name begins or ends with ".text", then replace
- that portion instead of appending an additional suffix. */
- size_t len = strlen (text_name);
- if (len >= 5
- && (strcmp (text_name + len - 5, ".text") == 0
- || strncmp (text_name, ".text", 5) == 0))
- len -= 5;
- name = xmalloc (len + strlen (base_name) + 1);
- if (strncmp (text_name, ".text", 5) == 0)
- {
- strcpy (name, base_name);
- strcat (name, text_name + 5);
- }
- else
- {
- strcpy (name, text_name);
- strcpy (name + len, base_name);
- }
- }
- /* Canonicalize section names to allow renaming literal sections.
- The group name, if any, came from the current text section and
- has already been canonicalized. */
- name = tc_canonicalize_symbol_name (name);
- seg = bfd_get_section_by_name_if (stdoutput, name, match_section_group,
- (void *) group_name);
- if (! seg)
- {
- flagword flags;
- seg = subseg_force_new (name, 0);
- if (! use_abs_literals)
- {
- /* Add the newly created literal segment to the list. */
- seg_list *n = (seg_list *) xmalloc (sizeof (seg_list));
- n->seg = seg;
- n->next = literal_head->next;
- literal_head->next = n;
- }
- flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_ALLOC | SEC_LOAD
- | (linkonce ? (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD) : 0)
- | (use_abs_literals ? SEC_DATA : SEC_CODE));
- elf_group_name (seg) = group_name;
- bfd_set_section_flags (stdoutput, seg, flags);
- bfd_set_section_alignment (stdoutput, seg, 2);
- }
- *pcached = seg;
- subseg_set (current_section, current_subsec);
- return seg;
- }
- /* Property Tables Stuff. */
- #define XTENSA_INSN_SEC_NAME ".xt.insn"
- #define XTENSA_LIT_SEC_NAME ".xt.lit"
- #define XTENSA_PROP_SEC_NAME ".xt.prop"
- typedef bfd_boolean (*frag_predicate) (const fragS *);
- typedef void (*frag_flags_fn) (const fragS *, frag_flags *);
- static bfd_boolean get_frag_is_literal (const fragS *);
- static void xtensa_create_property_segments
- (frag_predicate, frag_predicate, const char *, xt_section_type);
- static void xtensa_create_xproperty_segments
- (frag_flags_fn, const char *, xt_section_type);
- static bfd_boolean exclude_section_from_property_tables (segT);
- static bfd_boolean section_has_property (segT, frag_predicate);
- static bfd_boolean section_has_xproperty (segT, frag_flags_fn);
- static void add_xt_block_frags
- (segT, xtensa_block_info **, frag_predicate, frag_predicate);
- static bfd_boolean xtensa_frag_flags_is_empty (const frag_flags *);
- static void xtensa_frag_flags_init (frag_flags *);
- static void get_frag_property_flags (const fragS *, frag_flags *);
- static flagword frag_flags_to_number (const frag_flags *);
- static void add_xt_prop_frags (segT, xtensa_block_info **, frag_flags_fn);
- /* Set up property tables after relaxation. */
- void
- xtensa_post_relax_hook (void)
- {
- xtensa_move_seg_list_to_beginning (literal_head);
- xtensa_find_unmarked_state_frags ();
- xtensa_mark_frags_for_org ();
- xtensa_mark_difference_of_two_symbols ();
- xtensa_create_property_segments (get_frag_is_literal,
- NULL,
- XTENSA_LIT_SEC_NAME,
- xt_literal_sec);
- xtensa_create_xproperty_segments (get_frag_property_flags,
- XTENSA_PROP_SEC_NAME,
- xt_prop_sec);
- if (warn_unaligned_branch_targets)
- bfd_map_over_sections (stdoutput, xtensa_find_unaligned_branch_targets, 0);
- bfd_map_over_sections (stdoutput, xtensa_find_unaligned_loops, 0);
- }
- /* This function is only meaningful after xtensa_move_literals. */
- static bfd_boolean
- get_frag_is_literal (const fragS *fragP)
- {
- gas_assert (fragP != NULL);
- return fragP->tc_frag_data.is_literal;
- }
- static void
- xtensa_create_property_segments (frag_predicate property_function,
- frag_predicate end_property_function,
- const char *section_name_base,
- xt_section_type sec_type)
- {
- segT *seclist;
- /* Walk over all of the current segments.
- Walk over each fragment
- For each non-empty fragment,
- Build a property record (append where possible). */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segT sec = *seclist;
- if (exclude_section_from_property_tables (sec))
- continue;
- if (section_has_property (sec, property_function))
- {
- segment_info_type *xt_seg_info;
- xtensa_block_info **xt_blocks;
- segT prop_sec = xtensa_make_property_section (sec, section_name_base);
- prop_sec->output_section = prop_sec;
- subseg_set (prop_sec, 0);
- xt_seg_info = seg_info (prop_sec);
- xt_blocks = &xt_seg_info->tc_segment_info_data.blocks[sec_type];
- /* Walk over all of the frchains here and add new sections. */
- add_xt_block_frags (sec, xt_blocks, property_function,
- end_property_function);
- }
- }
- /* Now we fill them out.... */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segment_info_type *seginfo;
- xtensa_block_info *block;
- segT sec = *seclist;
- seginfo = seg_info (sec);
- block = seginfo->tc_segment_info_data.blocks[sec_type];
- if (block)
- {
- xtensa_block_info *cur_block;
- int num_recs = 0;
- bfd_size_type rec_size;
- for (cur_block = block; cur_block; cur_block = cur_block->next)
- num_recs++;
- rec_size = num_recs * 8;
- bfd_set_section_size (stdoutput, sec, rec_size);
- if (num_recs)
- {
- char *frag_data;
- int i;
- subseg_set (sec, 0);
- frag_data = frag_more (rec_size);
- cur_block = block;
- for (i = 0; i < num_recs; i++)
- {
- fixS *fix;
- /* Write the fixup. */
- gas_assert (cur_block);
- fix = fix_new (frag_now, i * 8, 4,
- section_symbol (cur_block->sec),
- cur_block->offset,
- FALSE, BFD_RELOC_32);
- fix->fx_file = "<internal>";
- fix->fx_line = 0;
- /* Write the length. */
- md_number_to_chars (&frag_data[4 + i * 8],
- cur_block->size, 4);
- cur_block = cur_block->next;
- }
- frag_wane (frag_now);
- frag_new (0);
- frag_wane (frag_now);
- }
- }
- }
- }
- static void
- xtensa_create_xproperty_segments (frag_flags_fn flag_fn,
- const char *section_name_base,
- xt_section_type sec_type)
- {
- segT *seclist;
- /* Walk over all of the current segments.
- Walk over each fragment.
- For each fragment that has instructions,
- build an instruction record (append where possible). */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segT sec = *seclist;
- if (exclude_section_from_property_tables (sec))
- continue;
- if (section_has_xproperty (sec, flag_fn))
- {
- segment_info_type *xt_seg_info;
- xtensa_block_info **xt_blocks;
- segT prop_sec = xtensa_make_property_section (sec, section_name_base);
- prop_sec->output_section = prop_sec;
- subseg_set (prop_sec, 0);
- xt_seg_info = seg_info (prop_sec);
- xt_blocks = &xt_seg_info->tc_segment_info_data.blocks[sec_type];
- /* Walk over all of the frchains here and add new sections. */
- add_xt_prop_frags (sec, xt_blocks, flag_fn);
- }
- }
- /* Now we fill them out.... */
- for (seclist = &stdoutput->sections;
- seclist && *seclist;
- seclist = &(*seclist)->next)
- {
- segment_info_type *seginfo;
- xtensa_block_info *block;
- segT sec = *seclist;
- seginfo = seg_info (sec);
- block = seginfo->tc_segment_info_data.blocks[sec_type];
- if (block)
- {
- xtensa_block_info *cur_block;
- int num_recs = 0;
- bfd_size_type rec_size;
- for (cur_block = block; cur_block; cur_block = cur_block->next)
- num_recs++;
- rec_size = num_recs * (8 + 4);
- bfd_set_section_size (stdoutput, sec, rec_size);
- /* elf_section_data (sec)->this_hdr.sh_entsize = 12; */
- if (num_recs)
- {
- char *frag_data;
- int i;
- subseg_set (sec, 0);
- frag_data = frag_more (rec_size);
- cur_block = block;
- for (i = 0; i < num_recs; i++)
- {
- fixS *fix;
- /* Write the fixup. */
- gas_assert (cur_block);
- fix = fix_new (frag_now, i * 12, 4,
- section_symbol (cur_block->sec),
- cur_block->offset,
- FALSE, BFD_RELOC_32);
- fix->fx_file = "<internal>";
- fix->fx_line = 0;
- /* Write the length. */
- md_number_to_chars (&frag_data[4 + i * 12],
- cur_block->size, 4);
- md_number_to_chars (&frag_data[8 + i * 12],
- frag_flags_to_number (&cur_block->flags),
- sizeof (flagword));
- cur_block = cur_block->next;
- }
- frag_wane (frag_now);
- frag_new (0);
- frag_wane (frag_now);
- }
- }
- }
- }
- static bfd_boolean
- exclude_section_from_property_tables (segT sec)
- {
- flagword flags = bfd_get_section_flags (stdoutput, sec);
- /* Sections that don't contribute to the memory footprint are excluded. */
- if ((flags & SEC_DEBUGGING)
- || !(flags & SEC_ALLOC)
- || (flags & SEC_MERGE))
- return TRUE;
- /* Linker cie and fde optimizations mess up property entries for
- eh_frame sections, but there is nothing inside them relevant to
- property tables anyway. */
- if (strcmp (sec->name, ".eh_frame") == 0)
- return TRUE;
- return FALSE;
- }
- static bfd_boolean
- section_has_property (segT sec, frag_predicate property_function)
- {
- segment_info_type *seginfo = seg_info (sec);
- fragS *fragP;
- if (seginfo && seginfo->frchainP)
- {
- for (fragP = seginfo->frchainP->frch_root; fragP; fragP = fragP->fr_next)
- {
- if (property_function (fragP)
- && (fragP->fr_type != rs_fill || fragP->fr_fix != 0))
- return TRUE;
- }
- }
- return FALSE;
- }
- static bfd_boolean
- section_has_xproperty (segT sec, frag_flags_fn property_function)
- {
- segment_info_type *seginfo = seg_info (sec);
- fragS *fragP;
- if (seginfo && seginfo->frchainP)
- {
- for (fragP = seginfo->frchainP->frch_root; fragP; fragP = fragP->fr_next)
- {
- frag_flags prop_flags;
- property_function (fragP, &prop_flags);
- if (!xtensa_frag_flags_is_empty (&prop_flags))
- return TRUE;
- }
- }
- return FALSE;
- }
- /* Two types of block sections exist right now: literal and insns. */
- static void
- add_xt_block_frags (segT sec,
- xtensa_block_info **xt_block,
- frag_predicate property_function,
- frag_predicate end_property_function)
- {
- fragS *fragP;
- /* Build it if needed. */
- while (*xt_block != NULL)
- xt_block = &(*xt_block)->next;
- /* We are either at NULL at the beginning or at the end. */
- /* Walk through the frags. */
- if (seg_info (sec)->frchainP)
- {
- for (fragP = seg_info (sec)->frchainP->frch_root;
- fragP;
- fragP = fragP->fr_next)
- {
- if (property_function (fragP)
- && (fragP->fr_type != rs_fill || fragP->fr_fix != 0))
- {
- if (*xt_block != NULL)
- {
- if ((*xt_block)->offset + (*xt_block)->size
- == fragP->fr_address)
- (*xt_block)->size += fragP->fr_fix;
- else
- xt_block = &((*xt_block)->next);
- }
- if (*xt_block == NULL)
- {
- xtensa_block_info *new_block = (xtensa_block_info *)
- xmalloc (sizeof (xtensa_block_info));
- new_block->sec = sec;
- new_block->offset = fragP->fr_address;
- new_block->size = fragP->fr_fix;
- new_block->next = NULL;
- xtensa_frag_flags_init (&new_block->flags);
- *xt_block = new_block;
- }
- if (end_property_function
- && end_property_function (fragP))
- {
- xt_block = &((*xt_block)->next);
- }
- }
- }
- }
- }
- /* Break the encapsulation of add_xt_prop_frags here. */
- static bfd_boolean
- xtensa_frag_flags_is_empty (const frag_flags *prop_flags)
- {
- if (prop_flags->is_literal
- || prop_flags->is_insn
- || prop_flags->is_data
- || prop_flags->is_unreachable)
- return FALSE;
- return TRUE;
- }
- static void
- xtensa_frag_flags_init (frag_flags *prop_flags)
- {
- memset (prop_flags, 0, sizeof (frag_flags));
- }
- static void
- get_frag_property_flags (const fragS *fragP, frag_flags *prop_flags)
- {
- xtensa_frag_flags_init (prop_flags);
- if (fragP->tc_frag_data.is_literal)
- prop_flags->is_literal = TRUE;
- if (fragP->tc_frag_data.is_specific_opcode
- || fragP->tc_frag_data.is_no_transform)
- {
- prop_flags->is_no_transform = TRUE;
- if (xtensa_frag_flags_is_empty (prop_flags))
- prop_flags->is_data = TRUE;
- }
- if (fragP->tc_frag_data.is_unreachable)
- prop_flags->is_unreachable = TRUE;
- else if (fragP->tc_frag_data.is_insn)
- {
- prop_flags->is_insn = TRUE;
- if (fragP->tc_frag_data.is_loop_target)
- prop_flags->insn.is_loop_target = TRUE;
- if (fragP->tc_frag_data.is_branch_target)
- prop_flags->insn.is_branch_target = TRUE;
- if (fragP->tc_frag_data.is_no_density)
- prop_flags->insn.is_no_density = TRUE;
- if (fragP->tc_frag_data.use_absolute_literals)
- prop_flags->insn.is_abslit = TRUE;
- }
- if (fragP->tc_frag_data.is_align)
- {
- prop_flags->is_align = TRUE;
- prop_flags->alignment = fragP->tc_frag_data.alignment;
- if (xtensa_frag_flags_is_empty (prop_flags))
- prop_flags->is_data = TRUE;
- }
- }
- static flagword
- frag_flags_to_number (const frag_flags *prop_flags)
- {
- flagword num = 0;
- if (prop_flags->is_literal)
- num |= XTENSA_PROP_LITERAL;
- if (prop_flags->is_insn)
- num |= XTENSA_PROP_INSN;
- if (prop_flags->is_data)
- num |= XTENSA_PROP_DATA;
- if (prop_flags->is_unreachable)
- num |= XTENSA_PROP_UNREACHABLE;
- if (prop_flags->insn.is_loop_target)
- num |= XTENSA_PROP_INSN_LOOP_TARGET;
- if (prop_flags->insn.is_branch_target)
- {
- num |= XTENSA_PROP_INSN_BRANCH_TARGET;
- num = SET_XTENSA_PROP_BT_ALIGN (num, prop_flags->insn.bt_align_priority);
- }
- if (prop_flags->insn.is_no_density)
- num |= XTENSA_PROP_INSN_NO_DENSITY;
- if (prop_flags->is_no_transform)
- num |= XTENSA_PROP_NO_TRANSFORM;
- if (prop_flags->insn.is_no_reorder)
- num |= XTENSA_PROP_INSN_NO_REORDER;
- if (prop_flags->insn.is_abslit)
- num |= XTENSA_PROP_INSN_ABSLIT;
- if (prop_flags->is_align)
- {
- num |= XTENSA_PROP_ALIGN;
- num = SET_XTENSA_PROP_ALIGNMENT (num, prop_flags->alignment);
- }
- return num;
- }
- static bfd_boolean
- xtensa_frag_flags_combinable (const frag_flags *prop_flags_1,
- const frag_flags *prop_flags_2)
- {
- /* Cannot combine with an end marker. */
- if (prop_flags_1->is_literal != prop_flags_2->is_literal)
- return FALSE;
- if (prop_flags_1->is_insn != prop_flags_2->is_insn)
- return FALSE;
- if (prop_flags_1->is_data != prop_flags_2->is_data)
- return FALSE;
- if (prop_flags_1->is_insn)
- {
- /* Properties of the beginning of the frag. */
- if (prop_flags_2->insn.is_loop_target)
- return FALSE;
- if (prop_flags_2->insn.is_branch_target)
- return FALSE;
- if (prop_flags_1->insn.is_no_density !=
- prop_flags_2->insn.is_no_density)
- return FALSE;
- if (prop_flags_1->is_no_transform !=
- prop_flags_2->is_no_transform)
- return FALSE;
- if (prop_flags_1->insn.is_no_reorder !=
- prop_flags_2->insn.is_no_reorder)
- return FALSE;
- if (prop_flags_1->insn.is_abslit !=
- prop_flags_2->insn.is_abslit)
- return FALSE;
- }
- if (prop_flags_1->is_align)
- return FALSE;
- return TRUE;
- }
- static bfd_vma
- xt_block_aligned_size (const xtensa_block_info *xt_block)
- {
- bfd_vma end_addr;
- unsigned align_bits;
- if (!xt_block->flags.is_align)
- return xt_block->size;
- end_addr = xt_block->offset + xt_block->size;
- align_bits = xt_block->flags.alignment;
- end_addr = ((end_addr + ((1 << align_bits) -1)) >> align_bits) << align_bits;
- return end_addr - xt_block->offset;
- }
- static bfd_boolean
- xtensa_xt_block_combine (xtensa_block_info *xt_block,
- const xtensa_block_info *xt_block_2)
- {
- if (xt_block->sec != xt_block_2->sec)
- return FALSE;
- if (xt_block->offset + xt_block_aligned_size (xt_block)
- != xt_block_2->offset)
- return FALSE;
- if (xt_block_2->size == 0
- && (!xt_block_2->flags.is_unreachable
- || xt_block->flags.is_unreachable))
- {
- if (xt_block_2->flags.is_align
- && xt_block->flags.is_align)
- {
- /* Nothing needed. */
- if (xt_block->flags.alignment >= xt_block_2->flags.alignment)
- return TRUE;
- }
- else
- {
- if (xt_block_2->flags.is_align)
- {
- /* Push alignment to previous entry. */
- xt_block->flags.is_align = xt_block_2->flags.is_align;
- xt_block->flags.alignment = xt_block_2->flags.alignment;
- }
- return TRUE;
- }
- }
- if (!xtensa_frag_flags_combinable (&xt_block->flags,
- &xt_block_2->flags))
- return FALSE;
- xt_block->size += xt_block_2->size;
- if (xt_block_2->flags.is_align)
- {
- xt_block->flags.is_align = TRUE;
- xt_block->flags.alignment = xt_block_2->flags.alignment;
- }
- return TRUE;
- }
- static void
- add_xt_prop_frags (segT sec,
- xtensa_block_info **xt_block,
- frag_flags_fn property_function)
- {
- fragS *fragP;
- /* Build it if needed. */
- while (*xt_block != NULL)
- {
- xt_block = &(*xt_block)->next;
- }
- /* We are either at NULL at the beginning or at the end. */
- /* Walk through the frags. */
- if (seg_info (sec)->frchainP)
- {
- for (fragP = seg_info (sec)->frchainP->frch_root; fragP;
- fragP = fragP->fr_next)
- {
- xtensa_block_info tmp_block;
- tmp_block.sec = sec;
- tmp_block.offset = fragP->fr_address;
- tmp_block.size = fragP->fr_fix;
- tmp_block.next = NULL;
- property_function (fragP, &tmp_block.flags);
- if (!xtensa_frag_flags_is_empty (&tmp_block.flags))
- /* && fragP->fr_fix != 0) */
- {
- if ((*xt_block) == NULL
- || !xtensa_xt_block_combine (*xt_block, &tmp_block))
- {
- xtensa_block_info *new_block;
- if ((*xt_block) != NULL)
- xt_block = &(*xt_block)->next;
- new_block = (xtensa_block_info *)
- xmalloc (sizeof (xtensa_block_info));
- *new_block = tmp_block;
- *xt_block = new_block;
- }
- }
- }
- }
- }
- /* op_placement_info_table */
- /* op_placement_info makes it easier to determine which
- ops can go in which slots. */
- static void
- init_op_placement_info_table (void)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_insnbuf ibuf = xtensa_insnbuf_alloc (isa);
- xtensa_opcode opcode;
- xtensa_format fmt;
- int slot;
- int num_opcodes = xtensa_isa_num_opcodes (isa);
- op_placement_table = (op_placement_info_table)
- xmalloc (sizeof (op_placement_info) * num_opcodes);
- gas_assert (xtensa_isa_num_formats (isa) < MAX_FORMATS);
- for (opcode = 0; opcode < num_opcodes; opcode++)
- {
- op_placement_info *opi = &op_placement_table[opcode];
- /* FIXME: Make tinsn allocation dynamic. */
- if (xtensa_opcode_num_operands (isa, opcode) > MAX_INSN_ARGS)
- as_fatal (_("too many operands in instruction"));
- opi->narrowest = XTENSA_UNDEFINED;
- opi->narrowest_size = 0x7F;
- opi->narrowest_slot = 0;
- opi->formats = 0;
- opi->num_formats = 0;
- opi->issuef = 0;
- for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++)
- {
- opi->slots[fmt] = 0;
- for (slot = 0; slot < xtensa_format_num_slots (isa, fmt); slot++)
- {
- if (xtensa_opcode_encode (isa, fmt, slot, ibuf, opcode) == 0)
- {
- int fmt_length = xtensa_format_length (isa, fmt);
- opi->issuef++;
- set_bit (fmt, opi->formats);
- set_bit (slot, opi->slots[fmt]);
- if (fmt_length < opi->narrowest_size
- || (fmt_length == opi->narrowest_size
- && (xtensa_format_num_slots (isa, fmt)
- < xtensa_format_num_slots (isa,
- opi->narrowest))))
- {
- opi->narrowest = fmt;
- opi->narrowest_size = fmt_length;
- opi->narrowest_slot = slot;
- }
- }
- }
- if (opi->formats)
- opi->num_formats++;
- }
- }
- xtensa_insnbuf_free (isa, ibuf);
- }
- bfd_boolean
- opcode_fits_format_slot (xtensa_opcode opcode, xtensa_format fmt, int slot)
- {
- return bit_is_set (slot, op_placement_table[opcode].slots[fmt]);
- }
- /* If the opcode is available in a single slot format, return its size. */
- static int
- xg_get_single_size (xtensa_opcode opcode)
- {
- return op_placement_table[opcode].narrowest_size;
- }
- static xtensa_format
- xg_get_single_format (xtensa_opcode opcode)
- {
- return op_placement_table[opcode].narrowest;
- }
- static int
- xg_get_single_slot (xtensa_opcode opcode)
- {
- return op_placement_table[opcode].narrowest_slot;
- }
- /* Instruction Stack Functions (from "xtensa-istack.h"). */
- void
- istack_init (IStack *stack)
- {
- stack->ninsn = 0;
- }
- bfd_boolean
- istack_empty (IStack *stack)
- {
- return (stack->ninsn == 0);
- }
- bfd_boolean
- istack_full (IStack *stack)
- {
- return (stack->ninsn == MAX_ISTACK);
- }
- /* Return a pointer to the top IStack entry.
- It is an error to call this if istack_empty () is TRUE. */
- TInsn *
- istack_top (IStack *stack)
- {
- int rec = stack->ninsn - 1;
- gas_assert (!istack_empty (stack));
- return &stack->insn[rec];
- }
- /* Add a new TInsn to an IStack.
- It is an error to call this if istack_full () is TRUE. */
- void
- istack_push (IStack *stack, TInsn *insn)
- {
- int rec = stack->ninsn;
- gas_assert (!istack_full (stack));
- stack->insn[rec] = *insn;
- stack->ninsn++;
- }
- /* Clear space for the next TInsn on the IStack and return a pointer
- to it. It is an error to call this if istack_full () is TRUE. */
- TInsn *
- istack_push_space (IStack *stack)
- {
- int rec = stack->ninsn;
- TInsn *insn;
- gas_assert (!istack_full (stack));
- insn = &stack->insn[rec];
- tinsn_init (insn);
- stack->ninsn++;
- return insn;
- }
- /* Remove the last pushed instruction. It is an error to call this if
- istack_empty () returns TRUE. */
- void
- istack_pop (IStack *stack)
- {
- int rec = stack->ninsn - 1;
- gas_assert (!istack_empty (stack));
- stack->ninsn--;
- tinsn_init (&stack->insn[rec]);
- }
- /* TInsn functions. */
- void
- tinsn_init (TInsn *dst)
- {
- memset (dst, 0, sizeof (TInsn));
- }
- /* Return TRUE if ANY of the operands in the insn are symbolic. */
- static bfd_boolean
- tinsn_has_symbolic_operands (const TInsn *insn)
- {
- int i;
- int n = insn->ntok;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < n; ++i)
- {
- switch (insn->tok[i].X_op)
- {
- case O_register:
- case O_constant:
- break;
- default:
- return TRUE;
- }
- }
- return FALSE;
- }
- bfd_boolean
- tinsn_has_invalid_symbolic_operands (const TInsn *insn)
- {
- xtensa_isa isa = xtensa_default_isa;
- int i;
- int n = insn->ntok;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < n; ++i)
- {
- switch (insn->tok[i].X_op)
- {
- case O_register:
- case O_constant:
- break;
- case O_big:
- case O_illegal:
- case O_absent:
- /* Errors for these types are caught later. */
- break;
- case O_hi16:
- case O_lo16:
- default:
- /* Symbolic immediates are only allowed on the last immediate
- operand. At this time, CONST16 is the only opcode where we
- support non-PC-relative relocations. */
- if (i != get_relaxable_immed (insn->opcode)
- || (xtensa_operand_is_PCrelative (isa, insn->opcode, i) != 1
- && insn->opcode != xtensa_const16_opcode))
- {
- as_bad (_("invalid symbolic operand"));
- return TRUE;
- }
- }
- }
- return FALSE;
- }
- /* For assembly code with complex expressions (e.g. subtraction),
- we have to build them in the literal pool so that
- their results are calculated correctly after relaxation.
- The relaxation only handles expressions that
- boil down to SYMBOL + OFFSET. */
- static bfd_boolean
- tinsn_has_complex_operands (const TInsn *insn)
- {
- int i;
- int n = insn->ntok;
- gas_assert (insn->insn_type == ITYPE_INSN);
- for (i = 0; i < n; ++i)
- {
- switch (insn->tok[i].X_op)
- {
- case O_register:
- case O_constant:
- case O_symbol:
- case O_lo16:
- case O_hi16:
- break;
- default:
- return TRUE;
- }
- }
- return FALSE;
- }
- /* Encode a TInsn opcode and its constant operands into slotbuf.
- Return TRUE if there is a symbol in the immediate field. This
- function assumes that:
- 1) The number of operands are correct.
- 2) The insn_type is ITYPE_INSN.
- 3) The opcode can be encoded in the specified format and slot.
- 4) Operands are either O_constant or O_symbol, and all constants fit. */
- static bfd_boolean
- tinsn_to_slotbuf (xtensa_format fmt,
- int slot,
- TInsn *tinsn,
- xtensa_insnbuf slotbuf)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_opcode opcode = tinsn->opcode;
- bfd_boolean has_fixup = FALSE;
- int noperands = xtensa_opcode_num_operands (isa, opcode);
- int i;
- gas_assert (tinsn->insn_type == ITYPE_INSN);
- if (noperands != tinsn->ntok)
- as_fatal (_("operand number mismatch"));
- if (xtensa_opcode_encode (isa, fmt, slot, slotbuf, opcode))
- {
- as_bad (_("cannot encode opcode \"%s\" in the given format \"%s\""),
- xtensa_opcode_name (isa, opcode), xtensa_format_name (isa, fmt));
- return FALSE;
- }
- for (i = 0; i < noperands; i++)
- {
- expressionS *exp = &tinsn->tok[i];
- int rc;
- unsigned line;
- char *file_name;
- uint32 opnd_value;
- switch (exp->X_op)
- {
- case O_register:
- if (xtensa_operand_is_visible (isa, opcode, i) == 0)
- break;
- /* The register number has already been checked in
- expression_maybe_register, so we don't need to check here. */
- opnd_value = exp->X_add_number;
- (void) xtensa_operand_encode (isa, opcode, i, &opnd_value);
- rc = xtensa_operand_set_field (isa, opcode, i, fmt, slot, slotbuf,
- opnd_value);
- if (rc != 0)
- as_warn (_("xtensa-isa failure: %s"), xtensa_isa_error_msg (isa));
- break;
- case O_constant:
- if (xtensa_operand_is_visible (isa, opcode, i) == 0)
- break;
- as_where (&file_name, &line);
- /* It is a constant and we called this function
- then we have to try to fit it. */
- xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i,
- exp->X_add_number, file_name, line);
- break;
- default:
- has_fixup = TRUE;
- break;
- }
- }
- return has_fixup;
- }
- /* Encode a single TInsn into an insnbuf. If the opcode can only be encoded
- into a multi-slot instruction, fill the other slots with NOPs.
- Return TRUE if there is a symbol in the immediate field. See also the
- assumptions listed for tinsn_to_slotbuf. */
- static bfd_boolean
- tinsn_to_insnbuf (TInsn *tinsn, xtensa_insnbuf insnbuf)
- {
- static xtensa_insnbuf slotbuf = 0;
- static vliw_insn vinsn;
- xtensa_isa isa = xtensa_default_isa;
- bfd_boolean has_fixup = FALSE;
- int i;
- if (!slotbuf)
- {
- slotbuf = xtensa_insnbuf_alloc (isa);
- xg_init_vinsn (&vinsn);
- }
- xg_clear_vinsn (&vinsn);
- bundle_tinsn (tinsn, &vinsn);
- xtensa_format_encode (isa, vinsn.format, insnbuf);
- for (i = 0; i < vinsn.num_slots; i++)
- {
- /* Only one slot may have a fix-up because the rest contains NOPs. */
- has_fixup |=
- tinsn_to_slotbuf (vinsn.format, i, &vinsn.slots[i], vinsn.slotbuf[i]);
- xtensa_format_set_slot (isa, vinsn.format, i, insnbuf, vinsn.slotbuf[i]);
- }
- return has_fixup;
- }
- /* Check the instruction arguments. Return TRUE on failure. */
- static bfd_boolean
- tinsn_check_arguments (const TInsn *insn)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_opcode opcode = insn->opcode;
- xtensa_regfile t1_regfile, t2_regfile;
- int t1_reg, t2_reg;
- int t1_base_reg, t1_last_reg;
- int t2_base_reg, t2_last_reg;
- char t1_inout, t2_inout;
- int i, j;
- if (opcode == XTENSA_UNDEFINED)
- {
- as_bad (_("invalid opcode"));
- return TRUE;
- }
- if (xtensa_opcode_num_operands (isa, opcode) > insn->ntok)
- {
- as_bad (_("too few operands"));
- return TRUE;
- }
- if (xtensa_opcode_num_operands (isa, opcode) < insn->ntok)
- {
- as_bad (_("too many operands"));
- return TRUE;
- }
- /* Check registers. */
- for (j = 0; j < insn->ntok; j++)
- {
- if (xtensa_operand_is_register (isa, insn->opcode, j) != 1)
- continue;
- t2_regfile = xtensa_operand_regfile (isa, insn->opcode, j);
- t2_base_reg = insn->tok[j].X_add_number;
- t2_last_reg
- = t2_base_reg + xtensa_operand_num_regs (isa, insn->opcode, j);
- for (i = 0; i < insn->ntok; i++)
- {
- if (i == j)
- continue;
- if (xtensa_operand_is_register (isa, insn->opcode, i) != 1)
- continue;
- t1_regfile = xtensa_operand_regfile (isa, insn->opcode, i);
- if (t1_regfile != t2_regfile)
- continue;
- t1_inout = xtensa_operand_inout (isa, insn->opcode, i);
- t2_inout = xtensa_operand_inout (isa, insn->opcode, j);
- t1_base_reg = insn->tok[i].X_add_number;
- t1_last_reg = (t1_base_reg
- + xtensa_operand_num_regs (isa, insn->opcode, i));
- for (t1_reg = t1_base_reg; t1_reg < t1_last_reg; t1_reg++)
- {
- for (t2_reg = t2_base_reg; t2_reg < t2_last_reg; t2_reg++)
- {
- if (t1_reg != t2_reg)
- continue;
- if (t1_inout != 'i' && t2_inout != 'i')
- {
- as_bad (_("multiple writes to the same register"));
- return TRUE;
- }
- }
- }
- }
- }
- return FALSE;
- }
- /* Load an instruction from its encoded form. */
- static void
- tinsn_from_chars (TInsn *tinsn, char *f, int slot)
- {
- vliw_insn vinsn;
- xg_init_vinsn (&vinsn);
- vinsn_from_chars (&vinsn, f);
- *tinsn = vinsn.slots[slot];
- xg_free_vinsn (&vinsn);
- }
- static void
- tinsn_from_insnbuf (TInsn *tinsn,
- xtensa_insnbuf slotbuf,
- xtensa_format fmt,
- int slot)
- {
- int i;
- xtensa_isa isa = xtensa_default_isa;
- /* Find the immed. */
- tinsn_init (tinsn);
- tinsn->insn_type = ITYPE_INSN;
- tinsn->is_specific_opcode = FALSE; /* must not be specific */
- tinsn->opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
- tinsn->ntok = xtensa_opcode_num_operands (isa, tinsn->opcode);
- for (i = 0; i < tinsn->ntok; i++)
- {
- set_expr_const (&tinsn->tok[i],
- xtensa_insnbuf_get_operand (slotbuf, fmt, slot,
- tinsn->opcode, i));
- }
- }
- /* Read the value of the relaxable immed from the fr_symbol and fr_offset. */
- static void
- tinsn_immed_from_frag (TInsn *tinsn, fragS *fragP, int slot)
- {
- xtensa_opcode opcode = tinsn->opcode;
- int opnum;
- if (fragP->tc_frag_data.slot_symbols[slot])
- {
- opnum = get_relaxable_immed (opcode);
- gas_assert (opnum >= 0);
- set_expr_symbol_offset (&tinsn->tok[opnum],
- fragP->tc_frag_data.slot_symbols[slot],
- fragP->tc_frag_data.slot_offsets[slot]);
- }
- tinsn->extra_arg = fragP->tc_frag_data.free_reg[slot];
- }
- static int
- get_num_stack_text_bytes (IStack *istack)
- {
- int i;
- int text_bytes = 0;
- for (i = 0; i < istack->ninsn; i++)
- {
- TInsn *tinsn = &istack->insn[i];
- if (tinsn->insn_type == ITYPE_INSN)
- text_bytes += xg_get_single_size (tinsn->opcode);
- }
- return text_bytes;
- }
- static int
- get_num_stack_literal_bytes (IStack *istack)
- {
- int i;
- int lit_bytes = 0;
- for (i = 0; i < istack->ninsn; i++)
- {
- TInsn *tinsn = &istack->insn[i];
- if (tinsn->insn_type == ITYPE_LITERAL && tinsn->ntok == 1)
- lit_bytes += 4;
- }
- return lit_bytes;
- }
- /* vliw_insn functions. */
- static void
- xg_init_vinsn (vliw_insn *v)
- {
- int i;
- xtensa_isa isa = xtensa_default_isa;
- xg_clear_vinsn (v);
- v->insnbuf = xtensa_insnbuf_alloc (isa);
- if (v->insnbuf == NULL)
- as_fatal (_("out of memory"));
- for (i = 0; i < config_max_slots; i++)
- {
- v->slotbuf[i] = xtensa_insnbuf_alloc (isa);
- if (v->slotbuf[i] == NULL)
- as_fatal (_("out of memory"));
- }
- }
- static void
- xg_clear_vinsn (vliw_insn *v)
- {
- int i;
- memset (v, 0, offsetof (vliw_insn, slots)
- + sizeof(TInsn) * config_max_slots);
- v->format = XTENSA_UNDEFINED;
- v->num_slots = 0;
- v->inside_bundle = FALSE;
- if (xt_saved_debug_type != DEBUG_NONE)
- debug_type = xt_saved_debug_type;
- for (i = 0; i < config_max_slots; i++)
- v->slots[i].opcode = XTENSA_UNDEFINED;
- }
- static void
- xg_copy_vinsn (vliw_insn *dst, vliw_insn *src)
- {
- memcpy (dst, src,
- offsetof(vliw_insn, slots) + src->num_slots * sizeof(TInsn));
- dst->insnbuf = src->insnbuf;
- memcpy (dst->slotbuf, src->slotbuf, src->num_slots * sizeof(xtensa_insnbuf));
- }
- static bfd_boolean
- vinsn_has_specific_opcodes (vliw_insn *v)
- {
- int i;
- for (i = 0; i < v->num_slots; i++)
- {
- if (v->slots[i].is_specific_opcode)
- return TRUE;
- }
- return FALSE;
- }
- static void
- xg_free_vinsn (vliw_insn *v)
- {
- int i;
- xtensa_insnbuf_free (xtensa_default_isa, v->insnbuf);
- for (i = 0; i < config_max_slots; i++)
- xtensa_insnbuf_free (xtensa_default_isa, v->slotbuf[i]);
- }
- /* Encode a vliw_insn into an insnbuf. Return TRUE if there are any symbolic
- operands. See also the assumptions listed for tinsn_to_slotbuf. */
- static bfd_boolean
- vinsn_to_insnbuf (vliw_insn *vinsn,
- char *frag_offset,
- fragS *fragP,
- bfd_boolean record_fixup)
- {
- xtensa_isa isa = xtensa_default_isa;
- xtensa_format fmt = vinsn->format;
- xtensa_insnbuf insnbuf = vinsn->insnbuf;
- int slot;
- bfd_boolean has_fixup = FALSE;
- xtensa_format_encode (isa, fmt, insnbuf);
- for (slot = 0; slot < vinsn->num_slots; slot++)
- {
- TInsn *tinsn = &vinsn->slots[slot];
- expressionS *extra_arg = &tinsn->extra_arg;
- bfd_boolean tinsn_has_fixup =
- tinsn_to_slotbuf (vinsn->format, slot, tinsn,
- vinsn->slotbuf[slot]);
- xtensa_format_set_slot (isa, fmt, slot,
- insnbuf, vinsn->slotbuf[slot]);
- if (extra_arg->X_op != O_illegal && extra_arg->X_op != O_register)
- {
- if (vinsn->num_slots != 1)
- as_bad (_("TLS relocation not allowed in FLIX bundle"));
- else if (record_fixup)
- /* Instructions that generate TLS relocations should always be
- relaxed in the front-end. If "record_fixup" is set, then this
- function is being called during back-end relaxation, so flag
- the unexpected behavior as an error. */
- as_bad (_("unexpected TLS relocation"));
- else
- fix_new (fragP, frag_offset - fragP->fr_literal,
- xtensa_format_length (isa, fmt),
- extra_arg->X_add_symbol, extra_arg->X_add_number,
- FALSE, map_operator_to_reloc (extra_arg->X_op, FALSE));
- }
- if (tinsn_has_fixup)
- {
- int i;
- xtensa_opcode opcode = tinsn->opcode;
- int noperands = xtensa_opcode_num_operands (isa, opcode);
- has_fixup = TRUE;
- for (i = 0; i < noperands; i++)
- {
- expressionS* exp = &tinsn->tok[i];
- switch (exp->X_op)
- {
- case O_symbol:
- case O_lo16:
- case O_hi16:
- if (get_relaxable_immed (opcode) == i)
- {
- /* Add a fix record for the instruction, except if this
- function is being called prior to relaxation, i.e.,
- if record_fixup is false, and the instruction might
- be relaxed later. */
- if (record_fixup
- || tinsn->is_specific_opcode
- || !xg_is_relaxable_insn (tinsn, 0))
- {
- xg_add_opcode_fix (tinsn, i, fmt, slot, exp, fragP,
- frag_offset - fragP->fr_literal);
- }
- else
- {
- if (exp->X_op != O_symbol)
- as_bad (_("invalid operand"));
- tinsn->symbol = exp->X_add_symbol;
- tinsn->offset = exp->X_add_number;
- }
- }
- else
- as_bad (_("symbolic operand not allowed"));
- break;
- case O_constant:
- case O_register:
- break;
- default:
- as_bad (_("expression too complex"));
- break;
- }
- }
- }
- }
- return has_fixup;
- }
- static void
- vinsn_from_chars (vliw_insn *vinsn, char *f)
- {
- static xtensa_insnbuf insnbuf = NULL;
- static xtensa_insnbuf slotbuf = NULL;
- int i;
- xtensa_format fmt;
- xtensa_isa isa = xtensa_default_isa;
- if (!insnbuf)
- {
- insnbuf = xtensa_insnbuf_alloc (isa);
- slotbuf = xtensa_insnbuf_alloc (isa);
- }
- xtensa_insnbuf_from_chars (isa, insnbuf, (unsigned char *) f, 0);
- fmt = xtensa_format_decode (isa, insnbuf);
- if (fmt == XTENSA_UNDEFINED)
- as_fatal (_("cannot decode instruction format"));
- vinsn->format = fmt;
- vinsn->num_slots = xtensa_format_num_slots (isa, fmt);
- for (i = 0; i < vinsn->num_slots; i++)
- {
- TInsn *tinsn = &vinsn->slots[i];
- xtensa_format_get_slot (isa, fmt, i, insnbuf, slotbuf);
- tinsn_from_insnbuf (tinsn, slotbuf, fmt, i);
- }
- }
- /* Expression utilities. */
- /* Return TRUE if the expression is an integer constant. */
- bfd_boolean
- expr_is_const (const expressionS *s)
- {
- return (s->X_op == O_constant);
- }
- /* Get the expression constant.
- Calling this is illegal if expr_is_const () returns TRUE. */
- offsetT
- get_expr_const (const expressionS *s)
- {
- gas_assert (expr_is_const (s));
- return s->X_add_number;
- }
- /* Set the expression to a constant value. */
- void
- set_expr_const (expressionS *s, offsetT val)
- {
- s->X_op = O_constant;
- s->X_add_number = val;
- s->X_add_symbol = NULL;
- s->X_op_symbol = NULL;
- }
- bfd_boolean
- expr_is_register (const expressionS *s)
- {
- return (s->X_op == O_register);
- }
- /* Get the expression constant.
- Calling this is illegal if expr_is_const () returns TRUE. */
- offsetT
- get_expr_register (const expressionS *s)
- {
- gas_assert (expr_is_register (s));
- return s->X_add_number;
- }
- /* Set the expression to a symbol + constant offset. */
- void
- set_expr_symbol_offset (expressionS *s, symbolS *sym, offsetT offset)
- {
- s->X_op = O_symbol;
- s->X_add_symbol = sym;
- s->X_op_symbol = NULL; /* unused */
- s->X_add_number = offset;
- }
- /* Return TRUE if the two expressions are equal. */
- bfd_boolean
- expr_is_equal (expressionS *s1, expressionS *s2)
- {
- if (s1->X_op != s2->X_op)
- return FALSE;
- if (s1->X_add_symbol != s2->X_add_symbol)
- return FALSE;
- if (s1->X_op_symbol != s2->X_op_symbol)
- return FALSE;
- if (s1->X_add_number != s2->X_add_number)
- return FALSE;
- return TRUE;
- }
- static void
- copy_expr (expressionS *dst, const expressionS *src)
- {
- memcpy (dst, src, sizeof (expressionS));
- }
- /* Support for the "--rename-section" option. */
- struct rename_section_struct
- {
- char *old_name;
- char *new_name;
- struct rename_section_struct *next;
- };
- static struct rename_section_struct *section_rename;
- /* Parse the string "oldname=new_name(:oldname2=new_name2)*" and add
- entries to the section_rename list. Note: Specifying multiple
- renamings separated by colons is not documented and is retained only
- for backward compatibility. */
- static void
- build_section_rename (const char *arg)
- {
- struct rename_section_struct *r;
- char *this_arg = NULL;
- char *next_arg = NULL;
- for (this_arg = xstrdup (arg); this_arg != NULL; this_arg = next_arg)
- {
- char *old_name, *new_name;
- if (this_arg)
- {
- next_arg = strchr (this_arg, ':');
- if (next_arg)
- {
- *next_arg = '\0';
- next_arg++;
- }
- }
- old_name = this_arg;
- new_name = strchr (this_arg, '=');
- if (*old_name == '\0')
- {
- as_warn (_("ignoring extra '-rename-section' delimiter ':'"));
- continue;
- }
- if (!new_name || new_name[1] == '\0')
- {
- as_warn (_("ignoring invalid '-rename-section' specification: '%s'"),
- old_name);
- continue;
- }
- *new_name = '\0';
- new_name++;
- /* Check for invalid section renaming. */
- for (r = section_rename; r != NULL; r = r->next)
- {
- if (strcmp (r->old_name, old_name) == 0)
- as_bad (_("section %s renamed multiple times"), old_name);
- if (strcmp (r->new_name, new_name) == 0)
- as_bad (_("multiple sections remapped to output section %s"),
- new_name);
- }
- /* Now add it. */
- r = (struct rename_section_struct *)
- xmalloc (sizeof (struct rename_section_struct));
- r->old_name = xstrdup (old_name);
- r->new_name = xstrdup (new_name);
- r->next = section_rename;
- section_rename = r;
- }
- }
- char *
- xtensa_section_rename (char *name)
- {
- struct rename_section_struct *r = section_rename;
- for (r = section_rename; r != NULL; r = r->next)
- {
- if (strcmp (r->old_name, name) == 0)
- return r->new_name;
- }
- return name;
- }
|