123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096 |
- // Inferno utils/5l/span.c
- // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/span.c
- //
- // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
- // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
- // Portions Copyright © 1997-1999 Vita Nuova Limited
- // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
- // Portions Copyright © 2004,2006 Bruce Ellis
- // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
- // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
- // Portions Copyright © 2009 The Go Authors. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- package arm
- import (
- "github.com/twitchyliquid64/golang-asm/obj"
- "github.com/twitchyliquid64/golang-asm/objabi"
- "fmt"
- "log"
- "math"
- "sort"
- )
- // ctxt5 holds state while assembling a single function.
- // Each function gets a fresh ctxt5.
- // This allows for multiple functions to be safely concurrently assembled.
- type ctxt5 struct {
- ctxt *obj.Link
- newprog obj.ProgAlloc
- cursym *obj.LSym
- printp *obj.Prog
- blitrl *obj.Prog
- elitrl *obj.Prog
- autosize int64
- instoffset int64
- pc int64
- pool struct {
- start uint32
- size uint32
- extra uint32
- }
- }
- type Optab struct {
- as obj.As
- a1 uint8
- a2 int8
- a3 uint8
- type_ uint8
- size int8
- param int16
- flag int8
- pcrelsiz uint8
- scond uint8 // optional flags accepted by the instruction
- }
- type Opcross [32][2][32]uint8
- const (
- LFROM = 1 << 0
- LTO = 1 << 1
- LPOOL = 1 << 2
- LPCREL = 1 << 3
- )
- var optab = []Optab{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type, size, param, flag, extra data size, optional suffix */
- {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0, 0},
- {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT},
- {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0, 0},
- {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT},
- {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0},
- {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0},
- {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0, 0},
- {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT},
- {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0, 0},
- {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0, C_SBIT},
- {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0, 0},
- {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0},
- {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0, 0},
- {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0},
- {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // prediction hinted form, hint ignored
- {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0, 0},
- {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0},
- {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0},
- {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0, 0},
- {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0, 0},
- {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0, C_SBIT},
- {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0, C_SBIT},
- {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0, C_SBIT},
- {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0, C_SBIT},
- {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0, 0},
- {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0, 0},
- {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
- {AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
- {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0, 0},
- {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4, 0},
- {AMVN, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0},
- {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0},
- {AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT},
- {AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, 0},
- {ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0},
- {AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0},
- {AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0},
- {AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0},
- {AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0},
- {AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0, 0},
- {AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0, 0},
- {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT},
- {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, 0},
- {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0, 0},
- {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0},
- {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0},
- {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
- {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0},
- {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0, C_SBIT},
- {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0, C_SBIT},
- {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0, 0},
- {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0, 0},
- {ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0, 0},
- {ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0, 0},
- {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0, C_SBIT},
- {ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3
- {ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3
- {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AXTAB, C_SHIFT, C_REG, C_REG, 22, 4, 0, 0, 0, 0},
- {AXTAB, C_SHIFT, C_NONE, C_REG, 22, 4, 0, 0, 0, 0},
- {AMOVW, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, C_SBIT},
- {AMOVB, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVBS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVBU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVH, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVHS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVHU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0, 0},
- {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0, 0},
- {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0, C_SBIT},
- {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0, 0},
- {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0, 0},
- {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0, 0},
- {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0, 0},
- {AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0},
- {ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0, 0},
- {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0, 0},
- {AMOVW, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVW, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBU, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT},
- {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT},
- {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0, 0},
- {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0, 0},
- {ADMB, C_NONE, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
- {ADMB, C_LCON, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
- {ADMB, C_SPR, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0},
- {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0, 0},
- {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0, 0},
- {ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0, 0},
- {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0, 0},
- {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0, C_UBIT},
- {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0, C_UBIT},
- {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0, C_UBIT},
- {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0, C_UBIT},
- {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0, 0},
- {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0, 0},
- {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0, 0},
- {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0, 0},
- {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0, 0},
- {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0, 0},
- {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0, 0},
- {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0, 0},
- {AMULA, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, C_SBIT},
- {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, 0},
- {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0, 0},
- {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0, 0},
- {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
- {obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, // nop variants, see #40689
- {obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
- {obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0},
- {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL
- {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL
- {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0, 0},
- }
- var mbOp = []struct {
- reg int16
- enc uint32
- }{
- {REG_MB_SY, 15},
- {REG_MB_ST, 14},
- {REG_MB_ISH, 11},
- {REG_MB_ISHST, 10},
- {REG_MB_NSH, 7},
- {REG_MB_NSHST, 6},
- {REG_MB_OSH, 3},
- {REG_MB_OSHST, 2},
- }
- var oprange [ALAST & obj.AMask][]Optab
- var xcmp [C_GOK + 1][C_GOK + 1]bool
- var (
- deferreturn *obj.LSym
- symdiv *obj.LSym
- symdivu *obj.LSym
- symmod *obj.LSym
- symmodu *obj.LSym
- )
- // Note about encoding: Prog.scond holds the condition encoding,
- // but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
- // The code that shifts the value << 28 has the responsibility
- // for XORing with C_SCOND_XOR too.
- func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) {
- if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 {
- c.ctxt.Diag("invalid .S suffix: %v", p)
- }
- if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 {
- c.ctxt.Diag("invalid .P suffix: %v", p)
- }
- if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 {
- c.ctxt.Diag("invalid .W suffix: %v", p)
- }
- if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 {
- c.ctxt.Diag("invalid .U suffix: %v", p)
- }
- }
- func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if ctxt.Retpoline {
- ctxt.Diag("-spectre=ret not supported on arm")
- ctxt.Retpoline = false // don't keep printing
- }
- var p *obj.Prog
- var op *obj.Prog
- p = cursym.Func.Text
- if p == nil || p.Link == nil { // handle external functions and ELF section symbols
- return
- }
- if oprange[AAND&obj.AMask] == nil {
- ctxt.Diag("arm ops not initialized, call arm.buildop first")
- }
- c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4}
- pc := int32(0)
- op = p
- p = p.Link
- var m int
- var o *Optab
- for ; p != nil || c.blitrl != nil; op, p = p, p.Link {
- if p == nil {
- if c.checkpool(op, pc) {
- p = op
- continue
- }
- // can't happen: blitrl is not nil, but checkpool didn't flushpool
- ctxt.Diag("internal inconsistency")
- break
- }
- p.Pc = int64(pc)
- o = c.oplook(p)
- m = int(o.size)
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("!pc invalid: %v size=%d", p, m)
- }
- // must check literal pool here in case p generates many instructions
- if c.blitrl != nil {
- // Emit the constant pool just before p if p
- // would push us over the immediate size limit.
- if c.checkpool(op, pc+int32(m)) {
- // Back up to the instruction just
- // before the pool and continue with
- // the first instruction of the pool.
- p = op
- continue
- }
- }
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
- ctxt.Diag("zero-width instruction\n%v", p)
- continue
- }
- switch o.flag & (LFROM | LTO | LPOOL) {
- case LFROM:
- c.addpool(p, &p.From)
- case LTO:
- c.addpool(p, &p.To)
- case LPOOL:
- if p.Scond&C_SCOND == C_SCOND_NONE {
- c.flushpool(p, 0, 0)
- }
- }
- if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
- c.flushpool(p, 0, 0)
- }
- pc += int32(m)
- }
- c.cursym.Size = int64(pc)
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- times := 0
- var bflag int
- var opc int32
- var out [6 + 3]uint32
- for {
- bflag = 0
- pc = 0
- times++
- c.cursym.Func.Text.Pc = 0 // force re-layout the code.
- for p = c.cursym.Func.Text; p != nil; p = p.Link {
- o = c.oplook(p)
- if int64(pc) > p.Pc {
- p.Pc = int64(pc)
- }
- /* very large branches
- if(o->type == 6 && p->pcond) {
- otxt = p->pcond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = p->pcond;
- p->pcond = q;
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = q->link->link;
- bflag = 1;
- }
- }
- */
- opc = int32(p.Pc)
- m = int(o.size)
- if p.Pc != int64(opc) {
- bflag = 1
- }
- //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
- pc = int32(p.Pc + int64(m))
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("pc invalid: %v size=%d", p, m)
- }
- if m/4 > len(out) {
- ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
- }
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) {
- if p.As == obj.ATEXT {
- c.autosize = p.To.Offset + 4
- continue
- }
- ctxt.Diag("zero-width instruction\n%v", p)
- continue
- }
- }
- c.cursym.Size = int64(pc)
- if bflag == 0 {
- break
- }
- }
- if pc%4 != 0 {
- ctxt.Diag("sym->size=%d, invalid", pc)
- }
- /*
- * lay out the code. all the pc-relative code references,
- * even cross-function, are resolved now;
- * only data references need to be relocated.
- * with more work we could leave cross-function
- * code references to be relocated too, and then
- * perhaps we'd be able to parallelize the span loop above.
- */
- p = c.cursym.Func.Text
- c.autosize = p.To.Offset + 4
- c.cursym.Grow(c.cursym.Size)
- bp := c.cursym.P
- pc = int32(p.Pc) // even p->link might need extra padding
- var v int
- for p = p.Link; p != nil; p = p.Link {
- c.pc = p.Pc
- o = c.oplook(p)
- opc = int32(p.Pc)
- c.asmout(p, o, out[:])
- m = int(o.size)
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
- }
- if int64(pc) > p.Pc {
- ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p)
- }
- for int64(pc) != p.Pc {
- // emit 0xe1a00000 (MOVW R0, R0)
- bp[0] = 0x00
- bp = bp[1:]
- bp[0] = 0x00
- bp = bp[1:]
- bp[0] = 0xa0
- bp = bp[1:]
- bp[0] = 0xe1
- bp = bp[1:]
- pc += 4
- }
- for i := 0; i < m/4; i++ {
- v = int(out[i])
- bp[0] = byte(v)
- bp = bp[1:]
- bp[0] = byte(v >> 8)
- bp = bp[1:]
- bp[0] = byte(v >> 16)
- bp = bp[1:]
- bp[0] = byte(v >> 24)
- bp = bp[1:]
- }
- pc += int32(m)
- }
- }
- // checkpool flushes the literal pool when the first reference to
- // it threatens to go out of range of a 12-bit PC-relative offset.
- //
- // nextpc is the tentative next PC at which the pool could be emitted.
- // checkpool should be called *before* emitting the instruction that
- // would cause the PC to reach nextpc.
- // If nextpc is too far from the first pool reference, checkpool will
- // flush the pool immediately after p.
- // The caller should resume processing a p.Link.
- func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool {
- poolLast := nextpc
- poolLast += 4 // the AB instruction to jump around the pool
- poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry
- refPC := int32(c.pool.start) // PC of the first pool reference
- v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl)
- if c.pool.size >= 0xff0 || immaddr(v) == 0 {
- return c.flushpool(p, 1, 0)
- } else if p.Link == nil {
- return c.flushpool(p, 2, 0)
- }
- return false
- }
- func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool {
- if c.blitrl != nil {
- if skip != 0 {
- if false && skip == 1 {
- fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
- }
- q := c.newprog()
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(p.Link)
- q.Link = c.blitrl
- q.Pos = p.Pos
- c.blitrl = q
- } else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) {
- return false
- }
- // The line number for constant pool entries doesn't really matter.
- // We set it to the line number of the preceding instruction so that
- // there are no deltas to encode in the pc-line tables.
- for q := c.blitrl; q != nil; q = q.Link {
- q.Pos = p.Pos
- }
- c.elitrl.Link = p.Link
- p.Link = c.blitrl
- c.blitrl = nil /* BUG: should refer back to values until out-of-range */
- c.elitrl = nil
- c.pool.size = 0
- c.pool.start = 0
- c.pool.extra = 0
- return true
- }
- return false
- }
- func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) {
- t := c.newprog()
- t.As = AWORD
- switch c.aclass(a) {
- default:
- t.To.Offset = a.Offset
- t.To.Sym = a.Sym
- t.To.Type = a.Type
- t.To.Name = a.Name
- if c.ctxt.Flag_shared && t.To.Sym != nil {
- t.Rel = p
- }
- case C_SROREG,
- C_LOREG,
- C_ROREG,
- C_FOREG,
- C_SOREG,
- C_HOREG,
- C_FAUTO,
- C_SAUTO,
- C_LAUTO,
- C_LACON:
- t.To.Type = obj.TYPE_CONST
- t.To.Offset = c.instoffset
- }
- if t.Rel == nil {
- for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
- if q.Rel == nil && q.To == t.To {
- p.Pool = q
- return
- }
- }
- }
- q := c.newprog()
- *q = *t
- q.Pc = int64(c.pool.size)
- if c.blitrl == nil {
- c.blitrl = q
- c.pool.start = uint32(p.Pc)
- } else {
- c.elitrl.Link = q
- }
- c.elitrl = q
- c.pool.size += 4
- // Store the link to the pool entry in Pool.
- p.Pool = q
- }
- func (c *ctxt5) regoff(a *obj.Addr) int32 {
- c.instoffset = 0
- c.aclass(a)
- return int32(c.instoffset)
- }
- func immrot(v uint32) int32 {
- for i := 0; i < 16; i++ {
- if v&^0xff == 0 {
- return int32(uint32(int32(i)<<8) | v | 1<<25)
- }
- v = v<<2 | v>>30
- }
- return 0
- }
- // immrot2a returns bits encoding the immediate constant fields of two instructions,
- // such that the encoded constants x, y satisfy x|y==v, x&y==0.
- // Returns 0,0 if no such decomposition of v exists.
- func immrot2a(v uint32) (uint32, uint32) {
- for i := uint(1); i < 32; i++ {
- m := uint32(1<<i - 1)
- if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 {
- return uint32(x), uint32(y)
- }
- }
- // TODO: handle some more cases, like where
- // the wraparound from the rotate could help.
- return 0, 0
- }
- // immrot2s returns bits encoding the immediate constant fields of two instructions,
- // such that the encoded constants y, x satisfy y-x==v, y&x==0.
- // Returns 0,0 if no such decomposition of v exists.
- func immrot2s(v uint32) (uint32, uint32) {
- if immrot(v) != 0 {
- return v, 0
- }
- // suppose v in the form of {leading 00, upper effective bits, lower 8 effective bits, trailing 00}
- // omit trailing 00
- var i uint32
- for i = 2; i < 32; i += 2 {
- if v&(1<<i-1) != 0 {
- break
- }
- }
- // i must be <= 24, then adjust i just above lower 8 effective bits of v
- i += 6
- // let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v
- x := 1<<i - v&(1<<i-1)
- y := v + x
- if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 {
- return y, x
- }
- return 0, 0
- }
- func immaddr(v int32) int32 {
- if v >= 0 && v <= 0xfff {
- return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
- }
- if v >= -0xfff && v < 0 {
- return -v&0xfff | 1<<24 /* pre indexing */
- }
- return 0
- }
- func immfloat(v int32) bool {
- return v&0xC03 == 0 /* offset will fit in floating-point load/store */
- }
- func immhalf(v int32) bool {
- if v >= 0 && v <= 0xff {
- return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
- }
- if v >= -0xff && v < 0 {
- return -v&0xff|1<<24 != 0 /* pre indexing */
- }
- return false
- }
- func (c *ctxt5) aclass(a *obj.Addr) int {
- switch a.Type {
- case obj.TYPE_NONE:
- return C_NONE
- case obj.TYPE_REG:
- c.instoffset = 0
- if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
- return C_REG
- }
- if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
- return C_FREG
- }
- if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
- return C_FCR
- }
- if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
- return C_PSR
- }
- if a.Reg >= REG_SPECIAL {
- return C_SPR
- }
- return C_GOK
- case obj.TYPE_REGREG:
- return C_REGREG
- case obj.TYPE_REGREG2:
- return C_REGREG2
- case obj.TYPE_REGLIST:
- return C_REGLIST
- case obj.TYPE_SHIFT:
- if a.Reg == 0 {
- // register shift R>>i
- return C_SHIFT
- } else {
- // memory address with shifted offset R>>i(R)
- return C_SHIFTADDR
- }
- case obj.TYPE_MEM:
- switch a.Name {
- case obj.NAME_EXTERN,
- obj.NAME_GOTREF,
- obj.NAME_STATIC:
- if a.Sym == nil || a.Sym.Name == "" {
- fmt.Printf("null sym external\n")
- return C_GOK
- }
- c.instoffset = 0 // s.b. unused but just in case
- if a.Sym.Type == objabi.STLSBSS {
- if c.ctxt.Flag_shared {
- return C_TLS_IE
- } else {
- return C_TLS_LE
- }
- }
- return C_ADDR
- case obj.NAME_AUTO:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-SP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = c.autosize + a.Offset
- if t := immaddr(int32(c.instoffset)); t != 0 {
- if immhalf(int32(c.instoffset)) {
- if immfloat(t) {
- return C_HFAUTO
- }
- return C_HAUTO
- }
- if immfloat(t) {
- return C_FAUTO
- }
- return C_SAUTO
- }
- return C_LAUTO
- case obj.NAME_PARAM:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-FP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = c.autosize + a.Offset + 4
- if t := immaddr(int32(c.instoffset)); t != 0 {
- if immhalf(int32(c.instoffset)) {
- if immfloat(t) {
- return C_HFAUTO
- }
- return C_HAUTO
- }
- if immfloat(t) {
- return C_FAUTO
- }
- return C_SAUTO
- }
- return C_LAUTO
- case obj.NAME_NONE:
- c.instoffset = a.Offset
- if t := immaddr(int32(c.instoffset)); t != 0 {
- if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */
- if immfloat(t) {
- return C_HFOREG
- }
- return C_HOREG
- }
- if immfloat(t) {
- return C_FOREG /* n.b. that it will also satisfy immrot */
- }
- if immrot(uint32(c.instoffset)) != 0 {
- return C_SROREG
- }
- if immhalf(int32(c.instoffset)) {
- return C_HOREG
- }
- return C_SOREG
- }
- if immrot(uint32(c.instoffset)) != 0 {
- return C_ROREG
- }
- return C_LOREG
- }
- return C_GOK
- case obj.TYPE_FCONST:
- if c.chipzero5(a.Val.(float64)) >= 0 {
- return C_ZFCON
- }
- if c.chipfloat5(a.Val.(float64)) >= 0 {
- return C_SFCON
- }
- return C_LFCON
- case obj.TYPE_TEXTSIZE:
- return C_TEXTSIZE
- case obj.TYPE_CONST,
- obj.TYPE_ADDR:
- switch a.Name {
- case obj.NAME_NONE:
- c.instoffset = a.Offset
- if a.Reg != 0 {
- return c.aconsize()
- }
- if immrot(uint32(c.instoffset)) != 0 {
- return C_RCON
- }
- if immrot(^uint32(c.instoffset)) != 0 {
- return C_NCON
- }
- if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 {
- return C_SCON
- }
- if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 {
- return C_RCON2A
- }
- if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 {
- return C_RCON2S
- }
- return C_LCON
- case obj.NAME_EXTERN,
- obj.NAME_GOTREF,
- obj.NAME_STATIC:
- s := a.Sym
- if s == nil {
- break
- }
- c.instoffset = 0 // s.b. unused but just in case
- return C_LCONADDR
- case obj.NAME_AUTO:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-SP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = c.autosize + a.Offset
- return c.aconsize()
- case obj.NAME_PARAM:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-FP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = c.autosize + a.Offset + 4
- return c.aconsize()
- }
- return C_GOK
- case obj.TYPE_BRANCH:
- return C_SBRA
- }
- return C_GOK
- }
- func (c *ctxt5) aconsize() int {
- if immrot(uint32(c.instoffset)) != 0 {
- return C_RACON
- }
- if immrot(uint32(-c.instoffset)) != 0 {
- return C_RACON
- }
- return C_LACON
- }
- func (c *ctxt5) oplook(p *obj.Prog) *Optab {
- a1 := int(p.Optab)
- if a1 != 0 {
- return &optab[a1-1]
- }
- a1 = int(p.From.Class)
- if a1 == 0 {
- a1 = c.aclass(&p.From) + 1
- p.From.Class = int8(a1)
- }
- a1--
- a3 := int(p.To.Class)
- if a3 == 0 {
- a3 = c.aclass(&p.To) + 1
- p.To.Class = int8(a3)
- }
- a3--
- a2 := C_NONE
- if p.Reg != 0 {
- switch {
- case REG_F0 <= p.Reg && p.Reg <= REG_F15:
- a2 = C_FREG
- case REG_R0 <= p.Reg && p.Reg <= REG_R15:
- a2 = C_REG
- default:
- c.ctxt.Diag("invalid register in %v", p)
- }
- }
- // check illegal base register
- switch a1 {
- case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
- if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg {
- c.ctxt.Diag("illegal base register: %v", p)
- }
- default:
- }
- switch a3 {
- case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR:
- if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg {
- c.ctxt.Diag("illegal base register: %v", p)
- }
- default:
- }
- // If current instruction has a .S suffix (flags update),
- // we must use the constant pool instead of splitting it.
- if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 {
- a1 = C_LCON
- }
- if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 {
- a3 = C_LCON
- }
- if false { /*debug['O']*/
- fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
- fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
- }
- ops := oprange[p.As&obj.AMask]
- c1 := &xcmp[a1]
- c3 := &xcmp[a3]
- for i := range ops {
- op := &ops[i]
- if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
- p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
- checkSuffix(c, p, op)
- return op
- }
- }
- c.ctxt.Diag("illegal combination %v; %v %v %v; from %d %d; to %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.From.Name, p.To.Type, p.To.Name)
- if ops == nil {
- ops = optab
- }
- return &ops[0]
- }
- func cmp(a int, b int) bool {
- if a == b {
- return true
- }
- switch a {
- case C_LCON:
- if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S {
- return true
- }
- case C_LACON:
- if b == C_RACON {
- return true
- }
- case C_LFCON:
- if b == C_ZFCON || b == C_SFCON {
- return true
- }
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO
- case C_FAUTO, C_HAUTO:
- return b == C_HFAUTO
- case C_SAUTO:
- return cmp(C_HFAUTO, b)
- case C_LAUTO:
- return cmp(C_SAUTO, b)
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG
- case C_FOREG, C_HOREG:
- return b == C_HFOREG
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b)
- case C_SOREG, C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b)
- case C_LOREG:
- return cmp(C_SROREG, b)
- case C_LBRA:
- if b == C_SBRA {
- return true
- }
- case C_HREG:
- return cmp(C_SP, b) || cmp(C_PC, b)
- }
- return false
- }
- type ocmp []Optab
- func (x ocmp) Len() int {
- return len(x)
- }
- func (x ocmp) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
- }
- func (x ocmp) Less(i, j int) bool {
- p1 := &x[i]
- p2 := &x[j]
- n := int(p1.as) - int(p2.as)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a1) - int(p2.a1)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a2) - int(p2.a2)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a3) - int(p2.a3)
- if n != 0 {
- return n < 0
- }
- return false
- }
- func opset(a, b0 obj.As) {
- oprange[a&obj.AMask] = oprange[b0]
- }
- func buildop(ctxt *obj.Link) {
- if oprange[AAND&obj.AMask] != nil {
- // Already initialized; stop now.
- // This happens in the cmd/asm tests,
- // each of which re-initializes the arch.
- return
- }
- deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
- symdiv = ctxt.Lookup("runtime._div")
- symdivu = ctxt.Lookup("runtime._divu")
- symmod = ctxt.Lookup("runtime._mod")
- symmodu = ctxt.Lookup("runtime._modu")
- var n int
- for i := 0; i < C_GOK; i++ {
- for n = 0; n < C_GOK; n++ {
- if cmp(n, i) {
- xcmp[i][n] = true
- }
- }
- }
- for n = 0; optab[n].as != obj.AXXX; n++ {
- if optab[n].flag&LPCREL != 0 {
- if ctxt.Flag_shared {
- optab[n].size += int8(optab[n].pcrelsiz)
- } else {
- optab[n].flag &^= LPCREL
- }
- }
- }
- sort.Sort(ocmp(optab[:n]))
- for i := 0; i < n; i++ {
- r := optab[i].as
- r0 := r & obj.AMask
- start := i
- for optab[i].as == r {
- i++
- }
- oprange[r0] = optab[start:i]
- i--
- switch r {
- default:
- ctxt.Diag("unknown op in build: %v", r)
- ctxt.DiagFlush()
- log.Fatalf("bad code")
- case AADD:
- opset(ASUB, r0)
- opset(ARSB, r0)
- opset(AADC, r0)
- opset(ASBC, r0)
- opset(ARSC, r0)
- case AORR:
- opset(AEOR, r0)
- opset(ABIC, r0)
- case ACMP:
- opset(ATEQ, r0)
- opset(ACMN, r0)
- opset(ATST, r0)
- case AMVN:
- break
- case ABEQ:
- opset(ABNE, r0)
- opset(ABCS, r0)
- opset(ABHS, r0)
- opset(ABCC, r0)
- opset(ABLO, r0)
- opset(ABMI, r0)
- opset(ABPL, r0)
- opset(ABVS, r0)
- opset(ABVC, r0)
- opset(ABHI, r0)
- opset(ABLS, r0)
- opset(ABGE, r0)
- opset(ABLT, r0)
- opset(ABGT, r0)
- opset(ABLE, r0)
- case ASLL:
- opset(ASRL, r0)
- opset(ASRA, r0)
- case AMUL:
- opset(AMULU, r0)
- case ADIV:
- opset(AMOD, r0)
- opset(AMODU, r0)
- opset(ADIVU, r0)
- case ADIVHW:
- opset(ADIVUHW, r0)
- case AMOVW,
- AMOVB,
- AMOVBS,
- AMOVBU,
- AMOVH,
- AMOVHS,
- AMOVHU:
- break
- case ASWPW:
- opset(ASWPBU, r0)
- case AB,
- ABL,
- ABX,
- ABXRET,
- obj.ADUFFZERO,
- obj.ADUFFCOPY,
- ASWI,
- AWORD,
- AMOVM,
- ARFE,
- obj.ATEXT:
- break
- case AADDF:
- opset(AADDD, r0)
- opset(ASUBF, r0)
- opset(ASUBD, r0)
- opset(AMULF, r0)
- opset(AMULD, r0)
- opset(ANMULF, r0)
- opset(ANMULD, r0)
- opset(AMULAF, r0)
- opset(AMULAD, r0)
- opset(AMULSF, r0)
- opset(AMULSD, r0)
- opset(ANMULAF, r0)
- opset(ANMULAD, r0)
- opset(ANMULSF, r0)
- opset(ANMULSD, r0)
- opset(AFMULAF, r0)
- opset(AFMULAD, r0)
- opset(AFMULSF, r0)
- opset(AFMULSD, r0)
- opset(AFNMULAF, r0)
- opset(AFNMULAD, r0)
- opset(AFNMULSF, r0)
- opset(AFNMULSD, r0)
- opset(ADIVF, r0)
- opset(ADIVD, r0)
- case ANEGF:
- opset(ANEGD, r0)
- opset(ASQRTF, r0)
- opset(ASQRTD, r0)
- opset(AMOVFD, r0)
- opset(AMOVDF, r0)
- opset(AABSF, r0)
- opset(AABSD, r0)
- case ACMPF:
- opset(ACMPD, r0)
- case AMOVF:
- opset(AMOVD, r0)
- case AMOVFW:
- opset(AMOVDW, r0)
- case AMOVWF:
- opset(AMOVWD, r0)
- case AMULL:
- opset(AMULAL, r0)
- opset(AMULLU, r0)
- opset(AMULALU, r0)
- case AMULWT:
- opset(AMULWB, r0)
- opset(AMULBB, r0)
- opset(AMMUL, r0)
- case AMULAWT:
- opset(AMULAWB, r0)
- opset(AMULABB, r0)
- opset(AMULS, r0)
- opset(AMMULA, r0)
- opset(AMMULS, r0)
- case ABFX:
- opset(ABFXU, r0)
- opset(ABFC, r0)
- opset(ABFI, r0)
- case ACLZ:
- opset(AREV, r0)
- opset(AREV16, r0)
- opset(AREVSH, r0)
- opset(ARBIT, r0)
- case AXTAB:
- opset(AXTAH, r0)
- opset(AXTABU, r0)
- opset(AXTAHU, r0)
- case ALDREX,
- ASTREX,
- ALDREXD,
- ASTREXD,
- ADMB,
- APLD,
- AAND,
- AMULA,
- obj.AUNDEF,
- obj.AFUNCDATA,
- obj.APCDATA,
- obj.ANOP:
- break
- }
- }
- }
- func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
- c.printp = p
- o1 := uint32(0)
- o2 := uint32(0)
- o3 := uint32(0)
- o4 := uint32(0)
- o5 := uint32(0)
- o6 := uint32(0)
- if false { /*debug['P']*/
- fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
- }
- switch o.type_ {
- default:
- c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
- case 0: /* pseudo ops */
- if false { /*debug['G']*/
- fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
- }
- case 1: /* op R,[R],R */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- case 2: /* movbu $I,[R],R */
- c.aclass(&p.From)
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= uint32(immrot(uint32(c.instoffset)))
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- case 106: /* op $I,R,R where I can be decomposed into 2 immediates */
- c.aclass(&p.From)
- r := int(p.Reg)
- rt := int(p.To.Reg)
- if r == 0 {
- r = rt
- }
- x, y := immrot2a(uint32(c.instoffset))
- var as2 obj.As
- switch p.As {
- case AADD, ASUB, AORR, AEOR, ABIC:
- as2 = p.As // ADD, SUB, ORR, EOR, BIC
- case ARSB:
- as2 = AADD // RSB -> RSB/ADD pair
- case AADC:
- as2 = AADD // ADC -> ADC/ADD pair
- case ASBC:
- as2 = ASUB // SBC -> SBC/SUB pair
- case ARSC:
- as2 = AADD // RSC -> RSC/ADD pair
- default:
- c.ctxt.Diag("unknown second op for %v", p)
- }
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o2 = c.oprrr(p, as2, int(p.Scond))
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
- o1 |= x
- o2 |= y
- case 107: /* op $I,R,R where I can be decomposed into 2 immediates */
- c.aclass(&p.From)
- r := int(p.Reg)
- rt := int(p.To.Reg)
- if r == 0 {
- r = rt
- }
- y, x := immrot2s(uint32(c.instoffset))
- var as2 obj.As
- switch p.As {
- case AADD:
- as2 = ASUB // ADD -> ADD/SUB pair
- case ASUB:
- as2 = AADD // SUB -> SUB/ADD pair
- case ARSB:
- as2 = ASUB // RSB -> RSB/SUB pair
- case AADC:
- as2 = ASUB // ADC -> ADC/SUB pair
- case ASBC:
- as2 = AADD // SBC -> SBC/ADD pair
- case ARSC:
- as2 = ASUB // RSC -> RSC/SUB pair
- default:
- c.ctxt.Diag("unknown second op for %v", p)
- }
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o2 = c.oprrr(p, as2, int(p.Scond))
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12
- o1 |= y
- o2 |= x
- case 3: /* add R<<[IR],[R],R */
- o1 = c.mov(p)
- case 4: /* MOVW $off(R), R -> add $off,[R],R */
- c.aclass(&p.From)
- if c.instoffset < 0 {
- o1 = c.oprrr(p, ASUB, int(p.Scond))
- o1 |= uint32(immrot(uint32(-c.instoffset)))
- } else {
- o1 = c.oprrr(p, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(c.instoffset)))
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 |= (uint32(r) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 5: /* bra s */
- o1 = c.opbra(p, p.As, int(p.Scond))
- v := int32(-8)
- if p.To.Sym != nil {
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- v += int32(p.To.Offset)
- rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
- rel.Type = objabi.R_CALLARM
- break
- }
- if p.To.Target() != nil {
- v = int32((p.To.Target().Pc - c.pc) - 8)
- }
- o1 |= (uint32(v) >> 2) & 0xffffff
- case 6: /* b ,O(R) -> add $O,R,PC */
- c.aclass(&p.To)
- o1 = c.oprrr(p, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(c.instoffset)))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (REGPC & 15) << 12
- case 7: /* bl (R) -> blx R */
- c.aclass(&p.To)
- if c.instoffset != 0 {
- c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset)
- }
- o1 = c.oprrr(p, ABL, int(p.Scond))
- o1 |= (uint32(p.To.Reg) & 15) << 0
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 0
- rel.Type = objabi.R_CALLIND
- case 8: /* sll $c,[R],R -> mov (R<<$c),R */
- c.aclass(&p.From)
- o1 = c.oprrr(p, p.As, int(p.Scond))
- r := int(p.Reg)
- if r == 0 {
- r = int(p.To.Reg)
- }
- o1 |= (uint32(r) & 15) << 0
- o1 |= uint32((c.instoffset & 31) << 7)
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- r := int(p.Reg)
- if r == 0 {
- r = int(p.To.Reg)
- }
- o1 |= (uint32(r) & 15) << 0
- o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 10: /* swi [$con] */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- if p.To.Type != obj.TYPE_NONE {
- c.aclass(&p.To)
- o1 |= uint32(c.instoffset & 0xffffff)
- }
- case 11: /* word */
- c.aclass(&p.To)
- o1 = uint32(c.instoffset)
- if p.To.Sym != nil {
- // This case happens with words generated
- // in the PC stream as part of the literal pool (c.pool).
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- if c.ctxt.Flag_shared {
- if p.To.Name == obj.NAME_GOTREF {
- rel.Type = objabi.R_GOTPCREL
- } else {
- rel.Type = objabi.R_PCREL
- }
- rel.Add += c.pc - p.Rel.Pc - 8
- } else {
- rel.Type = objabi.R_ADDR
- }
- o1 = 0
- }
- case 12: /* movw $lcon, reg */
- if o.a1 == C_SCON {
- o1 = c.omvs(p, &p.From, int(p.To.Reg))
- } else if p.As == AMVN {
- o1 = c.omvr(p, &p.From, int(p.To.Reg))
- } else {
- o1 = c.omvl(p, &p.From, int(p.To.Reg))
- }
- if o.flag&LPCREL != 0 {
- o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
- }
- case 13: /* op $lcon, [R], R */
- if o.a1 == C_SCON {
- o1 = c.omvs(p, &p.From, REGTMP)
- } else {
- o1 = c.omvl(p, &p.From, REGTMP)
- }
- if o1 == 0 {
- break
- }
- o2 = c.oprrr(p, p.As, int(p.Scond))
- o2 |= REGTMP & 15
- r := int(p.Reg)
- if p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = int(p.To.Reg)
- }
- o2 |= (uint32(r) & 15) << 16
- if p.To.Type != obj.TYPE_NONE {
- o2 |= (uint32(p.To.Reg) & 15) << 12
- }
- case 14: /* movb/movbu/movh/movhu R,R */
- o1 = c.oprrr(p, ASLL, int(p.Scond))
- if p.As == AMOVBU || p.As == AMOVHU {
- o2 = c.oprrr(p, ASRL, int(p.Scond))
- } else {
- o2 = c.oprrr(p, ASRA, int(p.Scond))
- }
- r := int(p.To.Reg)
- o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
- o2 |= uint32(r)&15 | (uint32(r)&15)<<12
- if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
- o1 |= 24 << 7
- o2 |= 24 << 7
- } else {
- o1 |= 16 << 7
- o2 |= 16 << 7
- }
- case 15: /* mul r,[r,]r */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
- case 16: /* div r,[r,]r */
- o1 = 0xf << 28
- o2 = 0
- case 17:
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- rt2 := int(p.To.Offset)
- r := int(p.Reg)
- o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
- case 18: /* BFX/BFXU/BFC/BFI */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- } else if p.As == ABFC { // only "BFC $width, $lsb, Reg" is accepted, p.Reg must be 0
- c.ctxt.Diag("illegal combination: %v", p)
- }
- if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST {
- c.ctxt.Diag("%v: missing or wrong LSB", p)
- break
- }
- lsb := p.GetFrom3().Offset
- width := p.From.Offset
- if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 32 {
- c.ctxt.Diag("%v: wrong width or LSB", p)
- }
- switch p.As {
- case ABFX, ABFXU: // (width-1) is encoded
- o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16
- case ABFC, ABFI: // MSB is encoded
- o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16
- default:
- c.ctxt.Diag("illegal combination: %v", p)
- }
- case 20: /* mov/movb/movbu R,O(R) */
- c.aclass(&p.To)
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
- case 21: /* mov/movbu O(R),R -> lr */
- c.aclass(&p.From)
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
- if p.As != AMOVW {
- o1 |= 1 << 22
- }
- case 22: /* XTAB R@>i, [R], R */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- switch p.From.Offset &^ 0xf {
- // only 0/8/16/24 bits rotation is accepted
- case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
- o1 |= uint32(p.From.Offset) & 0xc0f
- default:
- c.ctxt.Diag("illegal shift: %v", p)
- }
- rt := p.To.Reg
- r := p.Reg
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16
- case 23: /* MOVW/MOVB/MOVH R@>i, R */
- switch p.As {
- case AMOVW:
- o1 = c.mov(p)
- case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH:
- o1 = c.movxt(p)
- default:
- c.ctxt.Diag("illegal combination: %v", p)
- }
- case 30: /* mov/movb/movbu R,L(R) */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
- if p.As != AMOVW {
- o2 |= 1 << 22
- }
- case 31: /* mov/movbu L(R),R -> lr[b] */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
- o2 |= 1 << 22
- }
- case 34: /* mov $lacon,R */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.oprrr(p, AADD, int(p.Scond))
- o2 |= REGTMP & 15
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 |= (uint32(r) & 15) << 16
- if p.To.Type != obj.TYPE_NONE {
- o2 |= (uint32(p.To.Reg) & 15) << 12
- }
- case 35: /* mov PSR,R */
- o1 = 2<<23 | 0xf<<16 | 0<<0
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.From.Reg) & 1) << 22
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 36: /* mov R,PSR */
- o1 = 2<<23 | 0x2cf<<12 | 0<<4
- if p.Scond&C_FBIT != 0 {
- o1 ^= 0x010 << 12
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.To.Reg) & 1) << 22
- o1 |= (uint32(p.From.Reg) & 15) << 0
- case 37: /* mov $con,PSR */
- c.aclass(&p.From)
- o1 = 2<<23 | 0x2cf<<12 | 0<<4
- if p.Scond&C_FBIT != 0 {
- o1 ^= 0x010 << 12
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= uint32(immrot(uint32(c.instoffset)))
- o1 |= (uint32(p.To.Reg) & 1) << 22
- o1 |= (uint32(p.From.Reg) & 15) << 0
- case 38, 39:
- switch o.type_ {
- case 38: /* movm $con,oreg -> stm */
- o1 = 0x4 << 25
- o1 |= uint32(p.From.Offset & 0xffff)
- o1 |= (uint32(p.To.Reg) & 15) << 16
- c.aclass(&p.To)
- case 39: /* movm oreg,$con -> ldm */
- o1 = 0x4<<25 | 1<<20
- o1 |= uint32(p.To.Offset & 0xffff)
- o1 |= (uint32(p.From.Reg) & 15) << 16
- c.aclass(&p.From)
- }
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in MOVM; %v", p)
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- if p.Scond&C_PBIT != 0 {
- o1 |= 1 << 24
- }
- if p.Scond&C_UBIT != 0 {
- o1 |= 1 << 23
- }
- if p.Scond&C_WBIT != 0 {
- o1 |= 1 << 21
- }
- case 40: /* swp oreg,reg,reg */
- c.aclass(&p.From)
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in SWP")
- }
- o1 = 0x2<<23 | 0x9<<4
- if p.As != ASWPW {
- o1 |= 1 << 22
- }
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
- o1 = 0xe8fd8000
- case 50: /* floating point store */
- v := c.regoff(&p.To)
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p)
- case 51: /* floating point load */
- v := c.regoff(&p.From)
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
- case 52: /* floating point store, int32 offset UGLY */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
- o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
- case 53: /* floating point load, int32 offset UGLY */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
- o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
- case 54: /* floating point arith */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- switch p.As {
- case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD,
- AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD:
- c.ctxt.Diag("illegal combination: %v", p)
- default:
- r = rt
- }
- }
- o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- case 55: /* negf freg, freg */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12
- case 56: /* move to FP[CS]R */
- o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4
- o1 |= (uint32(p.From.Reg) & 15) << 12
- case 57: /* move from FP[CS]R */
- o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 58: /* movbu R,R */
- o1 = c.oprrr(p, AAND, int(p.Scond))
- o1 |= uint32(immrot(0xff))
- rt := int(p.To.Reg)
- r := int(p.From.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if p.From.Reg == 0 {
- c.ctxt.Diag("source operand is not a memory address: %v", p)
- break
- }
- if p.From.Offset&(1<<4) != 0 {
- c.ctxt.Diag("bad shift in LDR")
- break
- }
- o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU {
- o1 |= 1 << 22
- }
- case 60: /* movb R(R),R -> ldrsb indexed */
- if p.From.Reg == 0 {
- c.ctxt.Diag("source operand is not a memory address: %v", p)
- break
- }
- if p.From.Offset&(^0xf) != 0 {
- c.ctxt.Diag("bad shift: %v", p)
- break
- }
- o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
- switch p.As {
- case AMOVB, AMOVBS:
- o1 ^= 1<<5 | 1<<6
- case AMOVH, AMOVHS:
- o1 ^= 1 << 6
- default:
- }
- if p.Scond&C_UBIT != 0 {
- o1 &^= 1 << 23
- }
- case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
- if p.To.Reg == 0 {
- c.ctxt.Diag("MOV to shifter operand")
- }
- o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
- o1 |= 1 << 22
- }
- case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */
- if p.To.Reg == 0 {
- c.ctxt.Diag("MOV to shifter operand")
- }
- if p.To.Offset&(^0xf) != 0 {
- c.ctxt.Diag("bad shift: %v", p)
- }
- o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond))
- o1 ^= 1 << 20
- if p.Scond&C_UBIT != 0 {
- o1 &^= 1 << 23
- }
- /* reloc ops */
- case 64: /* mov/movb/movbu R,addr */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- case 65: /* mov/movbu addr,R */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
- o2 |= 1 << 22
- }
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- case 101: /* movw tlsvar,R, local exec*/
- o1 = c.omvl(p, &p.From, int(p.To.Reg))
- case 102: /* movw tlsvar,R, initial exec*/
- o1 = c.omvl(p, &p.From, int(p.To.Reg))
- o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
- case 103: /* word tlsvar, local exec */
- if p.To.Sym == nil {
- c.ctxt.Diag("nil sym in tls %v", p)
- }
- if p.To.Offset != 0 {
- c.ctxt.Diag("offset against tls var in %v", p)
- }
- // This case happens with words generated in the PC stream as part of
- // the literal c.pool.
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Type = objabi.R_TLS_LE
- o1 = 0
- case 104: /* word tlsvar, initial exec */
- if p.To.Sym == nil {
- c.ctxt.Diag("nil sym in tls %v", p)
- }
- if p.To.Offset != 0 {
- c.ctxt.Diag("offset against tls var in %v", p)
- }
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Type = objabi.R_TLS_IE
- rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz)
- case 68: /* floating point store -> ADDR */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- case 69: /* floating point load <- ADDR */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- c.aclass(&p.To)
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond))
- case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
- c.aclass(&p.From)
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o1 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o1 ^= (1 << 6)
- }
- case 72: /* movh/movhu R,L(R) -> strh */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond))
- case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o2 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o2 ^= (1 << 6)
- }
- case 74: /* bx $I */
- c.ctxt.Diag("ABX $I")
- case 75: /* bx O(R) */
- c.aclass(&p.To)
- if c.instoffset != 0 {
- c.ctxt.Diag("non-zero offset in ABX")
- }
- /*
- o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
- o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R
- */
- // p->to.reg may be REGLINK
- o1 = c.oprrr(p, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(c.instoffset)))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (REGTMP & 15) << 12
- o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
- o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp
- case 76: /* bx O(R) when returning from fn*/
- c.ctxt.Diag("ABXRET")
- case 77: /* ldrex oreg,reg */
- c.aclass(&p.From)
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in LDREX")
- }
- o1 = 0x19<<20 | 0xf9f
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 78: /* strex reg,oreg,reg */
- c.aclass(&p.From)
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in STREX")
- }
- if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg {
- c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
- }
- o1 = 0x18<<20 | 0xf90
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 80: /* fmov zfcon,freg */
- if p.As == AMOVD {
- o1 = 0xeeb00b00 // VMOV imm 64
- o2 = c.oprrr(p, ASUBD, int(p.Scond))
- } else {
- o1 = 0x0eb00a00 // VMOV imm 32
- o2 = c.oprrr(p, ASUBF, int(p.Scond))
- }
- v := int32(0x70) // 1.0
- r := (int(p.To.Reg) & 15) << 0
- // movf $1.0, r
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(r) & 15) << 12
- o1 |= (uint32(v) & 0xf) << 0
- o1 |= (uint32(v) & 0xf0) << 12
- // subf r,r,r
- o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
- case 81: /* fmov sfcon,freg */
- o1 = 0x0eb00a00 // VMOV imm 32
- if p.As == AMOVD {
- o1 = 0xeeb00b00 // VMOV imm 64
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.To.Reg) & 15) << 12
- v := int32(c.chipfloat5(p.From.Val.(float64)))
- o1 |= (uint32(v) & 0xf) << 0
- o1 |= (uint32(v) & 0xf0) << 12
- case 82: /* fcmp freg,freg, */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
- o2 = 0x0ef1fa10 // VMRS R15
- o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 83: /* fcmp freg,, */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
- o2 = 0x0ef1fa10 // VMRS R15
- o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- // macro for movfw freg,FTMP; movw FTMP,reg
- case 86: /* movfw freg,reg - truncate float-to-fix */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (FREGTMP & 15) << 12
- o2 = c.oprrr(p, -AMOVFW, int(p.Scond))
- o2 |= (FREGTMP & 15) << 16
- o2 |= (uint32(p.To.Reg) & 15) << 12
- // macro for movw reg,FTMP; movwf FTMP,freg
- case 87: /* movwf reg,freg - fix-to-float */
- o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 12
- o1 |= (FREGTMP & 15) << 16
- o2 = c.oprrr(p, p.As, int(p.Scond))
- o2 |= (FREGTMP & 15) << 0
- o2 |= (uint32(p.To.Reg) & 15) << 12
- case 88: /* movw reg,freg */
- o1 = c.oprrr(p, -AMOVWF, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 12
- o1 |= (uint32(p.To.Reg) & 15) << 16
- case 89: /* movw freg,reg */
- o1 = c.oprrr(p, -AMOVFW, int(p.Scond))
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- case 91: /* ldrexd oreg,reg */
- c.aclass(&p.From)
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in LDREX")
- }
- o1 = 0x1b<<20 | 0xf9f
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 92: /* strexd reg,oreg,reg */
- c.aclass(&p.From)
- if c.instoffset != 0 {
- c.ctxt.Diag("offset must be zero in STREX")
- }
- if p.Reg&1 != 0 {
- c.ctxt.Diag("source register must be even in STREXD: %v", p)
- }
- if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 {
- c.ctxt.Diag("cannot use same register as both source and destination: %v", p)
- }
- o1 = 0x1a<<20 | 0xf90
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
- o1 = c.omvl(p, &p.From, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o2 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o2 ^= (1 << 6)
- }
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- case 94: /* movh/movhu R,addr -> strh */
- o1 = c.omvl(p, &p.To, REGTMP)
- if o1 == 0 {
- break
- }
- o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond))
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
- case 95: /* PLD off(reg) */
- o1 = 0xf5d0f000
- o1 |= (uint32(p.From.Reg) & 15) << 16
- if p.From.Offset < 0 {
- o1 &^= (1 << 23)
- o1 |= uint32((-p.From.Offset) & 0xfff)
- } else {
- o1 |= uint32(p.From.Offset & 0xfff)
- }
- // This is supposed to be something that stops execution.
- // It's not supposed to be reached, ever, but if it is, we'd
- // like to be able to tell how we got there. Assemble as
- // 0xf7fabcfd which is guaranteed to raise undefined instruction
- // exception.
- case 96: /* UNDEF */
- o1 = 0xf7fabcfd
- case 97: /* CLZ Rm, Rd */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= (uint32(p.From.Reg) & 15) << 0
- case 98: /* MULW{T,B} Rs, Rm, Rd */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (uint32(p.From.Reg) & 15) << 8
- o1 |= (uint32(p.Reg) & 15) << 0
- case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (uint32(p.From.Reg) & 15) << 8
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= uint32((p.To.Offset & 15) << 12)
- case 105: /* divhw r,[r,]r */
- o1 = c.oprrr(p, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
- case 110: /* dmb [mbop | $con] */
- o1 = 0xf57ff050
- mbop := uint32(0)
- switch c.aclass(&p.From) {
- case C_SPR:
- for _, f := range mbOp {
- if f.reg == p.From.Reg {
- mbop = f.enc
- break
- }
- }
- case C_RCON:
- for _, f := range mbOp {
- enc := uint32(c.instoffset)
- if f.enc == enc {
- mbop = enc
- break
- }
- }
- case C_NONE:
- mbop = 0xf
- }
- if mbop == 0 {
- c.ctxt.Diag("illegal mb option:\n%v", p)
- }
- o1 |= mbop
- }
- out[0] = o1
- out[1] = o2
- out[2] = o3
- out[3] = o4
- out[4] = o5
- out[5] = o6
- }
- func (c *ctxt5) movxt(p *obj.Prog) uint32 {
- o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- switch p.As {
- case AMOVB, AMOVBS:
- o1 |= 0x6af<<16 | 0x7<<4
- case AMOVH, AMOVHS:
- o1 |= 0x6bf<<16 | 0x7<<4
- case AMOVBU:
- o1 |= 0x6ef<<16 | 0x7<<4
- case AMOVHU:
- o1 |= 0x6ff<<16 | 0x7<<4
- default:
- c.ctxt.Diag("illegal combination: %v", p)
- }
- switch p.From.Offset &^ 0xf {
- // only 0/8/16/24 bits rotation is accepted
- case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7:
- o1 |= uint32(p.From.Offset) & 0xc0f
- default:
- c.ctxt.Diag("illegal shift: %v", p)
- }
- o1 |= (uint32(p.To.Reg) & 15) << 12
- return o1
- }
- func (c *ctxt5) mov(p *obj.Prog) uint32 {
- c.aclass(&p.From)
- o1 := c.oprrr(p, p.As, int(p.Scond))
- o1 |= uint32(p.From.Offset)
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- r := int(p.Reg)
- if p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- return o1
- }
- func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 {
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_SBIT != 0 {
- o |= 1 << 20
- }
- switch a {
- case ADIVHW:
- return o | 0x71<<20 | 0xf<<12 | 0x1<<4
- case ADIVUHW:
- return o | 0x73<<20 | 0xf<<12 | 0x1<<4
- case AMMUL:
- return o | 0x75<<20 | 0xf<<12 | 0x1<<4
- case AMULS:
- return o | 0x6<<20 | 0x9<<4
- case AMMULA:
- return o | 0x75<<20 | 0x1<<4
- case AMMULS:
- return o | 0x75<<20 | 0xd<<4
- case AMULU, AMUL:
- return o | 0x0<<21 | 0x9<<4
- case AMULA:
- return o | 0x1<<21 | 0x9<<4
- case AMULLU:
- return o | 0x4<<21 | 0x9<<4
- case AMULL:
- return o | 0x6<<21 | 0x9<<4
- case AMULALU:
- return o | 0x5<<21 | 0x9<<4
- case AMULAL:
- return o | 0x7<<21 | 0x9<<4
- case AAND:
- return o | 0x0<<21
- case AEOR:
- return o | 0x1<<21
- case ASUB:
- return o | 0x2<<21
- case ARSB:
- return o | 0x3<<21
- case AADD:
- return o | 0x4<<21
- case AADC:
- return o | 0x5<<21
- case ASBC:
- return o | 0x6<<21
- case ARSC:
- return o | 0x7<<21
- case ATST:
- return o | 0x8<<21 | 1<<20
- case ATEQ:
- return o | 0x9<<21 | 1<<20
- case ACMP:
- return o | 0xa<<21 | 1<<20
- case ACMN:
- return o | 0xb<<21 | 1<<20
- case AORR:
- return o | 0xc<<21
- case AMOVB, AMOVH, AMOVW:
- if sc&(C_PBIT|C_WBIT) != 0 {
- c.ctxt.Diag("invalid .P/.W suffix: %v", p)
- }
- return o | 0xd<<21
- case ABIC:
- return o | 0xe<<21
- case AMVN:
- return o | 0xf<<21
- case ASLL:
- return o | 0xd<<21 | 0<<5
- case ASRL:
- return o | 0xd<<21 | 1<<5
- case ASRA:
- return o | 0xd<<21 | 2<<5
- case ASWI:
- return o | 0xf<<24
- case AADDD:
- return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
- case AADDF:
- return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
- case ASUBD:
- return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
- case ASUBF:
- return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
- case AMULD:
- return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
- case AMULF:
- return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
- case ANMULD:
- return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4
- case ANMULF:
- return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4
- case AMULAD:
- return o | 0xe<<24 | 0xb<<8
- case AMULAF:
- return o | 0xe<<24 | 0xa<<8
- case AMULSD:
- return o | 0xe<<24 | 0xb<<8 | 0x4<<4
- case AMULSF:
- return o | 0xe<<24 | 0xa<<8 | 0x4<<4
- case ANMULAD:
- return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4
- case ANMULAF:
- return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4
- case ANMULSD:
- return o | 0xe<<24 | 0x1<<20 | 0xb<<8
- case ANMULSF:
- return o | 0xe<<24 | 0x1<<20 | 0xa<<8
- case AFMULAD:
- return o | 0xe<<24 | 0xa<<20 | 0xb<<8
- case AFMULAF:
- return o | 0xe<<24 | 0xa<<20 | 0xa<<8
- case AFMULSD:
- return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4
- case AFMULSF:
- return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4
- case AFNMULAD:
- return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4
- case AFNMULAF:
- return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4
- case AFNMULSD:
- return o | 0xe<<24 | 0x9<<20 | 0xb<<8
- case AFNMULSF:
- return o | 0xe<<24 | 0x9<<20 | 0xa<<8
- case ADIVD:
- return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
- case ADIVF:
- return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
- case ASQRTD:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
- case ASQRTF:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
- case AABSD:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
- case AABSF:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
- case ANEGD:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
- case ANEGF:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
- case ACMPD:
- return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
- case ACMPF:
- return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
- case AMOVF:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
- case AMOVD:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
- case AMOVDF:
- return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
- case AMOVFD:
- return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
- case AMOVWF:
- if sc&C_UBIT == 0 {
- o |= 1 << 7 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
- case AMOVWD:
- if sc&C_UBIT == 0 {
- o |= 1 << 7 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
- case AMOVFW:
- if sc&C_UBIT == 0 {
- o |= 1 << 16 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
- case AMOVDW:
- if sc&C_UBIT == 0 {
- o |= 1 << 16 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
- case -AMOVWF: // copy WtoF
- return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
- case -AMOVFW: // copy FtoW
- return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
- case -ACMP: // cmp imm
- return o | 0x3<<24 | 0x5<<20
- case ABFX:
- return o | 0x3d<<21 | 0x5<<4
- case ABFXU:
- return o | 0x3f<<21 | 0x5<<4
- case ABFC:
- return o | 0x3e<<21 | 0x1f
- case ABFI:
- return o | 0x3e<<21 | 0x1<<4
- case AXTAB:
- return o | 0x6a<<20 | 0x7<<4
- case AXTAH:
- return o | 0x6b<<20 | 0x7<<4
- case AXTABU:
- return o | 0x6e<<20 | 0x7<<4
- case AXTAHU:
- return o | 0x6f<<20 | 0x7<<4
- // CLZ doesn't support .nil
- case ACLZ:
- return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
- case AREV:
- return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4
- case AREV16:
- return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4
- case AREVSH:
- return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4
- case ARBIT:
- return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4
- case AMULWT:
- return o&(0xf<<28) | 0x12<<20 | 0xe<<4
- case AMULWB:
- return o&(0xf<<28) | 0x12<<20 | 0xa<<4
- case AMULBB:
- return o&(0xf<<28) | 0x16<<20 | 0x8<<4
- case AMULAWT:
- return o&(0xf<<28) | 0x12<<20 | 0xc<<4
- case AMULAWB:
- return o&(0xf<<28) | 0x12<<20 | 0x8<<4
- case AMULABB:
- return o&(0xf<<28) | 0x10<<20 | 0x8<<4
- case ABL: // BLX REG
- return o&(0xf<<28) | 0x12fff3<<4
- }
- c.ctxt.Diag("%v: bad rrr %d", p, a)
- return 0
- }
- func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 {
- sc &= C_SCOND
- sc ^= C_SCOND_XOR
- if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
- return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
- }
- if sc != 0xe {
- c.ctxt.Diag("%v: .COND on bcond instruction", p)
- }
- switch a {
- case ABEQ:
- return 0x0<<28 | 0x5<<25
- case ABNE:
- return 0x1<<28 | 0x5<<25
- case ABCS:
- return 0x2<<28 | 0x5<<25
- case ABHS:
- return 0x2<<28 | 0x5<<25
- case ABCC:
- return 0x3<<28 | 0x5<<25
- case ABLO:
- return 0x3<<28 | 0x5<<25
- case ABMI:
- return 0x4<<28 | 0x5<<25
- case ABPL:
- return 0x5<<28 | 0x5<<25
- case ABVS:
- return 0x6<<28 | 0x5<<25
- case ABVC:
- return 0x7<<28 | 0x5<<25
- case ABHI:
- return 0x8<<28 | 0x5<<25
- case ABLS:
- return 0x9<<28 | 0x5<<25
- case ABGE:
- return 0xa<<28 | 0x5<<25
- case ABLT:
- return 0xb<<28 | 0x5<<25
- case ABGT:
- return 0xc<<28 | 0x5<<25
- case ABLE:
- return 0xd<<28 | 0x5<<25
- case AB:
- return 0xe<<28 | 0x5<<25
- }
- c.ctxt.Diag("%v: bad bra %v", p, a)
- return 0
- }
- func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 {
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_UBIT == 0 {
- o |= 1 << 23
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 1<<26 | 1<<20
- if v < 0 {
- if sc&C_UBIT != 0 {
- c.ctxt.Diag(".U on neg offset")
- }
- v = -v
- o ^= 1 << 23
- }
- if v >= 1<<12 || v < 0 {
- c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
- }
- o |= uint32(v)
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
- return o
- }
- func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 {
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 1<<23 | 1<<20 | 0xb<<4
- if v < 0 {
- v = -v
- o ^= 1 << 23
- }
- if v >= 1<<8 || v < 0 {
- c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp)
- }
- o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
- return o
- }
- func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 {
- o := c.olr(v, b, r, sc) ^ (1 << 20)
- if a != AMOVW {
- o |= 1 << 22
- }
- return o
- }
- func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 {
- o := c.olhr(v, b, r, sc) ^ (1 << 20)
- return o
- }
- func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 {
- return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20)
- }
- func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 {
- return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20)
- }
- func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 {
- return c.olr(int32(i), b, r, sc) ^ (1 << 25)
- }
- func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 {
- return c.olhr(int32(i), b, r, sc) ^ (1 << 22)
- }
- func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
- if v < 0 {
- v = -v
- o ^= 1 << 23
- }
- if v&3 != 0 {
- c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
- } else if v >= 1<<10 || v < 0 {
- c.ctxt.Diag("literal span too large: %d\n%v", v, p)
- }
- o |= (uint32(v) >> 2) & 0xFF
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
- switch a {
- default:
- c.ctxt.Diag("bad fst %v", a)
- fallthrough
- case AMOVD:
- o |= 1 << 8
- fallthrough
- case AMOVF:
- break
- }
- return o
- }
- // MOVW $"lower 16-bit", Reg
- func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 {
- o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= 0x30 << 20
- o1 |= (uint32(dr) & 15) << 12
- o1 |= uint32(a.Offset) & 0x0fff
- o1 |= (uint32(a.Offset) & 0xf000) << 4
- return o1
- }
- // MVN $C_NCON, Reg -> MOVW $C_RCON, Reg
- func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 {
- o1 := c.oprrr(p, AMOVW, int(p.Scond))
- o1 |= (uint32(dr) & 15) << 12
- v := immrot(^uint32(a.Offset))
- if v == 0 {
- c.ctxt.Diag("%v: missing literal", p)
- return 0
- }
- o1 |= uint32(v)
- return o1
- }
- func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 {
- var o1 uint32
- if p.Pool == nil {
- c.aclass(a)
- v := immrot(^uint32(c.instoffset))
- if v == 0 {
- c.ctxt.Diag("%v: missing literal", p)
- return 0
- }
- o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND)
- o1 |= uint32(v)
- o1 |= (uint32(dr) & 15) << 12
- } else {
- v := int32(p.Pool.Pc - p.Pc - 8)
- o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND)
- }
- return o1
- }
- func (c *ctxt5) chipzero5(e float64) int {
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if objabi.GOARM < 7 || math.Float64bits(e) != 0 {
- return -1
- }
- return 0
- }
- func (c *ctxt5) chipfloat5(e float64) int {
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if objabi.GOARM < 7 {
- return -1
- }
- ei := math.Float64bits(e)
- l := uint32(ei)
- h := uint32(ei >> 32)
- if l != 0 || h&0xffff != 0 {
- return -1
- }
- h1 := h & 0x7fc00000
- if h1 != 0x40000000 && h1 != 0x3fc00000 {
- return -1
- }
- n := 0
- // sign bit (a)
- if h&0x80000000 != 0 {
- n |= 1 << 7
- }
- // exp sign bit (b)
- if h1 == 0x3fc00000 {
- n |= 1 << 6
- }
- // rest of exp and mantissa (cd-efgh)
- n |= int((h >> 16) & 0x3f)
- //print("match %.8lux %.8lux %d\n", l, h, n);
- return n
- }
- func nocache(p *obj.Prog) {
- p.Optab = 0
- p.From.Class = 0
- if p.GetFrom3() != nil {
- p.GetFrom3().Class = 0
- }
- p.To.Class = 0
- }
|