cgcpu.pas 220 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,cg64f32,rgcpu;
  27. type
  28. { tbasecgarm is shared between all arm architectures }
  29. tbasecgarm = class(tcg)
  30. { true, if the next arithmetic operation should modify the flags }
  31. cgsetflags : boolean;
  32. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  33. protected
  34. procedure a_load_ref_cgparalocref(list: TAsmList; sourcesize: tcgsize; sizeleft: tcgint; const ref, paralocref: treference; const cgpara: tcgpara; const location: PCGParaLocation); override;
  35. public
  36. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  37. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  38. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  39. { move instructions }
  40. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  41. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  42. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  43. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  44. { fpu move instructions }
  45. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  46. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  47. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  48. procedure g_check_for_fpu_exception(list : TAsmList; force,clear : boolean); override;
  49. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  50. { comparison operations }
  51. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  52. l : tasmlabel);override;
  53. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  54. procedure a_jmp_name(list : TAsmList;const s : string); override;
  55. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  56. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  57. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  58. procedure g_profilecode(list : TAsmList); override;
  59. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  60. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  61. procedure g_maybe_got_init(list : TAsmList); override;
  62. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  63. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  64. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);override;
  65. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  66. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : tcgint;aligned : boolean);
  67. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  68. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  69. procedure g_save_registers(list : TAsmList);override;
  70. procedure g_restore_registers(list : TAsmList);override;
  71. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  72. procedure fixref(list : TAsmList;var ref : treference);
  73. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; virtual;
  74. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  75. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  76. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  77. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  78. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister; shuffle : pmmshuffle); override;
  79. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle); override;
  80. { Transform unsupported methods into Internal errors }
  81. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); override;
  82. { try to generate optimized 32 Bit multiplication, returns true if successful generated }
  83. function try_optimized_mul32_const_reg_reg(list: TAsmList; a: tcgint; src, dst: tregister) : boolean;
  84. { clear out potential overflow bits from 8 or 16 bit operations
  85. the upper 24/16 bits of a register after an operation }
  86. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  87. { mla for thumb requires that none of the registers is equal to r13/r15, this method ensures this }
  88. procedure safe_mla(list: TAsmList;op1,op2,op3,op4 : TRegister);
  89. procedure g_maybe_tls_init(list : TAsmList); override;
  90. end;
  91. { tcgarm is shared between normal arm and thumb-2 }
  92. tcgarm = class(tbasecgarm)
  93. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  94. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  95. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  96. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  97. size: tcgsize; a: tcgint; src, dst: tregister); override;
  98. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  99. size: tcgsize; src1, src2, dst: tregister); override;
  100. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  101. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  102. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  103. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  104. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  105. {Multiply two 32-bit registers into lo and hi 32-bit registers}
  106. procedure a_mul_reg_reg_pair(list: tasmlist; size: tcgsize; src1,src2,dstlo,dsthi: tregister); override;
  107. end;
  108. { normal arm cg }
  109. tarmcgarm = class(tcgarm)
  110. procedure init_register_allocators;override;
  111. procedure done_register_allocators;override;
  112. end;
  113. { 64 bit cg for all arm flavours }
  114. tbasecg64farm = class(tcg64f32)
  115. end;
  116. { tcg64farm is shared between normal arm and thumb-2 }
  117. tcg64farm = class(tbasecg64farm)
  118. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  119. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  120. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  121. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  122. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  123. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  124. procedure a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);override;
  125. procedure a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);override;
  126. end;
  127. tarmcg64farm = class(tcg64farm)
  128. end;
  129. tthumbcgarm = class(tbasecgarm)
  130. procedure init_register_allocators;override;
  131. procedure done_register_allocators;override;
  132. procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);override;
  133. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  134. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src,dst: TRegister);override;
  135. procedure a_op_const_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; dst: tregister);override;
  136. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
  137. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  138. procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const Ref: treference; reg: tregister);override;
  139. procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; reg: tregister);override;
  140. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  141. function handle_load_store(list: TAsmList; op: tasmop; oppostfix: toppostfix; reg: tregister; ref: treference): treference; override;
  142. end;
  143. tthumbcg64farm = class(tbasecg64farm)
  144. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  145. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  146. end;
  147. tthumb2cgarm = class(tcgarm)
  148. procedure init_register_allocators;override;
  149. procedure done_register_allocators;override;
  150. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  151. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  152. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  153. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  154. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  155. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  156. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  157. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  158. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  159. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; override;
  160. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  161. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  162. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  163. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  164. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister; shuffle : pmmshuffle); override;
  165. end;
  166. tthumb2cg64farm = class(tcg64farm)
  167. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  168. end;
  169. const
  170. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  171. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  172. winstackpagesize = 4096;
  173. function get_fpu_postfix(def : tdef) : toppostfix;
  174. procedure create_codegen;
  175. implementation
  176. uses
  177. globals,verbose,systems,cutils,
  178. aopt,aoptcpu,
  179. fmodule,
  180. symconst,symsym,symtable,
  181. tgobj,
  182. procinfo,cpupi,
  183. paramgr;
  184. { Range check must be disabled explicitly as conversions between signed and unsigned
  185. 32-bit values are done without explicit typecasts }
  186. {$R-}
  187. function get_fpu_postfix(def : tdef) : toppostfix;
  188. begin
  189. if def.typ=floatdef then
  190. begin
  191. case tfloatdef(def).floattype of
  192. s32real:
  193. result:=PF_S;
  194. s64real:
  195. result:=PF_D;
  196. s80real:
  197. result:=PF_E;
  198. else
  199. internalerror(200401272);
  200. end;
  201. end
  202. else
  203. internalerror(200401271);
  204. end;
  205. procedure tarmcgarm.init_register_allocators;
  206. begin
  207. inherited init_register_allocators;
  208. { currently, we always save R14, so we can use it }
  209. if (target_info.system<>system_arm_darwin) then
  210. begin
  211. if assigned(current_procinfo) and (current_procinfo.framepointer<>NR_R11) then
  212. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  213. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R12,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  214. RS_R9,RS_R10,RS_R11,RS_R14],first_int_imreg,[])
  215. else
  216. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  217. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R12,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  218. RS_R9,RS_R10,RS_R14],first_int_imreg,[])
  219. end
  220. else
  221. { r7 is not available on Darwin, it's used as frame pointer (always,
  222. for backtrace support -- also in gcc/clang -> R11 can be used).
  223. r9 is volatile }
  224. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  225. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R9,RS_R12,RS_R4,RS_R5,RS_R6,RS_R8,
  226. RS_R10,RS_R11,RS_R14],first_int_imreg,[]);
  227. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  228. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  229. { The register allocator currently cannot deal with multiple
  230. non-overlapping subregs per register, so we can only use
  231. half the single precision registers for now (as sub registers of the
  232. double precision ones). }
  233. if FPUARM_HAS_32REGS in fpu_capabilities[current_settings.fputype] then
  234. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  235. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  236. RS_D16,RS_D17,RS_D18,RS_D19,RS_D20,RS_D21,RS_D22,RS_D23,RS_D24,RS_D25,RS_D26,RS_D27,RS_D28,RS_D29,RS_D30,RS_D31,
  237. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  238. ],first_mm_imreg,[])
  239. else
  240. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  241. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15],first_mm_imreg,[]);
  242. end;
  243. procedure tarmcgarm.done_register_allocators;
  244. begin
  245. rg[R_INTREGISTER].free;
  246. rg[R_FPUREGISTER].free;
  247. rg[R_MMREGISTER].free;
  248. inherited done_register_allocators;
  249. end;
  250. procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  251. var
  252. imm_shift : byte;
  253. l : tasmlabel;
  254. hr : treference;
  255. imm1, imm2: DWord;
  256. begin
  257. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  258. internalerror(2002090902);
  259. if is_shifter_const(a,imm_shift) then
  260. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  261. else if is_shifter_const(not(a),imm_shift) then
  262. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  263. { loading of constants with mov and orr }
  264. else if (split_into_shifter_const(a,imm1, imm2)) then
  265. begin
  266. list.concat(taicpu.op_reg_const(A_MOV,reg, imm1));
  267. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg, imm2));
  268. end
  269. { loading of constants with mvn and bic }
  270. else if (split_into_shifter_const(not(a), imm1, imm2)) then
  271. begin
  272. list.concat(taicpu.op_reg_const(A_MVN,reg, imm1));
  273. list.concat(taicpu.op_reg_reg_const(A_BIC,reg,reg, imm2));
  274. end
  275. else
  276. begin
  277. reference_reset(hr,4,[]);
  278. current_asmdata.getjumplabel(l);
  279. cg.a_label(current_procinfo.aktlocaldata,l);
  280. hr.symboldata:=current_procinfo.aktlocaldata.last;
  281. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  282. hr.symbol:=l;
  283. hr.base:=NR_PC;
  284. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  285. end;
  286. end;
  287. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  288. var
  289. oppostfix:toppostfix;
  290. usedtmpref: treference;
  291. tmpreg,tmpreg2 : tregister;
  292. so : tshifterop;
  293. dir : integer;
  294. begin
  295. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  296. FromSize := ToSize;
  297. case FromSize of
  298. { signed integer registers }
  299. OS_8:
  300. oppostfix:=PF_B;
  301. OS_S8:
  302. oppostfix:=PF_SB;
  303. OS_16:
  304. oppostfix:=PF_H;
  305. OS_S16:
  306. oppostfix:=PF_SH;
  307. OS_32,
  308. OS_S32:
  309. oppostfix:=PF_None;
  310. else
  311. InternalError(200308297);
  312. end;
  313. if (fromsize=OS_S8) and
  314. (not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) then
  315. oppostfix:=PF_B;
  316. if ((ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize])) or
  317. ((not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) and
  318. (oppostfix in [PF_SH,PF_H])) then
  319. begin
  320. if target_info.endian=endian_big then
  321. dir:=-1
  322. else
  323. dir:=1;
  324. case FromSize of
  325. OS_16,OS_S16:
  326. begin
  327. { only complicated references need an extra loadaddr }
  328. if assigned(ref.symbol) or
  329. (ref.index<>NR_NO) or
  330. (ref.offset<-4095) or
  331. (ref.offset>4094) or
  332. { sometimes the compiler reused registers }
  333. (reg=ref.index) or
  334. (reg=ref.base) then
  335. begin
  336. tmpreg2:=getintregister(list,OS_INT);
  337. a_loadaddr_ref_reg(list,ref,tmpreg2);
  338. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  339. end
  340. else
  341. usedtmpref:=ref;
  342. if target_info.endian=endian_big then
  343. inc(usedtmpref.offset,1);
  344. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  345. tmpreg:=getintregister(list,OS_INT);
  346. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  347. inc(usedtmpref.offset,dir);
  348. if FromSize=OS_16 then
  349. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  350. else
  351. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  352. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  353. end;
  354. OS_32,OS_S32:
  355. begin
  356. tmpreg:=getintregister(list,OS_INT);
  357. { only complicated references need an extra loadaddr }
  358. if assigned(ref.symbol) or
  359. (ref.index<>NR_NO) or
  360. (ref.offset<-4095) or
  361. (ref.offset>4092) or
  362. { sometimes the compiler reused registers }
  363. (reg=ref.index) or
  364. (reg=ref.base) then
  365. begin
  366. tmpreg2:=getintregister(list,OS_INT);
  367. a_loadaddr_ref_reg(list,ref,tmpreg2);
  368. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  369. end
  370. else
  371. usedtmpref:=ref;
  372. shifterop_reset(so);so.shiftmode:=SM_LSL;
  373. if ref.alignment=2 then
  374. begin
  375. if target_info.endian=endian_big then
  376. inc(usedtmpref.offset,2);
  377. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  378. inc(usedtmpref.offset,dir*2);
  379. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  380. so.shiftimm:=16;
  381. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  382. end
  383. else
  384. begin
  385. tmpreg2:=getintregister(list,OS_INT);
  386. if target_info.endian=endian_big then
  387. inc(usedtmpref.offset,3);
  388. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  389. inc(usedtmpref.offset,dir);
  390. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  391. inc(usedtmpref.offset,dir);
  392. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
  393. so.shiftimm:=8;
  394. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  395. inc(usedtmpref.offset,dir);
  396. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  397. so.shiftimm:=16;
  398. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg2,so));
  399. so.shiftimm:=24;
  400. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  401. end;
  402. end
  403. else
  404. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  405. end;
  406. end
  407. else
  408. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  409. if (fromsize=OS_S8) and
  410. (not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) then
  411. a_load_reg_reg(list,OS_S8,OS_32,reg,reg)
  412. else if (fromsize=OS_S8) and (tosize = OS_16) then
  413. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  414. end;
  415. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  416. var
  417. hsym : tsym;
  418. href : treference;
  419. paraloc : Pcgparalocation;
  420. shift : byte;
  421. begin
  422. { calculate the parameter info for the procdef }
  423. procdef.init_paraloc_info(callerside);
  424. hsym:=tsym(procdef.parast.Find('self'));
  425. if not(assigned(hsym) and
  426. (hsym.typ=paravarsym)) then
  427. internalerror(200305251);
  428. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  429. while paraloc<>nil do
  430. with paraloc^ do
  431. begin
  432. case loc of
  433. LOC_REGISTER:
  434. begin
  435. if is_shifter_const(ioffset,shift) then
  436. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  437. else
  438. begin
  439. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  440. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  441. end;
  442. end;
  443. LOC_REFERENCE:
  444. begin
  445. { offset in the wrapper needs to be adjusted for the stored
  446. return address }
  447. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),ctempposinvalid,sizeof(pint),[]);
  448. if is_shifter_const(ioffset,shift) then
  449. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  450. else
  451. begin
  452. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  453. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  454. end;
  455. end
  456. else
  457. internalerror(200309189);
  458. end;
  459. paraloc:=next;
  460. end;
  461. end;
  462. procedure tbasecgarm.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  463. var
  464. ref: treference;
  465. begin
  466. paraloc.check_simple_location;
  467. paramanager.allocparaloc(list,paraloc.location);
  468. case paraloc.location^.loc of
  469. LOC_REGISTER,LOC_CREGISTER:
  470. a_load_const_reg(list,size,a,paraloc.location^.register);
  471. LOC_REFERENCE:
  472. begin
  473. reference_reset(ref,paraloc.alignment,[]);
  474. ref.base:=paraloc.location^.reference.index;
  475. ref.offset:=paraloc.location^.reference.offset;
  476. a_load_const_ref(list,size,a,ref);
  477. end;
  478. else
  479. internalerror(2002081101);
  480. end;
  481. end;
  482. procedure tbasecgarm.a_load_ref_cgparalocref(list: TAsmList; sourcesize: tcgsize; sizeleft: tcgint; const ref, paralocref: treference; const cgpara: tcgpara; const location: PCGParaLocation);
  483. begin
  484. { doubles in softemu mode have a strange order of registers and references }
  485. if (cgpara.size=OS_F64) and
  486. (location^.size=OS_32) then
  487. begin
  488. g_concatcopy(list,ref,paralocref,4)
  489. end
  490. else
  491. inherited;
  492. end;
  493. procedure tbasecgarm.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  494. var
  495. ref: treference;
  496. tmpreg: tregister;
  497. begin
  498. paraloc.check_simple_location;
  499. paramanager.allocparaloc(list,paraloc.location);
  500. case paraloc.location^.loc of
  501. LOC_REGISTER,LOC_CREGISTER:
  502. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  503. LOC_REFERENCE:
  504. begin
  505. reference_reset(ref,paraloc.alignment,[]);
  506. ref.base := paraloc.location^.reference.index;
  507. ref.offset := paraloc.location^.reference.offset;
  508. tmpreg := getintregister(list,OS_ADDR);
  509. a_loadaddr_ref_reg(list,r,tmpreg);
  510. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  511. end;
  512. else
  513. internalerror(2002080701);
  514. end;
  515. end;
  516. procedure tbasecgarm.a_call_name(list : TAsmList;const s : string; weak: boolean);
  517. var
  518. branchopcode: tasmop;
  519. r : treference;
  520. sym : TAsmSymbol;
  521. begin
  522. { use always BL as newer binutils do not translate blx apparently
  523. generating BL is also what clang and gcc do by default }
  524. branchopcode:=A_BL;
  525. if not(weak) then
  526. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION)
  527. else
  528. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION);
  529. reference_reset_symbol(r,sym,0,sizeof(pint),[]);
  530. if (tf_pic_uses_got in target_info.flags) and
  531. (cs_create_pic in current_settings.moduleswitches) then
  532. begin
  533. r.refaddr:=addr_pic
  534. end
  535. else
  536. r.refaddr:=addr_full;
  537. list.concat(taicpu.op_ref(branchopcode,r));
  538. {
  539. the compiler does not properly set this flag anymore in pass 1, and
  540. for now we only need it after pass 2 (I hope) (JM)
  541. if not(pi_do_call in current_procinfo.flags) then
  542. internalerror(2003060703);
  543. }
  544. include(current_procinfo.flags,pi_do_call);
  545. end;
  546. procedure tbasecgarm.a_call_reg(list : TAsmList;reg: tregister);
  547. begin
  548. { check not really correct: should only be used for non-Thumb cpus }
  549. if not(CPUARM_HAS_BLX in cpu_capabilities[current_settings.cputype]) then
  550. begin
  551. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  552. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  553. end
  554. else
  555. list.concat(taicpu.op_reg(A_BLX, reg));
  556. {
  557. the compiler does not properly set this flag anymore in pass 1, and
  558. for now we only need it after pass 2 (I hope) (JM)
  559. if not(pi_do_call in current_procinfo.flags) then
  560. internalerror(2003060703);
  561. }
  562. include(current_procinfo.flags,pi_do_call);
  563. end;
  564. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  565. begin
  566. a_op_const_reg_reg(list,op,size,a,reg,reg);
  567. end;
  568. procedure tcgarm.a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  569. var
  570. tmpreg,tmpresreg : tregister;
  571. tmpref : treference;
  572. begin
  573. tmpreg:=getintregister(list,size);
  574. tmpresreg:=getintregister(list,size);
  575. tmpref:=a_internal_load_ref_reg(list,size,size,ref,tmpreg);
  576. a_op_const_reg_reg(list,op,size,a,tmpreg,tmpresreg);
  577. a_load_reg_ref(list,size,size,tmpresreg,tmpref);
  578. end;
  579. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  580. var
  581. so : tshifterop;
  582. begin
  583. if op = OP_NEG then
  584. begin
  585. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  586. maybeadjustresult(list,OP_NEG,size,dst);
  587. end
  588. else if op = OP_NOT then
  589. begin
  590. if size in [OS_8, OS_16, OS_S8, OS_S16] then
  591. begin
  592. shifterop_reset(so);
  593. so.shiftmode:=SM_LSL;
  594. if size in [OS_8, OS_S8] then
  595. so.shiftimm:=24
  596. else
  597. so.shiftimm:=16;
  598. list.concat(taicpu.op_reg_reg_shifterop(A_MVN,dst,src,so));
  599. {Using a shift here allows this to be folded into another instruction}
  600. if size in [OS_S8, OS_S16] then
  601. so.shiftmode:=SM_ASR
  602. else
  603. so.shiftmode:=SM_LSR;
  604. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,dst,so));
  605. end
  606. else
  607. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  608. end
  609. else
  610. a_op_reg_reg_reg(list,op,size,src,dst,dst);
  611. end;
  612. const
  613. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  614. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  615. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE);
  616. op_reg_opcg2asmop: array[TOpCG] of tasmop =
  617. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  618. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  619. op_reg_postfix: array[TOpCG] of TOpPostfix =
  620. (PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,
  621. PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None);
  622. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  623. size: tcgsize; a: tcgint; src, dst: tregister);
  624. var
  625. ovloc : tlocation;
  626. begin
  627. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  628. end;
  629. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  630. size: tcgsize; src1, src2, dst: tregister);
  631. var
  632. ovloc : tlocation;
  633. begin
  634. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  635. end;
  636. function opshift2shiftmode(op: TOpCg): tshiftmode;
  637. begin
  638. case op of
  639. OP_SHL: Result:=SM_LSL;
  640. OP_SHR: Result:=SM_LSR;
  641. OP_ROR: Result:=SM_ROR;
  642. OP_ROL: Result:=SM_ROR;
  643. OP_SAR: Result:=SM_ASR;
  644. else internalerror(2012070501);
  645. end
  646. end;
  647. function tbasecgarm.try_optimized_mul32_const_reg_reg(list: TAsmList; a: tcgint; src, dst: tregister) : boolean;
  648. var
  649. multiplier : dword;
  650. power : longint;
  651. shifterop : tshifterop;
  652. bitsset : byte;
  653. negative : boolean;
  654. first : boolean;
  655. b,
  656. cycles : byte;
  657. maxeffort : byte;
  658. begin
  659. result:=true;
  660. cycles:=0;
  661. negative:=a<0;
  662. shifterop.rs:=NR_NO;
  663. shifterop.shiftmode:=SM_LSL;
  664. if negative then
  665. inc(cycles);
  666. multiplier:=dword(abs(a));
  667. bitsset:=popcnt(multiplier and $fffffffe);
  668. { heuristics to estimate how much instructions are reasonable to replace the mul,
  669. this is currently based on XScale timings }
  670. { in the simplest case, we need a mov to load the constant and a mul to carry out the
  671. actual multiplication, this requires min. 1+4 cycles
  672. because the first shift imm. might cause a stall and because we need more instructions
  673. when replacing the mul we generate max. 3 instructions to replace this mul }
  674. maxeffort:=3;
  675. { if the constant is not a shifter op, we need either some mov/mvn/bic/or sequence or
  676. a ldr, so generating one more operation to replace this is beneficial }
  677. if not(is_shifter_const(dword(a),b)) and not(is_shifter_const(not(dword(a)),b)) then
  678. inc(maxeffort);
  679. { if the upper 5 bits are all set or clear, mul is one cycle faster }
  680. if ((dword(a) and $f8000000)=0) or ((dword(a) and $f8000000)=$f8000000) then
  681. dec(maxeffort);
  682. { if the upper 17 bits are all set or clear, mul is another cycle faster }
  683. if ((dword(a) and $ffff8000)=0) or ((dword(a) and $ffff8000)=$ffff8000) then
  684. dec(maxeffort);
  685. { most simple cases }
  686. if a=1 then
  687. a_load_reg_reg(list,OS_32,OS_32,src,dst)
  688. else if a=0 then
  689. a_load_const_reg(list,OS_32,0,dst)
  690. else if a=-1 then
  691. a_op_reg_reg(list,OP_NEG,OS_32,src,dst)
  692. { add up ?
  693. basically, one add is needed for each bit being set in the constant factor
  694. however, the least significant bit is for free, it can be hidden in the initial
  695. instruction
  696. }
  697. else if (bitsset+cycles<=maxeffort) and
  698. (bitsset<=popcnt(dword(nextpowerof2(multiplier,power)-multiplier) and $fffffffe)) then
  699. begin
  700. first:=true;
  701. while multiplier<>0 do
  702. begin
  703. shifterop.shiftimm:=BsrDWord(multiplier);
  704. if odd(multiplier) then
  705. begin
  706. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,shifterop));
  707. dec(multiplier);
  708. end
  709. else
  710. if first then
  711. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,shifterop))
  712. else
  713. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,dst,src,shifterop));
  714. first:=false;
  715. dec(multiplier,1 shl shifterop.shiftimm);
  716. end;
  717. if negative then
  718. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,dst,0));
  719. end
  720. { subtract from the next greater power of two? }
  721. else if popcnt(dword(nextpowerof2(multiplier,power)-multiplier) and $fffffffe)+cycles+1<=maxeffort then
  722. begin
  723. first:=true;
  724. while multiplier<>0 do
  725. begin
  726. if first then
  727. begin
  728. multiplier:=(1 shl power)-multiplier;
  729. shifterop.shiftimm:=power;
  730. end
  731. else
  732. shifterop.shiftimm:=BsrDWord(multiplier);
  733. if odd(multiplier) then
  734. begin
  735. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,shifterop));
  736. dec(multiplier);
  737. end
  738. else
  739. if first then
  740. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,shifterop))
  741. else
  742. begin
  743. list.concat(taicpu.op_reg_reg_reg_shifterop(A_SUB,dst,dst,src,shifterop));
  744. dec(multiplier,1 shl shifterop.shiftimm);
  745. end;
  746. first:=false;
  747. end;
  748. if negative then
  749. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,dst,0));
  750. end
  751. else
  752. result:=false;
  753. end;
  754. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  755. var
  756. shift, lsb, width : byte;
  757. tmpreg : tregister;
  758. so : tshifterop;
  759. l1 : longint;
  760. imm1, imm2: DWord;
  761. begin
  762. optimize_op_const(size, op, a);
  763. case op of
  764. OP_NONE:
  765. begin
  766. if src <> dst then
  767. a_load_reg_reg(list, size, size, src, dst);
  768. exit;
  769. end;
  770. OP_MOVE:
  771. begin
  772. a_load_const_reg(list, size, a, dst);
  773. exit;
  774. end;
  775. else
  776. ;
  777. end;
  778. ovloc.loc:=LOC_VOID;
  779. if (a<>-2147483648) and not setflags and is_shifter_const(-a,shift) then
  780. case op of
  781. OP_ADD:
  782. begin
  783. op:=OP_SUB;
  784. a:=aint(dword(-a));
  785. end;
  786. OP_SUB:
  787. begin
  788. op:=OP_ADD;
  789. a:=aint(dword(-a));
  790. end
  791. else
  792. ;
  793. end;
  794. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  795. case op of
  796. OP_NEG,OP_NOT:
  797. internalerror(200308281);
  798. OP_SHL,
  799. OP_SHR,
  800. OP_ROL,
  801. OP_ROR,
  802. OP_SAR:
  803. begin
  804. if a>32 then
  805. internalerror(200308294);
  806. shifterop_reset(so);
  807. so.shiftmode:=opshift2shiftmode(op);
  808. if op = OP_ROL then
  809. so.shiftimm:=32-a
  810. else
  811. so.shiftimm:=a;
  812. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  813. end;
  814. else
  815. {if (op in [OP_SUB, OP_ADD]) and
  816. ((a < 0) or
  817. (a > 4095)) then
  818. begin
  819. tmpreg:=getintregister(list,size);
  820. list.concat(taicpu.op_reg_const(A_MOVT, tmpreg, (a shr 16) and $FFFF));
  821. list.concat(taicpu.op_reg_const(A_MOV, tmpreg, a and $FFFF));
  822. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  823. ));
  824. end
  825. else}
  826. begin
  827. if cgsetflags or setflags then
  828. a_reg_alloc(list,NR_DEFAULTFLAGS);
  829. list.concat(setoppostfix(
  830. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  831. end;
  832. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  833. begin
  834. ovloc.loc:=LOC_FLAGS;
  835. case op of
  836. OP_ADD:
  837. ovloc.resflags:=F_CS;
  838. OP_SUB:
  839. ovloc.resflags:=F_CC;
  840. else
  841. internalerror(2019050922);
  842. end;
  843. end;
  844. end
  845. else
  846. begin
  847. { there could be added some more sophisticated optimizations }
  848. if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then
  849. a_op_reg_reg(list,OP_NEG,size,src,dst)
  850. { we do this here instead in the peephole optimizer because
  851. it saves us a register }
  852. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  853. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  854. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  855. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  856. begin
  857. if l1>32 then{roozbeh does this ever happen?}
  858. internalerror(200308296);
  859. shifterop_reset(so);
  860. so.shiftmode:=SM_LSL;
  861. so.shiftimm:=l1;
  862. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  863. end
  864. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  865. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  866. begin
  867. if l1>32 then{does this ever happen?}
  868. internalerror(201205181);
  869. shifterop_reset(so);
  870. so.shiftmode:=SM_LSL;
  871. so.shiftimm:=l1;
  872. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  873. end
  874. else if (op in [OP_MUL,OP_IMUL]) and not(cgsetflags or setflags) and try_optimized_mul32_const_reg_reg(list,a,src,dst) then
  875. begin
  876. { nothing to do on success }
  877. end
  878. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  879. broader range of shifterconstants.}
  880. else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  881. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))
  882. { Doing two shifts instead of two bics might allow the peephole optimizer to fold the second shift
  883. into the following instruction}
  884. else if (op = OP_AND) and
  885. is_continuous_mask(aword(a), lsb, width) and
  886. ((lsb = 0) or ((lsb + width) = 32)) then
  887. begin
  888. shifterop_reset(so);
  889. if (width = 16) and
  890. (lsb = 0) and
  891. (current_settings.cputype >= cpu_armv6) then
  892. list.concat(taicpu.op_reg_reg(A_UXTH,dst,src))
  893. else if (width = 8) and
  894. (lsb = 0) and
  895. (current_settings.cputype >= cpu_armv6) then
  896. list.concat(taicpu.op_reg_reg(A_UXTB,dst,src))
  897. else if lsb = 0 then
  898. begin
  899. so.shiftmode:=SM_LSL;
  900. so.shiftimm:=32-width;
  901. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  902. so.shiftmode:=SM_LSR;
  903. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,dst,so));
  904. end
  905. else
  906. begin
  907. so.shiftmode:=SM_LSR;
  908. so.shiftimm:=lsb;
  909. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  910. so.shiftmode:=SM_LSL;
  911. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,dst,so));
  912. end;
  913. end
  914. else if (op = OP_AND) and split_into_shifter_const(not(dword(a)), imm1, imm2) then
  915. begin
  916. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,imm1));
  917. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm2));
  918. end
  919. else if (op in [OP_ADD, OP_SUB, OP_OR, OP_XOR]) and
  920. not(cgsetflags or setflags) and
  921. split_into_shifter_const(a, imm1, imm2) then
  922. begin
  923. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,imm1));
  924. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm2));
  925. end
  926. else
  927. begin
  928. tmpreg:=getintregister(list,size);
  929. a_load_const_reg(list,size,a,tmpreg);
  930. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  931. end;
  932. end;
  933. maybeadjustresult(list,op,size,dst);
  934. end;
  935. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  936. var
  937. so : tshifterop;
  938. tmpreg,overflowreg : tregister;
  939. asmop : tasmop;
  940. begin
  941. ovloc.loc:=LOC_VOID;
  942. case op of
  943. OP_NEG,OP_NOT,
  944. OP_DIV,OP_IDIV:
  945. internalerror(200308283);
  946. OP_SHL,
  947. OP_SHR,
  948. OP_SAR,
  949. OP_ROR:
  950. begin
  951. if (op = OP_ROR) and not(size in [OS_32,OS_S32]) then
  952. internalerror(2008072801);
  953. shifterop_reset(so);
  954. so.rs:=src1;
  955. so.shiftmode:=opshift2shiftmode(op);
  956. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  957. end;
  958. OP_ROL:
  959. begin
  960. if not(size in [OS_32,OS_S32]) then
  961. internalerror(2008072801);
  962. { simulate ROL by ror'ing 32-value }
  963. tmpreg:=getintregister(list,OS_32);
  964. list.concat(taicpu.op_reg_reg_const(A_RSB,tmpreg,src1, 32));
  965. shifterop_reset(so);
  966. so.rs:=tmpreg;
  967. so.shiftmode:=SM_ROR;
  968. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  969. end;
  970. OP_IMUL,
  971. OP_MUL:
  972. begin
  973. if (cgsetflags or setflags) and
  974. (CPUARM_HAS_UMULL in cpu_capabilities[current_settings.cputype]) then
  975. begin
  976. overflowreg:=getintregister(list,size);
  977. if op=OP_IMUL then
  978. asmop:=A_SMULL
  979. else
  980. asmop:=A_UMULL;
  981. { the arm doesn't allow that rd and rm are the same }
  982. if dst=src2 then
  983. begin
  984. if dst<>src1 then
  985. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  986. else
  987. begin
  988. tmpreg:=getintregister(list,size);
  989. a_load_reg_reg(list,size,size,src2,dst);
  990. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  991. end;
  992. end
  993. else
  994. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  995. a_reg_alloc(list,NR_DEFAULTFLAGS);
  996. if op=OP_IMUL then
  997. begin
  998. shifterop_reset(so);
  999. so.shiftmode:=SM_ASR;
  1000. so.shiftimm:=31;
  1001. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  1002. end
  1003. else
  1004. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  1005. ovloc.loc:=LOC_FLAGS;
  1006. ovloc.resflags:=F_NE;
  1007. end
  1008. else
  1009. begin
  1010. { the arm doesn't allow that rd and rm are the same }
  1011. if dst=src2 then
  1012. begin
  1013. if dst<>src1 then
  1014. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  1015. else
  1016. begin
  1017. tmpreg:=getintregister(list,size);
  1018. a_load_reg_reg(list,size,size,src2,dst);
  1019. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  1020. end;
  1021. end
  1022. else
  1023. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  1024. end;
  1025. end;
  1026. else
  1027. begin
  1028. if cgsetflags or setflags then
  1029. a_reg_alloc(list,NR_DEFAULTFLAGS);
  1030. list.concat(setoppostfix(
  1031. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  1032. end;
  1033. end;
  1034. maybeadjustresult(list,op,size,dst);
  1035. end;
  1036. procedure tcgarm.a_mul_reg_reg_pair(list: tasmlist; size: tcgsize; src1,src2,dstlo,dsthi: tregister);
  1037. var
  1038. asmop: tasmop;
  1039. begin
  1040. if CPUARM_HAS_UMULL in cpu_capabilities[current_settings.cputype] then
  1041. begin
  1042. list.concat(tai_comment.create(strpnew('tcgarm.a_mul_reg_reg_pair called')));
  1043. case size of
  1044. OS_32: asmop:=A_UMULL;
  1045. OS_S32: asmop:=A_SMULL;
  1046. else
  1047. InternalError(2014060802);
  1048. end;
  1049. { The caller might omit dstlo or dsthi, when he is not interested in it, we still
  1050. need valid registers everywhere. In case of dsthi = NR_NO we could fall back to
  1051. 32x32=32 bit multiplication}
  1052. if (dstlo = NR_NO) then
  1053. dstlo:=getintregister(list,size);
  1054. if (dsthi = NR_NO) then
  1055. dsthi:=getintregister(list,size);
  1056. list.concat(taicpu.op_reg_reg_reg_reg(asmop, dstlo, dsthi, src1,src2));
  1057. end
  1058. else if dsthi=NR_NO then
  1059. begin
  1060. if (dstlo = NR_NO) then
  1061. dstlo:=getintregister(list,size);
  1062. list.concat(taicpu.op_reg_reg_reg(A_MUL, dstlo, src1,src2));
  1063. end
  1064. else
  1065. begin
  1066. internalerror(2015083022);
  1067. end;
  1068. end;
  1069. function tbasecgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  1070. var
  1071. tmpreg1,tmpreg2 : tregister;
  1072. begin
  1073. tmpreg1:=NR_NO;
  1074. { Be sure to have a base register }
  1075. if (ref.base=NR_NO) then
  1076. begin
  1077. if ref.shiftmode<>SM_None then
  1078. internalerror(2014020701);
  1079. ref.base:=ref.index;
  1080. ref.index:=NR_NO;
  1081. end;
  1082. { absolute symbols can't be handled directly, we've to store the symbol reference
  1083. in the text segment and access it pc relative
  1084. For now, we assume that references where base or index equals to PC are already
  1085. relative, all other references are assumed to be absolute and thus they need
  1086. to be handled extra.
  1087. A proper solution would be to change refoptions to a set and store the information
  1088. if the symbol is absolute or relative there.
  1089. }
  1090. if (assigned(ref.symbol) and
  1091. not(is_pc(ref.base)) and
  1092. not(is_pc(ref.index))
  1093. ) or
  1094. { [#xxx] isn't a valid address operand }
  1095. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  1096. (ref.offset<-4095) or
  1097. (ref.offset>4095) or
  1098. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  1099. ((ref.offset<-255) or
  1100. (ref.offset>255)
  1101. )
  1102. ) or
  1103. (((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and
  1104. ((ref.offset<-1020) or
  1105. (ref.offset>1020) or
  1106. ((abs(ref.offset) mod 4)<>0)
  1107. )
  1108. ) or
  1109. ((GenerateThumbCode) and
  1110. (((oppostfix in [PF_SB,PF_SH]) and (ref.offset<>0)) or
  1111. ((oppostfix=PF_None) and ((ref.offset<0) or ((ref.base<>NR_STACK_POINTER_REG) and (ref.offset>124)) or
  1112. ((ref.base=NR_STACK_POINTER_REG) and (ref.offset>1020)) or ((ref.offset mod 4)<>0))) or
  1113. ((oppostfix=PF_H) and ((ref.offset<0) or (ref.offset>62) or ((ref.offset mod 2)<>0) or ((getsupreg(ref.base) in [RS_R8..RS_R15]) and (ref.offset<>0)))) or
  1114. ((oppostfix=PF_B) and ((ref.offset<0) or (ref.offset>31) or ((getsupreg(ref.base) in [RS_R8..RS_R15]) and (ref.offset<>0))))
  1115. )
  1116. ) then
  1117. begin
  1118. fixref(list,ref);
  1119. end;
  1120. if GenerateThumbCode then
  1121. begin
  1122. { certain thumb load require base and index }
  1123. if (oppostfix in [PF_SB,PF_SH]) and
  1124. (ref.base<>NR_NO) and (ref.index=NR_NO) then
  1125. begin
  1126. tmpreg1:=getintregister(list,OS_ADDR);
  1127. a_load_const_reg(list,OS_ADDR,0,tmpreg1);
  1128. ref.index:=tmpreg1;
  1129. end;
  1130. { "hi" registers cannot be used as base or index }
  1131. if (getsupreg(ref.base) in [RS_R8..RS_R12,RS_R14]) or
  1132. ((ref.base=NR_R13) and (ref.index<>NR_NO)) then
  1133. begin
  1134. tmpreg1:=getintregister(list,OS_ADDR);
  1135. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.base,tmpreg1);
  1136. ref.base:=tmpreg1;
  1137. end;
  1138. if getsupreg(ref.index) in [RS_R8..RS_R14] then
  1139. begin
  1140. tmpreg1:=getintregister(list,OS_ADDR);
  1141. a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.index,tmpreg1);
  1142. ref.index:=tmpreg1;
  1143. end;
  1144. end;
  1145. { fold if there is base, index and offset, however, don't fold
  1146. for vfp memory instructions because we later fold the index }
  1147. if not((op in [A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and
  1148. (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  1149. begin
  1150. if tmpreg1<>NR_NO then
  1151. begin
  1152. tmpreg2:=getintregister(list,OS_ADDR);
  1153. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg1,tmpreg2);
  1154. tmpreg1:=tmpreg2;
  1155. end
  1156. else
  1157. begin
  1158. tmpreg1:=getintregister(list,OS_ADDR);
  1159. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg1);
  1160. ref.base:=tmpreg1;
  1161. end;
  1162. ref.offset:=0;
  1163. end;
  1164. { floating point operations have only limited references
  1165. we expect here, that a base is already set }
  1166. if ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and (ref.index<>NR_NO) then
  1167. begin
  1168. if ref.shiftmode<>SM_none then
  1169. internalerror(200309121);
  1170. if tmpreg1<>NR_NO then
  1171. begin
  1172. if ref.base=tmpreg1 then
  1173. begin
  1174. if ref.signindex<0 then
  1175. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg1,tmpreg1,ref.index))
  1176. else
  1177. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg1,tmpreg1,ref.index));
  1178. ref.index:=NR_NO;
  1179. end
  1180. else
  1181. begin
  1182. if ref.index<>tmpreg1 then
  1183. internalerror(200403161);
  1184. if ref.signindex<0 then
  1185. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg1,ref.base,tmpreg1))
  1186. else
  1187. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg1,ref.base,tmpreg1));
  1188. ref.base:=tmpreg1;
  1189. ref.index:=NR_NO;
  1190. end;
  1191. end
  1192. else
  1193. begin
  1194. tmpreg1:=getintregister(list,OS_ADDR);
  1195. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg1,ref.base,ref.index));
  1196. ref.base:=tmpreg1;
  1197. ref.index:=NR_NO;
  1198. end;
  1199. end;
  1200. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  1201. Result := ref;
  1202. end;
  1203. procedure tbasecgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1204. var
  1205. oppostfix:toppostfix;
  1206. usedtmpref: treference;
  1207. tmpreg : tregister;
  1208. dir : integer;
  1209. begin
  1210. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  1211. FromSize := ToSize;
  1212. case ToSize of
  1213. { signed integer registers }
  1214. OS_8,
  1215. OS_S8:
  1216. oppostfix:=PF_B;
  1217. OS_16,
  1218. OS_S16:
  1219. oppostfix:=PF_H;
  1220. OS_32,
  1221. OS_S32,
  1222. { for vfp value stored in integer register }
  1223. OS_F32:
  1224. oppostfix:=PF_None;
  1225. else
  1226. InternalError(200308299);
  1227. end;
  1228. if ((ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize])) or
  1229. ((not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) and
  1230. (oppostfix =PF_H)) then
  1231. begin
  1232. if target_info.endian=endian_big then
  1233. dir:=-1
  1234. else
  1235. dir:=1;
  1236. case FromSize of
  1237. OS_16,OS_S16:
  1238. begin
  1239. tmpreg:=getintregister(list,OS_INT);
  1240. usedtmpref:=ref;
  1241. if target_info.endian=endian_big then
  1242. inc(usedtmpref.offset,1);
  1243. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  1244. inc(usedtmpref.offset,dir);
  1245. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,reg,tmpreg);
  1246. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1247. end;
  1248. OS_32,OS_S32:
  1249. begin
  1250. tmpreg:=getintregister(list,OS_INT);
  1251. usedtmpref:=ref;
  1252. if ref.alignment=2 then
  1253. begin
  1254. if target_info.endian=endian_big then
  1255. inc(usedtmpref.offset,2);
  1256. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  1257. a_op_const_reg_reg(list,OP_SHR,OS_INT,16,reg,tmpreg);
  1258. inc(usedtmpref.offset,dir*2);
  1259. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  1260. end
  1261. else
  1262. begin
  1263. if target_info.endian=endian_big then
  1264. inc(usedtmpref.offset,3);
  1265. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  1266. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,reg,tmpreg);
  1267. inc(usedtmpref.offset,dir);
  1268. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1269. a_op_const_reg(list,OP_SHR,OS_INT,8,tmpreg);
  1270. inc(usedtmpref.offset,dir);
  1271. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1272. a_op_const_reg(list,OP_SHR,OS_INT,8,tmpreg);
  1273. inc(usedtmpref.offset,dir);
  1274. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1275. end;
  1276. end
  1277. else
  1278. handle_load_store(list,A_STR,oppostfix,reg,ref);
  1279. end;
  1280. end
  1281. else
  1282. handle_load_store(list,A_STR,oppostfix,reg,ref);
  1283. end;
  1284. function tbasecgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  1285. var
  1286. oppostfix:toppostfix;
  1287. href: treference;
  1288. tmpreg: TRegister;
  1289. begin
  1290. case ToSize of
  1291. { signed integer registers }
  1292. OS_8,
  1293. OS_S8:
  1294. oppostfix:=PF_B;
  1295. OS_16,
  1296. OS_S16:
  1297. oppostfix:=PF_H;
  1298. OS_32,
  1299. OS_S32:
  1300. oppostfix:=PF_None;
  1301. else
  1302. InternalError(2003082910);
  1303. end;
  1304. if (tosize in [OS_S16,OS_16]) and
  1305. (not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) then
  1306. begin
  1307. result:=handle_load_store(list,A_STR,PF_B,reg,ref);
  1308. tmpreg:=getintregister(list,OS_INT);
  1309. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,reg,tmpreg);
  1310. href:=result;
  1311. inc(href.offset);
  1312. handle_load_store(list,A_STR,PF_B,tmpreg,href);
  1313. end
  1314. else
  1315. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  1316. end;
  1317. function tbasecgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  1318. var
  1319. oppostfix:toppostfix;
  1320. so: tshifterop;
  1321. tmpreg: TRegister;
  1322. href: treference;
  1323. begin
  1324. case FromSize of
  1325. { signed integer registers }
  1326. OS_8:
  1327. oppostfix:=PF_B;
  1328. OS_S8:
  1329. oppostfix:=PF_SB;
  1330. OS_16:
  1331. oppostfix:=PF_H;
  1332. OS_S16:
  1333. oppostfix:=PF_SH;
  1334. OS_32,
  1335. OS_S32:
  1336. oppostfix:=PF_None;
  1337. else
  1338. InternalError(200308291);
  1339. end;
  1340. if (tosize=OS_S8) and
  1341. (not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) then
  1342. begin
  1343. result:=handle_load_store(list,A_LDR,PF_B,reg,ref);
  1344. a_load_reg_reg(list,OS_S8,OS_32,reg,reg);
  1345. end
  1346. else if (tosize in [OS_S16,OS_16]) and
  1347. (not (CPUARM_HAS_ALL_MEM in cpu_capabilities[current_settings.cputype])) then
  1348. begin
  1349. result:=handle_load_store(list,A_LDR,PF_B,reg,ref);
  1350. tmpreg:=getintregister(list,OS_INT);
  1351. href:=result;
  1352. inc(href.offset);
  1353. handle_load_store(list,A_LDR,PF_B,tmpreg,href);
  1354. shifterop_reset(so);
  1355. so.shiftmode:=SM_LSL;
  1356. so.shiftimm:=8;
  1357. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  1358. end
  1359. else
  1360. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  1361. end;
  1362. procedure tbasecgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1363. var
  1364. so : tshifterop;
  1365. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  1366. begin
  1367. if GenerateThumbCode then
  1368. begin
  1369. case shiftmode of
  1370. SM_ASR:
  1371. a_op_const_reg_reg(list,OP_SAR,OS_32,shiftimm,reg,reg2);
  1372. SM_LSR:
  1373. a_op_const_reg_reg(list,OP_SHR,OS_32,shiftimm,reg,reg2);
  1374. SM_LSL:
  1375. a_op_const_reg_reg(list,OP_SHL,OS_32,shiftimm,reg,reg2);
  1376. else
  1377. internalerror(2013090301);
  1378. end;
  1379. end
  1380. else
  1381. begin
  1382. so.shiftmode:=shiftmode;
  1383. so.shiftimm:=shiftimm;
  1384. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  1385. end;
  1386. end;
  1387. var
  1388. instr: taicpu;
  1389. conv_done: boolean;
  1390. begin
  1391. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1392. internalerror(2002090901);
  1393. conv_done:=false;
  1394. if tosize<>fromsize then
  1395. begin
  1396. shifterop_reset(so);
  1397. conv_done:=true;
  1398. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1399. fromsize:=tosize;
  1400. if current_settings.cputype<cpu_armv6 then
  1401. case fromsize of
  1402. OS_8:
  1403. if GenerateThumbCode then
  1404. a_op_const_reg_reg(list,OP_AND,OS_32,$ff,reg1,reg2)
  1405. else
  1406. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1407. OS_S8:
  1408. begin
  1409. do_shift(SM_LSL,24,reg1);
  1410. if tosize=OS_16 then
  1411. begin
  1412. do_shift(SM_ASR,8,reg2);
  1413. do_shift(SM_LSR,16,reg2);
  1414. end
  1415. else
  1416. do_shift(SM_ASR,24,reg2);
  1417. end;
  1418. OS_16:
  1419. begin
  1420. do_shift(SM_LSL,16,reg1);
  1421. do_shift(SM_LSR,16,reg2);
  1422. end;
  1423. OS_S16:
  1424. begin
  1425. do_shift(SM_LSL,16,reg1);
  1426. do_shift(SM_ASR,16,reg2)
  1427. end;
  1428. else
  1429. conv_done:=false;
  1430. end
  1431. else
  1432. case fromsize of
  1433. OS_8:
  1434. if GenerateThumbCode then
  1435. list.concat(taicpu.op_reg_reg(A_UXTB,reg2,reg1))
  1436. else
  1437. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1438. OS_S8:
  1439. begin
  1440. if tosize=OS_16 then
  1441. begin
  1442. so.shiftmode:=SM_ROR;
  1443. so.shiftimm:=16;
  1444. list.concat(taicpu.op_reg_reg_shifterop(A_SXTB16,reg2,reg1,so));
  1445. do_shift(SM_LSR,16,reg2);
  1446. end
  1447. else
  1448. list.concat(taicpu.op_reg_reg(A_SXTB,reg2,reg1));
  1449. end;
  1450. OS_16:
  1451. list.concat(taicpu.op_reg_reg(A_UXTH,reg2,reg1));
  1452. OS_S16:
  1453. list.concat(taicpu.op_reg_reg(A_SXTH,reg2,reg1));
  1454. else
  1455. conv_done:=false;
  1456. end
  1457. end;
  1458. if not conv_done and (reg1<>reg2) then
  1459. begin
  1460. { same size, only a register mov required }
  1461. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1462. list.Concat(instr);
  1463. { Notify the register allocator that we have written a move instruction so
  1464. it can try to eliminate it. }
  1465. add_move_instruction(instr);
  1466. end;
  1467. end;
  1468. procedure tbasecgarm.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  1469. var
  1470. href,href2 : treference;
  1471. hloc : pcgparalocation;
  1472. begin
  1473. href:=ref;
  1474. hloc:=paraloc.location;
  1475. while assigned(hloc) do
  1476. begin
  1477. case hloc^.loc of
  1478. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1479. begin
  1480. paramanager.allocparaloc(list,paraloc.location);
  1481. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1482. end;
  1483. LOC_REGISTER :
  1484. case hloc^.size of
  1485. OS_32,
  1486. OS_F32:
  1487. begin
  1488. paramanager.allocparaloc(list,paraloc.location);
  1489. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1490. end;
  1491. OS_64,
  1492. OS_F64:
  1493. cg64.a_load64_ref_cgpara(list,href,paraloc);
  1494. else
  1495. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1496. end;
  1497. LOC_REFERENCE :
  1498. begin
  1499. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,ctempposinvalid,paraloc.alignment,[]);
  1500. { concatcopy should choose the best way to copy the data }
  1501. g_concatcopy(list,href,href2,tcgsize2size[hloc^.size]);
  1502. end;
  1503. else
  1504. internalerror(200408241);
  1505. end;
  1506. inc(href.offset,tcgsize2size[hloc^.size]);
  1507. hloc:=hloc^.next;
  1508. end;
  1509. end;
  1510. procedure tbasecgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1511. begin
  1512. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1513. end;
  1514. procedure tbasecgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1515. var
  1516. oppostfix:toppostfix;
  1517. begin
  1518. case fromsize of
  1519. OS_32,
  1520. OS_F32:
  1521. oppostfix:=PF_S;
  1522. OS_64,
  1523. OS_F64:
  1524. oppostfix:=PF_D;
  1525. OS_F80:
  1526. oppostfix:=PF_E;
  1527. else
  1528. InternalError(200309021);
  1529. end;
  1530. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1531. if fromsize<>tosize then
  1532. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1533. end;
  1534. procedure tbasecgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1535. var
  1536. oppostfix:toppostfix;
  1537. begin
  1538. case tosize of
  1539. OS_F32:
  1540. oppostfix:=PF_S;
  1541. OS_F64:
  1542. oppostfix:=PF_D;
  1543. OS_F80:
  1544. oppostfix:=PF_E;
  1545. else
  1546. InternalError(200309022);
  1547. end;
  1548. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1549. end;
  1550. procedure tbasecgarm.g_check_for_fpu_exception(list: TAsmList;force,clear : boolean);
  1551. var
  1552. r : TRegister;
  1553. ai: taicpu;
  1554. l: TAsmLabel;
  1555. begin
  1556. if ((cs_check_fpu_exceptions in current_settings.localswitches) and
  1557. not(FPUARM_HAS_EXCEPTION_TRAPPING in fpu_capabilities[current_settings.fputype]) and
  1558. (force or current_procinfo.FPUExceptionCheckNeeded)) then
  1559. begin
  1560. r:=getintregister(list,OS_INT);
  1561. list.concat(taicpu.op_reg_reg(A_FMRX,r,NR_FPSCR));
  1562. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_AND,r,r,$9f),PF_S));
  1563. current_asmdata.getjumplabel(l);
  1564. ai:=taicpu.op_sym(A_B,l);
  1565. ai.is_jmp:=true;
  1566. ai.condition:=C_EQ;
  1567. list.concat(ai);
  1568. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1569. cg.a_call_name(list,'FPC_THROWFPUEXCEPTION',false);
  1570. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1571. a_label(list,l);
  1572. if clear then
  1573. current_procinfo.FPUExceptionCheckNeeded:=false;
  1574. end;
  1575. end;
  1576. { comparison operations }
  1577. procedure tbasecgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  1578. l : tasmlabel);
  1579. var
  1580. tmpreg : tregister;
  1581. b : byte;
  1582. begin
  1583. a_reg_alloc(list,NR_DEFAULTFLAGS);
  1584. if (not(GenerateThumbCode) and is_shifter_const(a,b)) or
  1585. ((GenerateThumbCode) and is_thumb_imm(a)) then
  1586. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1587. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1588. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1589. else if (a<>$7fffffff) and (a<>-1) and not(GenerateThumbCode) and is_shifter_const(-a,b) then
  1590. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1591. else
  1592. begin
  1593. tmpreg:=getintregister(list,size);
  1594. a_load_const_reg(list,size,a,tmpreg);
  1595. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1596. end;
  1597. a_jmp_cond(list,cmp_op,l);
  1598. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1599. end;
  1600. procedure tbasecgarm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister);
  1601. begin
  1602. if reverse then
  1603. begin
  1604. list.Concat(taicpu.op_reg_reg(A_CLZ,dst,src));
  1605. list.Concat(taicpu.op_reg_reg_const(A_RSB,dst,dst,31));
  1606. list.Concat(taicpu.op_reg_reg_const(A_AND,dst,dst,255));
  1607. end
  1608. { it is decided during the compilation of the system unit if this code is used or not
  1609. so no additional check for rbit is needed }
  1610. else
  1611. begin
  1612. list.Concat(taicpu.op_reg_reg(A_RBIT,dst,src));
  1613. list.Concat(taicpu.op_reg_reg(A_CLZ,dst,dst));
  1614. a_reg_alloc(list,NR_DEFAULTFLAGS);
  1615. list.Concat(taicpu.op_reg_const(A_CMP,dst,32));
  1616. if GenerateThumb2Code then
  1617. list.Concat(taicpu.op_cond(A_IT, C_EQ));
  1618. list.Concat(setcondition(taicpu.op_reg_const(A_MOV,dst,$ff),C_EQ));
  1619. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1620. end;
  1621. end;
  1622. procedure tbasecgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1623. begin
  1624. a_reg_alloc(list,NR_DEFAULTFLAGS);
  1625. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1626. a_jmp_cond(list,cmp_op,l);
  1627. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1628. end;
  1629. procedure tbasecgarm.a_jmp_name(list : TAsmList;const s : string);
  1630. var
  1631. ai : taicpu;
  1632. begin
  1633. { generate far jump, leave it to the optimizer to get rid of it }
  1634. if GenerateThumbCode then
  1635. ai:=taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s,AT_FUNCTION))
  1636. else
  1637. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1638. ai.is_jmp:=true;
  1639. list.concat(ai);
  1640. end;
  1641. procedure tbasecgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1642. var
  1643. ai : taicpu;
  1644. begin
  1645. { generate far jump, leave it to the optimizer to get rid of it }
  1646. if GenerateThumbCode then
  1647. ai:=taicpu.op_sym(A_BL,l)
  1648. else
  1649. ai:=taicpu.op_sym(A_B,l);
  1650. ai.is_jmp:=true;
  1651. list.concat(ai);
  1652. end;
  1653. procedure tbasecgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1654. var
  1655. ai : taicpu;
  1656. inv_flags : TResFlags;
  1657. hlabel : TAsmLabel;
  1658. begin
  1659. if GenerateThumbCode then
  1660. begin
  1661. inv_flags:=f;
  1662. inverse_flags(inv_flags);
  1663. { the optimizer has to fix this if jump range is sufficient short }
  1664. current_asmdata.getjumplabel(hlabel);
  1665. ai:=setcondition(taicpu.op_sym(A_B,hlabel),flags_to_cond(inv_flags));
  1666. ai.is_jmp:=true;
  1667. list.concat(ai);
  1668. a_jmp_always(list,l);
  1669. a_label(list,hlabel);
  1670. end
  1671. else
  1672. begin
  1673. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1674. ai.is_jmp:=true;
  1675. list.concat(ai);
  1676. end;
  1677. end;
  1678. procedure tbasecgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1679. begin
  1680. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1681. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1682. end;
  1683. procedure tbasecgarm.g_profilecode(list : TAsmList);
  1684. begin
  1685. if target_info.system = system_arm_linux then
  1686. begin
  1687. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R14]));
  1688. a_call_name(list,'__gnu_mcount_nc',false);
  1689. end
  1690. else
  1691. internalerror(2014091201);
  1692. end;
  1693. procedure tbasecgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1694. var
  1695. ref : treference;
  1696. shift : byte;
  1697. firstfloatreg,lastfloatreg,
  1698. r : byte;
  1699. mmregs,
  1700. regs, saveregs : tcpuregisterset;
  1701. registerarea,
  1702. r7offset,
  1703. stackmisalignment : pint;
  1704. imm1, imm2: DWord;
  1705. stack_parameters : Boolean;
  1706. begin
  1707. LocalSize:=align(LocalSize,4);
  1708. stack_parameters:=current_procinfo.procdef.stack_tainting_parameter(calleeside);
  1709. { call instruction does not put anything on the stack }
  1710. registerarea:=0;
  1711. tcpuprocinfo(current_procinfo).stackpaddingreg:=High(TSuperRegister);
  1712. lastfloatreg:=RS_NO;
  1713. if not(nostackframe) then
  1714. begin
  1715. firstfloatreg:=RS_NO;
  1716. mmregs:=[];
  1717. case current_settings.fputype of
  1718. fpu_none,
  1719. fpu_soft,
  1720. fpu_libgcc:
  1721. ;
  1722. fpu_fpa,
  1723. fpu_fpa10,
  1724. fpu_fpa11:
  1725. begin
  1726. { save floating point registers? }
  1727. regs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  1728. for r:=RS_F0 to RS_F7 do
  1729. if r in regs then
  1730. begin
  1731. if firstfloatreg=RS_NO then
  1732. firstfloatreg:=r;
  1733. lastfloatreg:=r;
  1734. inc(registerarea,12);
  1735. end;
  1736. end;
  1737. else if FPUARM_HAS_32REGS in fpu_capabilities[current_settings.fputype] then
  1738. begin;
  1739. { the *[0..31] is a hack to prevent that the compiler tries to save odd single-type registers,
  1740. they have numbers>$1f which is not really correct as they should simply have the same numbers
  1741. as the even ones by with a different subtype as it is done on x86 with al/ah }
  1742. mmregs:=(rg[R_MMREGISTER].used_in_proc-paramanager.get_volatile_registers_mm(pocall_stdcall))*[0..31];
  1743. end
  1744. else if FPUARM_HAS_VFP_EXTENSION in fpu_capabilities[current_settings.fputype] then
  1745. begin;
  1746. { the *[0..15] is a hack to prevent that the compiler tries to save odd single-type registers,
  1747. they have numbers>$1f which is not really correct as they should simply have the same numbers
  1748. as the even ones by with a different subtype as it is done on x86 with al/ah }
  1749. mmregs:=(rg[R_MMREGISTER].used_in_proc-paramanager.get_volatile_registers_mm(pocall_stdcall))*[0..15];
  1750. end
  1751. else
  1752. internalerror(2019050924);
  1753. end;
  1754. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1755. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1756. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1757. { save int registers }
  1758. reference_reset(ref,4,[]);
  1759. ref.index:=NR_STACK_POINTER_REG;
  1760. ref.addressmode:=AM_PREINDEXED;
  1761. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1762. if not(target_info.system in systems_darwin) then
  1763. begin
  1764. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1765. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1766. begin
  1767. a_reg_alloc(list,NR_R12);
  1768. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1769. end;
  1770. { the (old) ARM APCS requires saving both the stack pointer (to
  1771. crawl the stack) and the PC (to identify the function this
  1772. stack frame belongs to) -> also save R12 (= copy of R13 on entry)
  1773. and R15 -- still needs updating for EABI and Darwin, they don't
  1774. need that }
  1775. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1776. regs:=regs+[RS_FRAME_POINTER_REG,RS_R12,RS_R14,RS_R15]
  1777. else
  1778. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1779. include(regs,RS_R14);
  1780. if regs<>[] then
  1781. begin
  1782. for r:=RS_R0 to RS_R15 do
  1783. if r in regs then
  1784. inc(registerarea,4);
  1785. { if the stack is not 8 byte aligned, try to add an extra register,
  1786. so we can avoid the extra sub/add ...,#4 later (KB) }
  1787. if ((registerarea mod current_settings.alignment.localalignmax) <> 0) then
  1788. for r:=RS_R3 downto RS_R0 do
  1789. if not(r in regs) then
  1790. begin
  1791. regs:=regs+[r];
  1792. inc(registerarea,4);
  1793. tcpuprocinfo(current_procinfo).stackpaddingreg:=r;
  1794. break;
  1795. end;
  1796. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  1797. end;
  1798. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1799. begin
  1800. { the framepointer now points to the saved R15, so the saved
  1801. framepointer is at R11-12 (for get_caller_frame) }
  1802. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1803. a_reg_dealloc(list,NR_R12);
  1804. end;
  1805. end
  1806. else
  1807. begin
  1808. { always save r14 if we use r7 as the framepointer, because
  1809. the parameter offsets are hardcoded in advance and always
  1810. assume that r14 sits on the stack right behind the saved r7
  1811. }
  1812. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1813. include(regs,RS_FRAME_POINTER_REG);
  1814. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1815. include(regs,RS_R14);
  1816. if regs<>[] then
  1817. begin
  1818. { on Darwin, you first have to save [r4-r7,lr], and then
  1819. [r8,r10,r11] and make r7 point to the previously saved
  1820. r7 so that you can perform a stack crawl based on it
  1821. ([r7] is previous stack frame, [r7+4] is return address
  1822. }
  1823. include(regs,RS_FRAME_POINTER_REG);
  1824. saveregs:=regs-[RS_R8,RS_R10,RS_R11];
  1825. r7offset:=0;
  1826. for r:=RS_R0 to RS_R15 do
  1827. if r in saveregs then
  1828. begin
  1829. inc(registerarea,4);
  1830. if r<RS_FRAME_POINTER_REG then
  1831. inc(r7offset,4);
  1832. end;
  1833. { save the registers }
  1834. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  1835. { make r7 point to the saved r7 (regardless of whether this
  1836. frame uses the framepointer, for backtrace purposes) }
  1837. if r7offset<>0 then
  1838. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_FRAME_POINTER_REG,NR_R13,r7offset))
  1839. else
  1840. list.concat(taicpu.op_reg_reg(A_MOV,NR_R7,NR_R13));
  1841. { now save the rest (if any) }
  1842. saveregs:=regs-saveregs;
  1843. if saveregs<>[] then
  1844. begin
  1845. for r:=RS_R8 to RS_R11 do
  1846. if r in saveregs then
  1847. inc(registerarea,4);
  1848. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  1849. end;
  1850. end;
  1851. end;
  1852. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  1853. if (LocalSize<>0) or
  1854. ((stackmisalignment<>0) and
  1855. ((pi_do_call in current_procinfo.flags) or
  1856. (po_assembler in current_procinfo.procdef.procoptions))) then
  1857. begin
  1858. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1859. if stack_parameters and (pi_estimatestacksize in current_procinfo.flags) then
  1860. begin
  1861. if localsize>tcpuprocinfo(current_procinfo).stackframesize then
  1862. internalerror(2014030901)
  1863. else
  1864. localsize:=tcpuprocinfo(current_procinfo).stackframesize-registerarea;
  1865. end;
  1866. if is_shifter_const(localsize,shift) then
  1867. begin
  1868. a_reg_dealloc(list,NR_R12);
  1869. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1870. end
  1871. else if split_into_shifter_const(localsize, imm1, imm2) then
  1872. begin
  1873. a_reg_dealloc(list,NR_R12);
  1874. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm1));
  1875. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm2));
  1876. end
  1877. else
  1878. begin
  1879. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1880. a_reg_alloc(list,NR_R12);
  1881. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1882. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1883. a_reg_dealloc(list,NR_R12);
  1884. end;
  1885. end;
  1886. if (mmregs<>[]) or
  1887. (firstfloatreg<>RS_NO) then
  1888. begin
  1889. reference_reset(ref,4,[]);
  1890. if (tg.direction*tcpuprocinfo(current_procinfo).floatregstart>=1023) or
  1891. (FPUARM_HAS_VFP_DOUBLE in fpu_capabilities[current_settings.fputype]) then
  1892. begin
  1893. if not is_shifter_const(tcpuprocinfo(current_procinfo).floatregstart,shift) then
  1894. begin
  1895. a_reg_alloc(list,NR_R12);
  1896. a_load_const_reg(list,OS_ADDR,-tcpuprocinfo(current_procinfo).floatregstart,NR_R12);
  1897. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1898. a_reg_dealloc(list,NR_R12);
  1899. end
  1900. else
  1901. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_R12,current_procinfo.framepointer,-tcpuprocinfo(current_procinfo).floatregstart));
  1902. ref.base:=NR_R12;
  1903. end
  1904. else
  1905. begin
  1906. ref.base:=current_procinfo.framepointer;
  1907. ref.offset:=tcpuprocinfo(current_procinfo).floatregstart;
  1908. end;
  1909. case current_settings.fputype of
  1910. fpu_fpa,
  1911. fpu_fpa10,
  1912. fpu_fpa11:
  1913. begin
  1914. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1915. lastfloatreg-firstfloatreg+1,ref));
  1916. end;
  1917. else if FPUARM_HAS_VFP_DOUBLE in fpu_capabilities[current_settings.fputype] then
  1918. begin
  1919. ref.index:=ref.base;
  1920. ref.base:=NR_NO;
  1921. { FSTMX is deprecated on ARMv6 and later }
  1922. {if (current_settings.cputype<cpu_armv6) then
  1923. postfix:=PF_IAX
  1924. else
  1925. postfix:=PF_IAD;}
  1926. if mmregs<>[] then
  1927. list.concat(taicpu.op_ref_regset(A_VSTM,ref,R_MMREGISTER,R_SUBFD,mmregs));
  1928. end
  1929. else
  1930. internalerror(2019050923);
  1931. end;
  1932. end;
  1933. end;
  1934. end;
  1935. procedure tbasecgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1936. var
  1937. ref : treference;
  1938. LocalSize : longint;
  1939. firstfloatreg,lastfloatreg,
  1940. r,
  1941. shift : byte;
  1942. mmregs,
  1943. saveregs,
  1944. regs : tcpuregisterset;
  1945. registerarea,
  1946. stackmisalignment: pint;
  1947. paddingreg: TSuperRegister;
  1948. imm1, imm2: DWord;
  1949. begin
  1950. if not(nostackframe) then
  1951. begin
  1952. registerarea:=0;
  1953. firstfloatreg:=RS_NO;
  1954. lastfloatreg:=RS_NO;
  1955. mmregs:=[];
  1956. saveregs:=[];
  1957. case current_settings.fputype of
  1958. fpu_none,
  1959. fpu_soft,
  1960. fpu_libgcc:
  1961. ;
  1962. fpu_fpa,
  1963. fpu_fpa10,
  1964. fpu_fpa11:
  1965. begin
  1966. { restore floating point registers? }
  1967. regs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  1968. for r:=RS_F0 to RS_F7 do
  1969. if r in regs then
  1970. begin
  1971. if firstfloatreg=RS_NO then
  1972. firstfloatreg:=r;
  1973. lastfloatreg:=r;
  1974. { floating point register space is already included in
  1975. localsize below by calc_stackframe_size
  1976. inc(registerarea,12);
  1977. }
  1978. end;
  1979. end;
  1980. else if FPUARM_HAS_VFP_DOUBLE in fpu_capabilities[current_settings.fputype] then
  1981. begin
  1982. { restore vfp registers? }
  1983. { the *[0..31] is a hack to prevent that the compiler tries to save odd single-type registers,
  1984. they have numbers>$1f which is not really correct as they should simply have the same numbers
  1985. as the even ones by with a different subtype as it is done on x86 with al/ah }
  1986. mmregs:=(rg[R_MMREGISTER].used_in_proc-paramanager.get_volatile_registers_mm(pocall_stdcall))*[0..31];
  1987. end
  1988. else
  1989. internalerror(2019050926);
  1990. end;
  1991. if (firstfloatreg<>RS_NO) or
  1992. (mmregs<>[]) then
  1993. begin
  1994. reference_reset(ref,4,[]);
  1995. if (tg.direction*tcpuprocinfo(current_procinfo).floatregstart>=1023) or
  1996. (FPUARM_HAS_VFP_DOUBLE in fpu_capabilities[current_settings.fputype]) then
  1997. begin
  1998. if not is_shifter_const(tcpuprocinfo(current_procinfo).floatregstart,shift) then
  1999. begin
  2000. a_reg_alloc(list,NR_R12);
  2001. a_load_const_reg(list,OS_ADDR,-tcpuprocinfo(current_procinfo).floatregstart,NR_R12);
  2002. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  2003. a_reg_dealloc(list,NR_R12);
  2004. end
  2005. else
  2006. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_R12,current_procinfo.framepointer,-tcpuprocinfo(current_procinfo).floatregstart));
  2007. ref.base:=NR_R12;
  2008. end
  2009. else
  2010. begin
  2011. ref.base:=current_procinfo.framepointer;
  2012. ref.offset:=tcpuprocinfo(current_procinfo).floatregstart;
  2013. end;
  2014. case current_settings.fputype of
  2015. fpu_fpa,
  2016. fpu_fpa10,
  2017. fpu_fpa11:
  2018. begin
  2019. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  2020. lastfloatreg-firstfloatreg+1,ref));
  2021. end;
  2022. else if FPUARM_HAS_VFP_DOUBLE in fpu_capabilities[current_settings.fputype] then
  2023. begin
  2024. ref.index:=ref.base;
  2025. ref.base:=NR_NO;
  2026. { FLDMX is deprecated on ARMv6 and later }
  2027. {if (current_settings.cputype<cpu_armv6) then
  2028. mmpostfix:=PF_IAX
  2029. else
  2030. mmpostfix:=PF_IAD;}
  2031. if mmregs<>[] then
  2032. list.concat(taicpu.op_ref_regset(A_VLDM,ref,R_MMREGISTER,R_SUBFD,mmregs));
  2033. end
  2034. else
  2035. internalerror(2019050921);
  2036. end;
  2037. end;
  2038. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  2039. if (pi_do_call in current_procinfo.flags) or
  2040. (regs<>[]) or
  2041. ((target_info.system in systems_darwin) and
  2042. (current_procinfo.framepointer<>NR_STACK_POINTER_REG)) then
  2043. begin
  2044. exclude(regs,RS_R14);
  2045. include(regs,RS_R15);
  2046. if (target_info.system in systems_darwin) then
  2047. include(regs,RS_FRAME_POINTER_REG);
  2048. end;
  2049. if not(target_info.system in systems_darwin) then
  2050. begin
  2051. { restore saved stack pointer to SP (R13) and saved lr to PC (R15).
  2052. The saved PC came after that but is discarded, since we restore
  2053. the stack pointer }
  2054. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  2055. regs:=regs+[RS_FRAME_POINTER_REG,RS_R13,RS_R15];
  2056. end
  2057. else
  2058. begin
  2059. { restore R8-R11 already if necessary (they've been stored
  2060. before the others) }
  2061. saveregs:=regs*[RS_R8,RS_R10,RS_R11];
  2062. if saveregs<>[] then
  2063. begin
  2064. reference_reset(ref,4,[]);
  2065. ref.index:=NR_STACK_POINTER_REG;
  2066. ref.addressmode:=AM_PREINDEXED;
  2067. for r:=RS_R8 to RS_R11 do
  2068. if r in saveregs then
  2069. inc(registerarea,4);
  2070. regs:=regs-saveregs;
  2071. end;
  2072. end;
  2073. for r:=RS_R0 to RS_R15 do
  2074. if r in regs then
  2075. inc(registerarea,4);
  2076. { reapply the stack padding reg, in case there was one, see the complimentary
  2077. comment in g_proc_entry() (KB) }
  2078. paddingreg:=tcpuprocinfo(current_procinfo).stackpaddingreg;
  2079. if paddingreg < RS_R4 then
  2080. if paddingreg in regs then
  2081. internalerror(201306190)
  2082. else
  2083. begin
  2084. regs:=regs+[paddingreg];
  2085. inc(registerarea,4);
  2086. end;
  2087. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  2088. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  2089. (target_info.system in systems_darwin) then
  2090. begin
  2091. LocalSize:=current_procinfo.calc_stackframe_size;
  2092. if (LocalSize<>0) or
  2093. ((stackmisalignment<>0) and
  2094. ((pi_do_call in current_procinfo.flags) or
  2095. (po_assembler in current_procinfo.procdef.procoptions))) then
  2096. begin
  2097. if pi_estimatestacksize in current_procinfo.flags then
  2098. LocalSize:=tcpuprocinfo(current_procinfo).stackframesize-registerarea
  2099. else
  2100. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  2101. if is_shifter_const(LocalSize,shift) then
  2102. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize))
  2103. else if split_into_shifter_const(localsize, imm1, imm2) then
  2104. begin
  2105. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm1));
  2106. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm2));
  2107. end
  2108. else
  2109. begin
  2110. a_reg_alloc(list,NR_R12);
  2111. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  2112. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  2113. a_reg_dealloc(list,NR_R12);
  2114. end;
  2115. end;
  2116. if (target_info.system in systems_darwin) and
  2117. (saveregs<>[]) then
  2118. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  2119. if regs=[] then
  2120. begin
  2121. if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  2122. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  2123. else
  2124. list.concat(taicpu.op_reg(A_BX,NR_R14))
  2125. end
  2126. else
  2127. begin
  2128. reference_reset(ref,4,[]);
  2129. ref.index:=NR_STACK_POINTER_REG;
  2130. ref.addressmode:=AM_PREINDEXED;
  2131. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  2132. end;
  2133. end
  2134. else
  2135. begin
  2136. { restore int registers and return }
  2137. reference_reset(ref,4,[]);
  2138. ref.index:=NR_FRAME_POINTER_REG;
  2139. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_EA));
  2140. end;
  2141. end
  2142. else if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  2143. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  2144. else
  2145. list.concat(taicpu.op_reg(A_BX,NR_R14))
  2146. end;
  2147. procedure tbasecgarm.g_maybe_got_init(list : TAsmList);
  2148. var
  2149. ref : treference;
  2150. l : TAsmLabel;
  2151. regs : tcpuregisterset;
  2152. r: byte;
  2153. begin
  2154. if (cs_create_pic in current_settings.moduleswitches) and
  2155. (pi_needs_got in current_procinfo.flags) and
  2156. (tf_pic_uses_got in target_info.flags) then
  2157. begin
  2158. { Procedure parametrs are not initialized at this stage.
  2159. Before GOT initialization code, allocate registers used for procedure parameters
  2160. to prevent usage of these registers for temp operations in later stages of code
  2161. generation. }
  2162. regs:=rg[R_INTREGISTER].used_in_proc;
  2163. for r:=RS_R0 to RS_R3 do
  2164. if r in regs then
  2165. a_reg_alloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE));
  2166. { Allocate scratch register R12 and use it for GOT calculations directly.
  2167. Otherwise the init code can be distorted in later stages of code generation. }
  2168. a_reg_alloc(list,NR_R12);
  2169. reference_reset(ref,4,[]);
  2170. current_asmdata.getglobaldatalabel(l);
  2171. cg.a_label(current_procinfo.aktlocaldata,l);
  2172. ref.symbol:=l;
  2173. ref.base:=NR_PC;
  2174. ref.symboldata:=current_procinfo.aktlocaldata.last;
  2175. list.concat(Taicpu.op_reg_ref(A_LDR,NR_R12,ref));
  2176. current_asmdata.getaddrlabel(l);
  2177. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_32bit,l,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_',AT_DATA),-8));
  2178. cg.a_label(list,l);
  2179. list.concat(Taicpu.op_reg_reg_reg(A_ADD,NR_R12,NR_PC,NR_R12));
  2180. list.concat(Taicpu.op_reg_reg(A_MOV,current_procinfo.got,NR_R12));
  2181. { Deallocate registers }
  2182. a_reg_dealloc(list,NR_R12);
  2183. for r:=RS_R3 downto RS_R0 do
  2184. if r in regs then
  2185. a_reg_dealloc(list, newreg(R_INTREGISTER,r,R_SUBWHOLE));
  2186. end;
  2187. end;
  2188. procedure tbasecgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  2189. var
  2190. b : byte;
  2191. tmpref : treference;
  2192. instr : taicpu;
  2193. begin
  2194. if ref.addressmode<>AM_OFFSET then
  2195. internalerror(200309071);
  2196. tmpref:=ref;
  2197. { Be sure to have a base register }
  2198. if (tmpref.base=NR_NO) then
  2199. begin
  2200. if tmpref.shiftmode<>SM_None then
  2201. internalerror(2014020702);
  2202. if tmpref.signindex<0 then
  2203. internalerror(200312023);
  2204. tmpref.base:=tmpref.index;
  2205. tmpref.index:=NR_NO;
  2206. end;
  2207. if assigned(tmpref.symbol) or
  2208. not((is_shifter_const(tmpref.offset,b)) or
  2209. (is_shifter_const(-tmpref.offset,b))
  2210. ) then
  2211. fixref(list,tmpref);
  2212. { expect a base here if there is an index }
  2213. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  2214. internalerror(200312022);
  2215. if tmpref.index<>NR_NO then
  2216. begin
  2217. if tmpref.shiftmode<>SM_None then
  2218. internalerror(200312021);
  2219. if tmpref.signindex<0 then
  2220. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  2221. else
  2222. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  2223. if tmpref.offset<>0 then
  2224. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  2225. end
  2226. else
  2227. begin
  2228. if tmpref.base=NR_NO then
  2229. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  2230. else
  2231. if tmpref.offset<>0 then
  2232. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  2233. else
  2234. begin
  2235. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  2236. list.concat(instr);
  2237. add_move_instruction(instr);
  2238. end;
  2239. end;
  2240. end;
  2241. procedure tbasecgarm.fixref(list : TAsmList;var ref : treference);
  2242. var
  2243. tmpreg, tmpreg2 : tregister;
  2244. tmpref : treference;
  2245. l, piclabel : tasmlabel;
  2246. indirection_done : boolean;
  2247. begin
  2248. { absolute symbols can't be handled directly, we've to store the symbol reference
  2249. in the text segment and access it pc relative
  2250. For now, we assume that references where base or index equals to PC are already
  2251. relative, all other references are assumed to be absolute and thus they need
  2252. to be handled extra.
  2253. A proper solution would be to change refoptions to a set and store the information
  2254. if the symbol is absolute or relative there.
  2255. }
  2256. { create consts entry }
  2257. reference_reset(tmpref,4,[]);
  2258. current_asmdata.getjumplabel(l);
  2259. cg.a_label(current_procinfo.aktlocaldata,l);
  2260. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  2261. piclabel:=nil;
  2262. tmpreg:=NR_NO;
  2263. indirection_done:=false;
  2264. if assigned(ref.symbol) then
  2265. begin
  2266. if (target_info.system=system_arm_darwin) and
  2267. (ref.symbol.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL,AB_PRIVATE_EXTERN,AB_COMMON]) then
  2268. begin
  2269. tmpreg:=g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
  2270. if ref.offset<>0 then
  2271. a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg);
  2272. indirection_done:=true;
  2273. end
  2274. else if ref.refaddr=addr_gottpoff then
  2275. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_gottpoff,ref.symbol,ref.relsymbol,ref.offset))
  2276. else if ref.refaddr=addr_tlsgd then
  2277. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_tlsgd,ref.symbol,ref.relsymbol,ref.offset))
  2278. else if ref.refaddr=addr_tlsdesc then
  2279. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_tlsdesc,ref.symbol,ref.relsymbol,ref.offset))
  2280. else if ref.refaddr=addr_tpoff then
  2281. begin
  2282. if assigned(ref.relsymbol) or (ref.offset<>0) then
  2283. Internalerror(2019092804);
  2284. current_procinfo.aktlocaldata.concat(tai_const.Create_type_sym(aitconst_tpoff,ref.symbol));
  2285. end
  2286. else if (cs_create_pic in current_settings.moduleswitches) then
  2287. if (tf_pic_uses_got in target_info.flags) then
  2288. current_procinfo.aktlocaldata.concat(tai_const.Create_type_sym(aitconst_got,ref.symbol))
  2289. else
  2290. begin
  2291. { ideally, we would want to generate
  2292. ldr r1, LPICConstPool
  2293. LPICLocal:
  2294. ldr/str r2,[pc,r1]
  2295. ...
  2296. LPICConstPool:
  2297. .long _globsym-(LPICLocal+8)
  2298. However, we cannot be sure that the ldr/str will follow
  2299. right after the call to fixref, so we have to load the
  2300. complete address already in a register.
  2301. }
  2302. current_asmdata.getaddrlabel(piclabel);
  2303. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_ptr,piclabel,ref.symbol,ref.offset-8));
  2304. end
  2305. else
  2306. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  2307. end
  2308. else
  2309. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  2310. { load consts entry }
  2311. if not indirection_done then
  2312. begin
  2313. tmpreg:=getintregister(list,OS_INT);
  2314. tmpref.symbol:=l;
  2315. tmpref.base:=NR_PC;
  2316. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  2317. if (cs_create_pic in current_settings.moduleswitches) and
  2318. (tf_pic_uses_got in target_info.flags) and
  2319. assigned(ref.symbol) then
  2320. begin
  2321. {$ifdef EXTDEBUG}
  2322. if not (pi_needs_got in current_procinfo.flags) then
  2323. Comment(V_warning,'pi_needs_got not included');
  2324. {$endif EXTDEBUG}
  2325. Include(current_procinfo.flags,pi_needs_got);
  2326. reference_reset(tmpref,4,[]);
  2327. tmpref.base:=current_procinfo.got;
  2328. tmpref.index:=tmpreg;
  2329. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  2330. if ref.offset<>0 then
  2331. a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg);
  2332. end;
  2333. end;
  2334. if assigned(piclabel) then
  2335. begin
  2336. cg.a_label(list,piclabel);
  2337. tmpreg2:=getaddressregister(list);
  2338. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpreg,NR_PC,tmpreg2);
  2339. tmpreg:=tmpreg2
  2340. end;
  2341. { This routine can be called with PC as base/index in case the offset
  2342. was too large to encode in a load/store. In that case, the entire
  2343. absolute expression has been re-encoded in a new constpool entry, and
  2344. we have to remove the use of PC from the original reference (the code
  2345. above made everything relative to the value loaded from the new
  2346. constpool entry) }
  2347. if is_pc(ref.base) then
  2348. ref.base:=NR_NO;
  2349. if is_pc(ref.index) then
  2350. ref.index:=NR_NO;
  2351. if (ref.base<>NR_NO) then
  2352. begin
  2353. if ref.index<>NR_NO then
  2354. begin
  2355. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  2356. ref.base:=tmpreg;
  2357. end
  2358. else
  2359. if ref.base<>NR_PC then
  2360. begin
  2361. ref.index:=tmpreg;
  2362. ref.shiftimm:=0;
  2363. ref.signindex:=1;
  2364. ref.shiftmode:=SM_None;
  2365. end
  2366. else
  2367. ref.base:=tmpreg;
  2368. end
  2369. else
  2370. ref.base:=tmpreg;
  2371. ref.offset:=0;
  2372. ref.symbol:=nil;
  2373. end;
  2374. procedure tbasecgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  2375. var
  2376. paraloc1,paraloc2,paraloc3 : TCGPara;
  2377. pd : tprocdef;
  2378. begin
  2379. pd:=search_system_proc('MOVE');
  2380. paraloc1.init;
  2381. paraloc2.init;
  2382. paraloc3.init;
  2383. paramanager.getintparaloc(list,pd,1,paraloc1);
  2384. paramanager.getintparaloc(list,pd,2,paraloc2);
  2385. paramanager.getintparaloc(list,pd,3,paraloc3);
  2386. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  2387. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  2388. a_loadaddr_ref_cgpara(list,source,paraloc1);
  2389. paramanager.freecgpara(list,paraloc3);
  2390. paramanager.freecgpara(list,paraloc2);
  2391. paramanager.freecgpara(list,paraloc1);
  2392. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2393. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  2394. a_call_name(list,'FPC_MOVE',false);
  2395. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  2396. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2397. paraloc3.done;
  2398. paraloc2.done;
  2399. paraloc1.done;
  2400. end;
  2401. procedure tbasecgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : tcgint;aligned : boolean);
  2402. const
  2403. maxtmpreg_arm = 10; {roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
  2404. maxtmpreg_thumb = 5;
  2405. var
  2406. srcref,dstref,usedtmpref,usedtmpref2:treference;
  2407. srcreg,destreg,countreg,r,tmpreg:tregister;
  2408. helpsize:aint;
  2409. copysize:byte;
  2410. cgsize:Tcgsize;
  2411. tmpregisters:array[1..maxtmpreg_arm] of tregister;
  2412. maxtmpreg,
  2413. tmpregi,tmpregi2:byte;
  2414. { will never be called with count<=4 }
  2415. procedure genloop(count : aword;size : byte);
  2416. const
  2417. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  2418. var
  2419. l : tasmlabel;
  2420. begin
  2421. current_asmdata.getjumplabel(l);
  2422. if count<size then size:=1;
  2423. a_load_const_reg(list,OS_INT,count div size,countreg);
  2424. cg.a_label(list,l);
  2425. srcref.addressmode:=AM_POSTINDEXED;
  2426. dstref.addressmode:=AM_POSTINDEXED;
  2427. srcref.offset:=size;
  2428. dstref.offset:=size;
  2429. r:=getintregister(list,size2opsize[size]);
  2430. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  2431. a_reg_alloc(list,NR_DEFAULTFLAGS);
  2432. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  2433. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  2434. a_jmp_flags(list,F_NE,l);
  2435. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2436. srcref.offset:=1;
  2437. dstref.offset:=1;
  2438. case count mod size of
  2439. 1:
  2440. begin
  2441. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2442. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2443. end;
  2444. 2:
  2445. if aligned then
  2446. begin
  2447. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  2448. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  2449. end
  2450. else
  2451. begin
  2452. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2453. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2454. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2455. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2456. end;
  2457. 3:
  2458. if aligned then
  2459. begin
  2460. srcref.offset:=2;
  2461. dstref.offset:=2;
  2462. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  2463. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  2464. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2465. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2466. end
  2467. else
  2468. begin
  2469. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2470. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2471. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2472. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2473. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2474. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2475. end;
  2476. end;
  2477. { keep the registers alive }
  2478. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  2479. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  2480. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  2481. end;
  2482. { save estimation, if a creating a separate ref is needed or
  2483. if we can keep the original reference while copying }
  2484. function SimpleRef(const ref : treference) : boolean;
  2485. begin
  2486. result:=((ref.base=NR_PC) and (ref.addressmode=AM_OFFSET) and (ref.refaddr in [addr_full,addr_no])) or
  2487. ((ref.symbol=nil) and
  2488. (ref.addressmode=AM_OFFSET) and
  2489. (((ref.offset>=0) and (ref.offset+len<=31)) or
  2490. (not(GenerateThumbCode) and (ref.offset>=-255) and (ref.offset+len<=255)) or
  2491. { ldrh has a limited offset range }
  2492. (not(GenerateThumbCode) and ((len mod 4) in [0,1]) and (ref.offset>=-4095) and (ref.offset+len<=4095))
  2493. )
  2494. );
  2495. end;
  2496. { will never be called with count<=4 }
  2497. procedure genloop_thumb(count : aword;size : byte);
  2498. procedure refincofs(const ref : treference;const value : longint = 1);
  2499. begin
  2500. a_op_const_reg(list,OP_ADD,OS_ADDR,value,ref.base);
  2501. end;
  2502. const
  2503. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  2504. var
  2505. l : tasmlabel;
  2506. begin
  2507. current_asmdata.getjumplabel(l);
  2508. if count<size then size:=1;
  2509. a_load_const_reg(list,OS_INT,count div size,countreg);
  2510. cg.a_label(list,l);
  2511. r:=getintregister(list,size2opsize[size]);
  2512. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  2513. refincofs(srcref);
  2514. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  2515. refincofs(dstref);
  2516. a_reg_alloc(list,NR_DEFAULTFLAGS);
  2517. list.concat(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1));
  2518. a_jmp_flags(list,F_NE,l);
  2519. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2520. case count mod size of
  2521. 1:
  2522. begin
  2523. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2524. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2525. end;
  2526. 2:
  2527. if aligned then
  2528. begin
  2529. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  2530. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  2531. end
  2532. else
  2533. begin
  2534. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2535. refincofs(srcref);
  2536. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2537. refincofs(dstref);
  2538. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2539. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2540. end;
  2541. 3:
  2542. if aligned then
  2543. begin
  2544. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  2545. refincofs(srcref,2);
  2546. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  2547. refincofs(dstref,2);
  2548. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2549. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2550. end
  2551. else
  2552. begin
  2553. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2554. refincofs(srcref);
  2555. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2556. refincofs(dstref);
  2557. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2558. refincofs(srcref);
  2559. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2560. refincofs(dstref);
  2561. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2562. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2563. end;
  2564. end;
  2565. { keep the registers alive }
  2566. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  2567. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  2568. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  2569. end;
  2570. begin
  2571. if len=0 then
  2572. exit;
  2573. if GenerateThumbCode then
  2574. maxtmpreg:=maxtmpreg_thumb
  2575. else
  2576. maxtmpreg:=maxtmpreg_arm;
  2577. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  2578. dstref:=dest;
  2579. srcref:=source;
  2580. if cs_opt_size in current_settings.optimizerswitches then
  2581. helpsize:=8;
  2582. if aligned and (len=4) then
  2583. begin
  2584. tmpreg:=getintregister(list,OS_32);
  2585. a_load_ref_reg(list,OS_32,OS_32,source,tmpreg);
  2586. a_load_reg_ref(list,OS_32,OS_32,tmpreg,dest);
  2587. end
  2588. else if aligned and (len=2) then
  2589. begin
  2590. tmpreg:=getintregister(list,OS_16);
  2591. a_load_ref_reg(list,OS_16,OS_16,source,tmpreg);
  2592. a_load_reg_ref(list,OS_16,OS_16,tmpreg,dest);
  2593. end
  2594. else if (len<=helpsize) and aligned then
  2595. begin
  2596. tmpregi:=0;
  2597. { loading address in a separate register needed? }
  2598. if SimpleRef(source) then
  2599. begin
  2600. { ... then we don't need a loadaddr }
  2601. srcref:=source;
  2602. end
  2603. else
  2604. begin
  2605. srcreg:=getintregister(list,OS_ADDR);
  2606. a_loadaddr_ref_reg(list,source,srcreg);
  2607. reference_reset_base(srcref,srcreg,0,source.temppos,source.alignment,source.volatility);
  2608. end;
  2609. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  2610. begin
  2611. inc(tmpregi);
  2612. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  2613. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  2614. inc(srcref.offset,4);
  2615. dec(len,4);
  2616. end;
  2617. { loading address in a separate register needed? }
  2618. if SimpleRef(dest) then
  2619. dstref:=dest
  2620. else
  2621. begin
  2622. destreg:=getintregister(list,OS_ADDR);
  2623. a_loadaddr_ref_reg(list,dest,destreg);
  2624. reference_reset_base(dstref,destreg,0,dest.temppos,dest.alignment,dest.volatility);
  2625. end;
  2626. tmpregi2:=1;
  2627. while (tmpregi2<=tmpregi) do
  2628. begin
  2629. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  2630. inc(dstref.offset,4);
  2631. inc(tmpregi2);
  2632. end;
  2633. copysize:=4;
  2634. cgsize:=OS_32;
  2635. while len<>0 do
  2636. begin
  2637. if len<2 then
  2638. begin
  2639. copysize:=1;
  2640. cgsize:=OS_8;
  2641. end
  2642. else if len<4 then
  2643. begin
  2644. copysize:=2;
  2645. cgsize:=OS_16;
  2646. end;
  2647. dec(len,copysize);
  2648. r:=getintregister(list,cgsize);
  2649. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  2650. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  2651. inc(srcref.offset,copysize);
  2652. inc(dstref.offset,copysize);
  2653. end;{end of while}
  2654. end
  2655. else
  2656. begin
  2657. cgsize:=OS_32;
  2658. if (len<=4) then{len<=4 and not aligned}
  2659. begin
  2660. r:=getintregister(list,cgsize);
  2661. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2662. if Len=1 then
  2663. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  2664. else
  2665. begin
  2666. tmpreg:=getintregister(list,cgsize);
  2667. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2668. inc(usedtmpref.offset,1);
  2669. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2670. inc(usedtmpref2.offset,1);
  2671. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  2672. if len>2 then
  2673. begin
  2674. inc(usedtmpref.offset,1);
  2675. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2676. inc(usedtmpref2.offset,1);
  2677. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  2678. if len>3 then
  2679. begin
  2680. inc(usedtmpref.offset,1);
  2681. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2682. inc(usedtmpref2.offset,1);
  2683. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  2684. end;
  2685. end;
  2686. end;
  2687. end{end of if len<=4}
  2688. else
  2689. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  2690. destreg:=getintregister(list,OS_ADDR);
  2691. a_loadaddr_ref_reg(list,dest,destreg);
  2692. reference_reset_base(dstref,destreg,0,dest.temppos,dest.alignment,dest.volatility);
  2693. srcreg:=getintregister(list,OS_ADDR);
  2694. a_loadaddr_ref_reg(list,source,srcreg);
  2695. reference_reset_base(srcref,srcreg,0,dest.temppos,source.alignment,source.volatility);
  2696. countreg:=getintregister(list,OS_32);
  2697. // if cs_opt_size in current_settings.optimizerswitches then
  2698. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  2699. {if aligned then
  2700. genloop(len,4)
  2701. else}
  2702. if GenerateThumbCode then
  2703. genloop_thumb(len,1)
  2704. else
  2705. genloop(len,1);
  2706. end;
  2707. end;
  2708. end;
  2709. procedure tbasecgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);
  2710. begin
  2711. g_concatcopy_internal(list,source,dest,len,false);
  2712. end;
  2713. procedure tbasecgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2714. begin
  2715. if (source.alignment in [1,3]) or
  2716. (dest.alignment in [1,3]) then
  2717. g_concatcopy_internal(list,source,dest,len,false)
  2718. else
  2719. g_concatcopy_internal(list,source,dest,len,true);
  2720. end;
  2721. procedure tbasecgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  2722. var
  2723. ovloc : tlocation;
  2724. begin
  2725. ovloc.loc:=LOC_VOID;
  2726. g_overflowCheck_loc(list,l,def,ovloc);
  2727. end;
  2728. procedure tbasecgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  2729. var
  2730. hl : tasmlabel;
  2731. ai:TAiCpu;
  2732. hflags : tresflags;
  2733. begin
  2734. if not(cs_check_overflow in current_settings.localswitches) then
  2735. exit;
  2736. current_asmdata.getjumplabel(hl);
  2737. case ovloc.loc of
  2738. LOC_VOID:
  2739. begin
  2740. ai:=taicpu.op_sym(A_B,hl);
  2741. ai.is_jmp:=true;
  2742. if not((def.typ=pointerdef) or
  2743. ((def.typ=orddef) and
  2744. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2745. pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2746. ai.SetCondition(C_VC)
  2747. else
  2748. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  2749. ai.SetCondition(C_CS)
  2750. else
  2751. ai.SetCondition(C_CC);
  2752. list.concat(ai);
  2753. end;
  2754. LOC_FLAGS:
  2755. begin
  2756. hflags:=ovloc.resflags;
  2757. inverse_flags(hflags);
  2758. cg.a_jmp_flags(list,hflags,hl);
  2759. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2760. end;
  2761. else
  2762. internalerror(200409281);
  2763. end;
  2764. a_call_name(list,'FPC_OVERFLOW',false);
  2765. a_label(list,hl);
  2766. end;
  2767. procedure tbasecgarm.g_save_registers(list : TAsmList);
  2768. begin
  2769. { this work is done in g_proc_entry }
  2770. end;
  2771. procedure tbasecgarm.g_restore_registers(list : TAsmList);
  2772. begin
  2773. { this work is done in g_proc_exit }
  2774. end;
  2775. procedure tbasecgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2776. var
  2777. ai : taicpu;
  2778. hlabel : TAsmLabel;
  2779. begin
  2780. if GenerateThumbCode then
  2781. begin
  2782. { the optimizer has to fix this if jump range is sufficient short }
  2783. current_asmdata.getjumplabel(hlabel);
  2784. ai:=Taicpu.Op_sym(A_B,hlabel);
  2785. ai.SetCondition(inverse_cond(OpCmp2AsmCond[cond]));
  2786. ai.is_jmp:=true;
  2787. list.concat(ai);
  2788. a_jmp_always(list,l);
  2789. a_label(list,hlabel);
  2790. end
  2791. else
  2792. begin
  2793. ai:=Taicpu.Op_sym(A_B,l);
  2794. ai.SetCondition(OpCmp2AsmCond[cond]);
  2795. ai.is_jmp:=true;
  2796. list.concat(ai);
  2797. end;
  2798. end;
  2799. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  2800. const
  2801. convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of tasmop = (
  2802. (A_VMOV,A_VCVT,A_NONE,A_NONE,A_NONE),
  2803. (A_VCVT,A_VMOV,A_NONE,A_NONE,A_NONE),
  2804. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2805. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2806. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE));
  2807. begin
  2808. result:=convertop[fromsize,tosize];
  2809. if result=A_NONE then
  2810. internalerror(200312205);
  2811. end;
  2812. function get_scalar_mm_prefix(fromsize,tosize : tcgsize) : TOpPostfix;
  2813. const
  2814. convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of TOpPostfix = (
  2815. (PF_F32, PF_F32F64,PF_None,PF_None,PF_None),
  2816. (PF_F64F32,PF_F64, PF_None,PF_None,PF_None),
  2817. (PF_None, PF_None, PF_None,PF_None,PF_None),
  2818. (PF_None, PF_None, PF_None,PF_None,PF_None),
  2819. (PF_None, PF_None, PF_None,PF_None,PF_None));
  2820. begin
  2821. result:=convertop[fromsize,tosize];
  2822. end;
  2823. procedure tbasecgarm.a_loadmm_reg_reg(list: tasmlist; fromsize,tosize: tcgsize; reg1,reg2: tregister; shuffle: pmmshuffle);
  2824. var
  2825. instr: taicpu;
  2826. begin
  2827. if (shuffle=nil) or shufflescalar(shuffle) then
  2828. instr:=setoppostfix(taicpu.op_reg_reg(get_scalar_mm_op(tosize,fromsize),reg2,reg1),get_scalar_mm_prefix(tosize,fromsize))
  2829. else
  2830. internalerror(2009112407);
  2831. list.concat(instr);
  2832. case instr.opcode of
  2833. A_VMOV:
  2834. { VMOV cannot generate an FPU exception, so we do not need a check here }
  2835. add_move_instruction(instr);
  2836. else
  2837. { VCVT can generate an exception }
  2838. maybe_check_for_fpu_exception(list);
  2839. end;
  2840. end;
  2841. procedure tbasecgarm.a_loadmm_ref_reg(list: tasmlist; fromsize,tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  2842. var
  2843. intreg,
  2844. tmpmmreg : tregister;
  2845. reg64 : tregister64;
  2846. begin
  2847. if assigned(shuffle) and
  2848. not(shufflescalar(shuffle)) then
  2849. internalerror(2009112413);
  2850. case fromsize of
  2851. OS_32,OS_S32:
  2852. begin
  2853. fromsize:=OS_F32;
  2854. { since we are loading an integer, no conversion may be required }
  2855. if (fromsize<>tosize) then
  2856. internalerror(2009112801);
  2857. end;
  2858. OS_64,OS_S64:
  2859. begin
  2860. fromsize:=OS_F64;
  2861. { since we are loading an integer, no conversion may be required }
  2862. if (fromsize<>tosize) then
  2863. internalerror(2009112901);
  2864. end;
  2865. OS_F32,OS_F64:
  2866. ;
  2867. else
  2868. internalerror(2019050920);
  2869. end;
  2870. if (fromsize<>tosize) then
  2871. tmpmmreg:=getmmregister(list,fromsize)
  2872. else
  2873. tmpmmreg:=reg;
  2874. if (ref.alignment in [1,2]) then
  2875. begin
  2876. case fromsize of
  2877. OS_F32:
  2878. begin
  2879. intreg:=getintregister(list,OS_32);
  2880. a_load_ref_reg(list,OS_32,OS_32,ref,intreg);
  2881. a_loadmm_intreg_reg(list,OS_32,OS_F32,intreg,tmpmmreg,mms_movescalar);
  2882. end;
  2883. OS_F64:
  2884. begin
  2885. reg64.reglo:=getintregister(list,OS_32);
  2886. reg64.reghi:=getintregister(list,OS_32);
  2887. cg64.a_load64_ref_reg(list,ref,reg64);
  2888. cg64.a_loadmm_intreg64_reg(list,OS_F64,reg64,tmpmmreg);
  2889. end;
  2890. else
  2891. internalerror(2009112412);
  2892. end;
  2893. end
  2894. else
  2895. handle_load_store(list,A_VLDR,PF_None,tmpmmreg,ref);
  2896. if (tmpmmreg<>reg) then
  2897. a_loadmm_reg_reg(list,fromsize,tosize,tmpmmreg,reg,shuffle);
  2898. end;
  2899. procedure tbasecgarm.a_loadmm_reg_ref(list: tasmlist; fromsize,tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  2900. var
  2901. intreg,
  2902. tmpmmreg : tregister;
  2903. reg64 : tregister64;
  2904. begin
  2905. if assigned(shuffle) and
  2906. not(shufflescalar(shuffle)) then
  2907. internalerror(2009112416);
  2908. case tosize of
  2909. OS_32,OS_S32:
  2910. begin
  2911. tosize:=OS_F32;
  2912. { since we are loading an integer, no conversion may be required }
  2913. if (fromsize<>tosize) then
  2914. internalerror(2009112801);
  2915. end;
  2916. OS_64,OS_S64:
  2917. begin
  2918. tosize:=OS_F64;
  2919. { since we are loading an integer, no conversion may be required }
  2920. if (fromsize<>tosize) then
  2921. internalerror(2009112901);
  2922. end;
  2923. OS_F32,OS_F64:
  2924. ;
  2925. else
  2926. internalerror(2019050919);
  2927. end;
  2928. if (fromsize<>tosize) then
  2929. begin
  2930. tmpmmreg:=getmmregister(list,tosize);
  2931. a_loadmm_reg_reg(list,fromsize,tosize,reg,tmpmmreg,shuffle);
  2932. end
  2933. else
  2934. tmpmmreg:=reg;
  2935. if (ref.alignment in [1,2]) then
  2936. begin
  2937. case tosize of
  2938. OS_F32:
  2939. begin
  2940. intreg:=getintregister(list,OS_32);
  2941. a_loadmm_reg_intreg(list,OS_F32,OS_32,tmpmmreg,intreg,shuffle);
  2942. a_load_reg_ref(list,OS_32,OS_32,intreg,ref);
  2943. end;
  2944. OS_F64:
  2945. begin
  2946. reg64.reglo:=getintregister(list,OS_32);
  2947. reg64.reghi:=getintregister(list,OS_32);
  2948. cg64.a_loadmm_reg_intreg64(list,OS_F64,tmpmmreg,reg64);
  2949. cg64.a_load64_reg_ref(list,reg64,ref);
  2950. end;
  2951. else
  2952. internalerror(2009112417);
  2953. end;
  2954. end
  2955. else
  2956. handle_load_store(list,A_VSTR,PF_None,tmpmmreg,ref);
  2957. { VSTR cannot generate an FPU exception, VCVT is handled seperately, so we do not need a check here }
  2958. end;
  2959. procedure tbasecgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  2960. begin
  2961. { this code can only be used to transfer raw data, not to perform
  2962. conversions }
  2963. if (tosize<>OS_F32) then
  2964. internalerror(2009112419);
  2965. if not(fromsize in [OS_32,OS_S32]) then
  2966. internalerror(2009112420);
  2967. if assigned(shuffle) and
  2968. not shufflescalar(shuffle) then
  2969. internalerror(2009112516);
  2970. list.concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg));
  2971. { VMOV cannot generate an FPU exception, so we do not need a check here }
  2972. end;
  2973. procedure tbasecgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
  2974. begin
  2975. { this code can only be used to transfer raw data, not to perform
  2976. conversions }
  2977. if (fromsize<>OS_F32) then
  2978. internalerror(2009112430);
  2979. if not(tosize in [OS_32,OS_S32]) then
  2980. internalerror(2009112420);
  2981. if assigned(shuffle) and
  2982. not shufflescalar(shuffle) then
  2983. internalerror(2009112514);
  2984. list.concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg));
  2985. { VMOV cannot generate an FPU exception, so we do not need a check here }
  2986. end;
  2987. procedure tbasecgarm.a_opmm_reg_reg(list: tasmlist; op: topcg; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle);
  2988. var
  2989. tmpreg: tregister;
  2990. begin
  2991. { the vfp doesn't support xor nor any other logical operation, but
  2992. this routine is used to initialise global mm regvars. We can
  2993. easily initialise an mm reg with 0 though. }
  2994. case op of
  2995. OP_XOR:
  2996. begin
  2997. if (FPUARM_HAS_NEON in fpu_capabilities[current_settings.fputype]) and (size in [OS_F64]) then
  2998. begin
  2999. if (reg_cgsize(src)<>size) or
  3000. assigned(shuffle) then
  3001. internalerror(2019081301);
  3002. list.concat(taicpu.op_reg_reg_reg(A_VEOR,dst,dst,src));
  3003. end
  3004. else
  3005. begin
  3006. if (src<>dst) or
  3007. (reg_cgsize(src)<>size) or
  3008. assigned(shuffle) then
  3009. internalerror(2009112907);
  3010. tmpreg:=getintregister(list,OS_32);
  3011. a_load_const_reg(list,OS_32,0,tmpreg);
  3012. case size of
  3013. OS_F32:
  3014. list.concat(taicpu.op_reg_reg(A_VMOV,dst,tmpreg));
  3015. OS_F64:
  3016. list.concat(taicpu.op_reg_reg_reg(A_VMOV,dst,tmpreg,tmpreg));
  3017. else
  3018. internalerror(2009112908);
  3019. end;
  3020. end;
  3021. end
  3022. else
  3023. internalerror(2009112906);
  3024. end;
  3025. end;
  3026. procedure tbasecgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  3027. const
  3028. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NEG];
  3029. begin
  3030. if (op in overflowops) and
  3031. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  3032. a_load_reg_reg(list,OS_32,size,dst,dst);
  3033. end;
  3034. procedure tbasecgarm.safe_mla(list : TAsmList; op1,op2,op3,op4 : TRegister);
  3035. procedure checkreg(var reg : TRegister);
  3036. var
  3037. tmpreg : TRegister;
  3038. begin
  3039. if ((GenerateThumbCode or GenerateThumb2Code) and (getsupreg(reg)=RS_R13)) or
  3040. (getsupreg(reg)=RS_R15) then
  3041. begin
  3042. tmpreg:=getintregister(list,OS_INT);
  3043. a_load_reg_reg(list,OS_INT,OS_INT,reg,tmpreg);
  3044. reg:=tmpreg;
  3045. end;
  3046. end;
  3047. begin
  3048. checkreg(op1);
  3049. checkreg(op2);
  3050. checkreg(op3);
  3051. checkreg(op4);
  3052. list.concat(taicpu.op_reg_reg_reg_reg(A_MLA,op1,op2,op3,op4));
  3053. end;
  3054. procedure tbasecgarm.g_maybe_tls_init(list : TAsmList);
  3055. begin
  3056. if pi_needs_tls in current_procinfo.flags then
  3057. begin
  3058. list.concat(tai_regalloc.alloc(NR_R0,nil));
  3059. a_call_name(list,'fpc_read_tp',false);
  3060. a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_R0,current_procinfo.tlsoffset);
  3061. list.concat(tai_regalloc.dealloc(NR_R0,nil));
  3062. end;
  3063. end;
  3064. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  3065. begin
  3066. case op of
  3067. OP_NEG:
  3068. begin
  3069. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3070. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  3071. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  3072. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3073. end;
  3074. OP_NOT:
  3075. begin
  3076. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  3077. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  3078. end;
  3079. else
  3080. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  3081. end;
  3082. end;
  3083. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  3084. begin
  3085. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  3086. end;
  3087. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  3088. var
  3089. ovloc : tlocation;
  3090. begin
  3091. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  3092. end;
  3093. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  3094. var
  3095. ovloc : tlocation;
  3096. begin
  3097. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  3098. end;
  3099. procedure tcg64farm.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  3100. begin
  3101. { this code can only be used to transfer raw data, not to perform
  3102. conversions }
  3103. if (mmsize<>OS_F64) then
  3104. internalerror(2009112405);
  3105. list.concat(taicpu.op_reg_reg_reg(A_VMOV,mmreg,intreg.reglo,intreg.reghi));
  3106. { VMOV cannot generate an FPU exception, so we do not need a check here }
  3107. end;
  3108. procedure tcg64farm.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  3109. begin
  3110. { this code can only be used to transfer raw data, not to perform
  3111. conversions }
  3112. if (mmsize<>OS_F64) then
  3113. internalerror(2009112406);
  3114. list.concat(taicpu.op_reg_reg_reg(A_VMOV,intreg.reglo,intreg.reghi,mmreg));
  3115. { VMOV cannot generate an FPU exception, so we do not need a check here }
  3116. end;
  3117. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  3118. var
  3119. tmpreg : tregister;
  3120. b : byte;
  3121. begin
  3122. ovloc.loc:=LOC_VOID;
  3123. case op of
  3124. OP_NEG,
  3125. OP_NOT :
  3126. internalerror(2012022501);
  3127. else
  3128. ;
  3129. end;
  3130. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  3131. begin
  3132. case op of
  3133. OP_ADD:
  3134. begin
  3135. if is_shifter_const(lo(value),b) then
  3136. begin
  3137. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3138. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  3139. end
  3140. else
  3141. begin
  3142. tmpreg:=cg.getintregister(list,OS_32);
  3143. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  3144. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3145. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3146. end;
  3147. if is_shifter_const(hi(value),b) then
  3148. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  3149. else
  3150. begin
  3151. tmpreg:=cg.getintregister(list,OS_32);
  3152. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3153. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  3154. end;
  3155. end;
  3156. OP_SUB:
  3157. begin
  3158. if is_shifter_const(lo(value),b) then
  3159. begin
  3160. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3161. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  3162. end
  3163. else
  3164. begin
  3165. tmpreg:=cg.getintregister(list,OS_32);
  3166. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  3167. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3168. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3169. end;
  3170. if is_shifter_const(hi(value),b) then
  3171. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  3172. else
  3173. begin
  3174. tmpreg:=cg.getintregister(list,OS_32);
  3175. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3176. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  3177. end;
  3178. end;
  3179. else
  3180. internalerror(200502131);
  3181. end;
  3182. if size=OS_64 then
  3183. begin
  3184. { the arm has an weired opinion how flags for SUB/ADD are handled }
  3185. ovloc.loc:=LOC_FLAGS;
  3186. case op of
  3187. OP_ADD:
  3188. ovloc.resflags:=F_CS;
  3189. OP_SUB:
  3190. ovloc.resflags:=F_CC;
  3191. else
  3192. internalerror(2019050918);
  3193. end;
  3194. end;
  3195. end
  3196. else
  3197. begin
  3198. case op of
  3199. OP_AND,OP_OR,OP_XOR:
  3200. begin
  3201. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  3202. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  3203. end;
  3204. OP_ADD:
  3205. begin
  3206. if is_shifter_const(aint(lo(value)),b) then
  3207. begin
  3208. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3209. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  3210. end
  3211. else
  3212. begin
  3213. tmpreg:=cg.getintregister(list,OS_32);
  3214. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  3215. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3216. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3217. end;
  3218. if is_shifter_const(aint(hi(value)),b) then
  3219. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  3220. else
  3221. begin
  3222. tmpreg:=cg.getintregister(list,OS_32);
  3223. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  3224. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  3225. end;
  3226. end;
  3227. OP_SUB:
  3228. begin
  3229. if is_shifter_const(aint(lo(value)),b) then
  3230. begin
  3231. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3232. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  3233. end
  3234. else
  3235. begin
  3236. tmpreg:=cg.getintregister(list,OS_32);
  3237. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  3238. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3239. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3240. end;
  3241. if is_shifter_const(aint(hi(value)),b) then
  3242. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  3243. else
  3244. begin
  3245. tmpreg:=cg.getintregister(list,OS_32);
  3246. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3247. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  3248. end;
  3249. end;
  3250. else
  3251. internalerror(2003083101);
  3252. end;
  3253. end;
  3254. end;
  3255. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  3256. begin
  3257. ovloc.loc:=LOC_VOID;
  3258. case op of
  3259. OP_NEG,
  3260. OP_NOT :
  3261. internalerror(2012022502);
  3262. else
  3263. ;
  3264. end;
  3265. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  3266. begin
  3267. case op of
  3268. OP_ADD:
  3269. begin
  3270. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3271. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  3272. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  3273. end;
  3274. OP_SUB:
  3275. begin
  3276. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3277. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  3278. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  3279. end;
  3280. else
  3281. internalerror(2003083101);
  3282. end;
  3283. if size=OS_64 then
  3284. begin
  3285. { the arm has an weired opinion how flags for SUB/ADD are handled }
  3286. ovloc.loc:=LOC_FLAGS;
  3287. case op of
  3288. OP_ADD:
  3289. ovloc.resflags:=F_CS;
  3290. OP_SUB:
  3291. ovloc.resflags:=F_CC;
  3292. else
  3293. internalerror(2019050917);
  3294. end;
  3295. end;
  3296. end
  3297. else
  3298. begin
  3299. case op of
  3300. OP_AND,OP_OR,OP_XOR:
  3301. begin
  3302. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  3303. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  3304. end;
  3305. OP_ADD:
  3306. begin
  3307. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3308. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  3309. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  3310. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3311. end;
  3312. OP_SUB:
  3313. begin
  3314. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3315. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  3316. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  3317. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3318. end;
  3319. else
  3320. internalerror(2003083101);
  3321. end;
  3322. end;
  3323. end;
  3324. procedure tthumbcgarm.init_register_allocators;
  3325. begin
  3326. inherited init_register_allocators;
  3327. if assigned(current_procinfo) and (current_procinfo.framepointer=NR_R7) then
  3328. rg[R_INTREGISTER]:=trgintcputhumb.create(R_INTREGISTER,R_SUBWHOLE,
  3329. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6],first_int_imreg,[])
  3330. else
  3331. rg[R_INTREGISTER]:=trgintcputhumb.create(R_INTREGISTER,R_SUBWHOLE,
  3332. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7],first_int_imreg,[]);
  3333. end;
  3334. procedure tthumbcgarm.done_register_allocators;
  3335. begin
  3336. rg[R_INTREGISTER].free;
  3337. rg[R_FPUREGISTER].free;
  3338. rg[R_MMREGISTER].free;
  3339. inherited done_register_allocators;
  3340. end;
  3341. procedure tthumbcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  3342. var
  3343. ref : treference;
  3344. r : byte;
  3345. regs : tcpuregisterset;
  3346. stackmisalignment : pint;
  3347. registerarea: DWord;
  3348. stack_parameters: Boolean;
  3349. begin
  3350. stack_parameters:=current_procinfo.procdef.stack_tainting_parameter(calleeside);
  3351. LocalSize:=align(LocalSize,4);
  3352. { call instruction does not put anything on the stack }
  3353. stackmisalignment:=0;
  3354. if not(nostackframe) then
  3355. begin
  3356. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3357. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3358. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  3359. { save int registers }
  3360. reference_reset(ref,4,[]);
  3361. ref.index:=NR_STACK_POINTER_REG;
  3362. ref.addressmode:=AM_PREINDEXED;
  3363. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3364. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3365. begin
  3366. //!!!! a_reg_alloc(list,NR_R12);
  3367. //!!!! list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  3368. end;
  3369. { the (old) ARM APCS requires saving both the stack pointer (to
  3370. crawl the stack) and the PC (to identify the function this
  3371. stack frame belongs to) -> also save R12 (= copy of R13 on entry)
  3372. and R15 -- still needs updating for EABI and Darwin, they don't
  3373. need that }
  3374. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3375. regs:=regs+[RS_R7,RS_R14]
  3376. else
  3377. // if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  3378. include(regs,RS_R14);
  3379. { safely estimate stack size }
  3380. if localsize+current_settings.alignment.localalignmax+4>508 then
  3381. begin
  3382. include(rg[R_INTREGISTER].used_in_proc,RS_R4);
  3383. include(regs,RS_R4);
  3384. end;
  3385. registerarea:=0;
  3386. if regs<>[] then
  3387. begin
  3388. for r:=RS_R0 to RS_R15 do
  3389. if r in regs then
  3390. inc(registerarea,4);
  3391. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,regs));
  3392. end;
  3393. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  3394. if stack_parameters or (LocalSize<>0) or
  3395. ((stackmisalignment<>0) and
  3396. ((pi_do_call in current_procinfo.flags) or
  3397. (po_assembler in current_procinfo.procdef.procoptions))) then
  3398. begin
  3399. { do we access stack parameters?
  3400. if yes, the previously estimated stacksize must be used }
  3401. if stack_parameters then
  3402. begin
  3403. if localsize>tcpuprocinfo(current_procinfo).stackframesize then
  3404. begin
  3405. writeln(localsize);
  3406. writeln(tcpuprocinfo(current_procinfo).stackframesize);
  3407. internalerror(2013040601);
  3408. end
  3409. else
  3410. localsize:=tcpuprocinfo(current_procinfo).stackframesize-registerarea;
  3411. end
  3412. else
  3413. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3414. if localsize<508 then
  3415. begin
  3416. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  3417. end
  3418. else if localsize<=1016 then
  3419. begin
  3420. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,508));
  3421. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize-508));
  3422. end
  3423. else
  3424. begin
  3425. a_load_const_reg(list,OS_ADDR,-localsize,NR_R4);
  3426. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R4));
  3427. include(regs,RS_R4);
  3428. //!!!! if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  3429. //!!!! a_reg_alloc(list,NR_R12);
  3430. //!!!! a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3431. //!!!! list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3432. //!!!! a_reg_dealloc(list,NR_R12);
  3433. end;
  3434. end;
  3435. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3436. begin
  3437. list.concat(taicpu.op_reg_reg_const(A_ADD,current_procinfo.framepointer,NR_STACK_POINTER_REG,0));
  3438. end;
  3439. end;
  3440. end;
  3441. procedure tthumbcgarm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  3442. var
  3443. LocalSize : longint;
  3444. r: byte;
  3445. regs : tcpuregisterset;
  3446. registerarea : DWord;
  3447. stackmisalignment: pint;
  3448. stack_parameters : Boolean;
  3449. begin
  3450. if not(nostackframe) then
  3451. begin
  3452. stack_parameters:=current_procinfo.procdef.stack_tainting_parameter(calleeside);
  3453. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3454. include(regs,RS_R15);
  3455. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3456. include(regs,getsupreg(current_procinfo.framepointer));
  3457. registerarea:=0;
  3458. for r:=RS_R0 to RS_R15 do
  3459. if r in regs then
  3460. inc(registerarea,4);
  3461. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  3462. LocalSize:=current_procinfo.calc_stackframe_size;
  3463. if stack_parameters then
  3464. localsize:=tcpuprocinfo(current_procinfo).stackframesize-registerarea
  3465. else
  3466. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3467. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  3468. (target_info.system in systems_darwin) then
  3469. begin
  3470. if (LocalSize<>0) or
  3471. ((stackmisalignment<>0) and
  3472. ((pi_do_call in current_procinfo.flags) or
  3473. (po_assembler in current_procinfo.procdef.procoptions))) then
  3474. begin
  3475. if LocalSize=0 then
  3476. else if LocalSize<=508 then
  3477. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize))
  3478. else if LocalSize<=1016 then
  3479. begin
  3480. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,508));
  3481. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize-508));
  3482. end
  3483. else
  3484. begin
  3485. a_reg_alloc(list,NR_R3);
  3486. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R3);
  3487. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R3));
  3488. a_reg_dealloc(list,NR_R3);
  3489. end;
  3490. end;
  3491. if regs=[] then
  3492. begin
  3493. if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3494. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3495. else
  3496. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3497. end
  3498. else
  3499. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,regs));
  3500. end;
  3501. end
  3502. else if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3503. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3504. else
  3505. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3506. end;
  3507. procedure tthumbcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  3508. var
  3509. oppostfix:toppostfix;
  3510. usedtmpref: treference;
  3511. tmpreg,tmpreg2 : tregister;
  3512. dir : integer;
  3513. begin
  3514. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  3515. FromSize := ToSize;
  3516. case FromSize of
  3517. { signed integer registers }
  3518. OS_8:
  3519. oppostfix:=PF_B;
  3520. OS_S8:
  3521. oppostfix:=PF_SB;
  3522. OS_16:
  3523. oppostfix:=PF_H;
  3524. OS_S16:
  3525. oppostfix:=PF_SH;
  3526. OS_32,
  3527. OS_S32:
  3528. oppostfix:=PF_None;
  3529. else
  3530. InternalError(200308298);
  3531. end;
  3532. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  3533. begin
  3534. if target_info.endian=endian_big then
  3535. dir:=-1
  3536. else
  3537. dir:=1;
  3538. case FromSize of
  3539. OS_16,OS_S16:
  3540. begin
  3541. { only complicated references need an extra loadaddr }
  3542. if assigned(ref.symbol) or
  3543. (ref.index<>NR_NO) or
  3544. (ref.offset<-124) or
  3545. (ref.offset>124) or
  3546. { sometimes the compiler reused registers }
  3547. (reg=ref.index) or
  3548. (reg=ref.base) then
  3549. begin
  3550. tmpreg2:=getintregister(list,OS_INT);
  3551. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3552. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  3553. end
  3554. else
  3555. usedtmpref:=ref;
  3556. if target_info.endian=endian_big then
  3557. inc(usedtmpref.offset,1);
  3558. tmpreg:=getintregister(list,OS_INT);
  3559. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3560. inc(usedtmpref.offset,dir);
  3561. if FromSize=OS_16 then
  3562. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  3563. else
  3564. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  3565. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,8));
  3566. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3567. end;
  3568. OS_32,OS_S32:
  3569. begin
  3570. tmpreg:=getintregister(list,OS_INT);
  3571. { only complicated references need an extra loadaddr }
  3572. if assigned(ref.symbol) or
  3573. (ref.index<>NR_NO) or
  3574. (ref.offset<-124) or
  3575. (ref.offset>124) or
  3576. { sometimes the compiler reused registers }
  3577. (reg=ref.index) or
  3578. (reg=ref.base) then
  3579. begin
  3580. tmpreg2:=getintregister(list,OS_INT);
  3581. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3582. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  3583. end
  3584. else
  3585. usedtmpref:=ref;
  3586. if ref.alignment=2 then
  3587. begin
  3588. if target_info.endian=endian_big then
  3589. inc(usedtmpref.offset,2);
  3590. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  3591. inc(usedtmpref.offset,dir*2);
  3592. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  3593. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,16));
  3594. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3595. end
  3596. else
  3597. begin
  3598. if target_info.endian=endian_big then
  3599. inc(usedtmpref.offset,3);
  3600. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3601. inc(usedtmpref.offset,dir);
  3602. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3603. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,8));
  3604. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3605. inc(usedtmpref.offset,dir);
  3606. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3607. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,16));
  3608. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3609. inc(usedtmpref.offset,dir);
  3610. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3611. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,24));
  3612. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3613. end;
  3614. end
  3615. else
  3616. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3617. end;
  3618. end
  3619. else
  3620. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3621. if (fromsize=OS_S8) and (tosize = OS_16) then
  3622. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  3623. end;
  3624. procedure tthumbcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3625. var
  3626. l : tasmlabel;
  3627. hr : treference;
  3628. begin
  3629. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  3630. internalerror(2002090902);
  3631. if is_thumb_imm(a) then
  3632. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  3633. else
  3634. begin
  3635. reference_reset(hr,4,[]);
  3636. current_asmdata.getjumplabel(l);
  3637. cg.a_label(current_procinfo.aktlocaldata,l);
  3638. hr.symboldata:=current_procinfo.aktlocaldata.last;
  3639. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  3640. hr.symbol:=l;
  3641. hr.base:=NR_PC;
  3642. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  3643. end;
  3644. end;
  3645. procedure tthumbcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  3646. var
  3647. hsym : tsym;
  3648. href,
  3649. tmpref : treference;
  3650. paraloc : Pcgparalocation;
  3651. l : TAsmLabel;
  3652. begin
  3653. { calculate the parameter info for the procdef }
  3654. procdef.init_paraloc_info(callerside);
  3655. hsym:=tsym(procdef.parast.Find('self'));
  3656. if not(assigned(hsym) and
  3657. (hsym.typ=paravarsym)) then
  3658. internalerror(200305251);
  3659. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  3660. while paraloc<>nil do
  3661. with paraloc^ do
  3662. begin
  3663. case loc of
  3664. LOC_REGISTER:
  3665. begin
  3666. if is_thumb_imm(ioffset) then
  3667. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  3668. else
  3669. begin
  3670. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3671. reference_reset(tmpref,4,[]);
  3672. current_asmdata.getjumplabel(l);
  3673. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  3674. cg.a_label(current_procinfo.aktlocaldata,l);
  3675. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3676. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ioffset));
  3677. tmpref.symbol:=l;
  3678. tmpref.base:=NR_PC;
  3679. list.concat(taicpu.op_reg_ref(A_LDR,NR_R4,tmpref));
  3680. a_op_reg_reg(list,OP_SUB,size,NR_R4,register);
  3681. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3682. end;
  3683. end;
  3684. LOC_REFERENCE:
  3685. begin
  3686. { offset in the wrapper needs to be adjusted for the stored
  3687. return address }
  3688. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),ctempposinvalid,sizeof(pint),[]);
  3689. if is_thumb_imm(ioffset) then
  3690. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  3691. else
  3692. begin
  3693. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3694. reference_reset(tmpref,4,[]);
  3695. current_asmdata.getjumplabel(l);
  3696. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  3697. cg.a_label(current_procinfo.aktlocaldata,l);
  3698. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3699. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ioffset));
  3700. tmpref.symbol:=l;
  3701. tmpref.base:=NR_PC;
  3702. list.concat(taicpu.op_reg_ref(A_LDR,NR_R4,tmpref));
  3703. a_op_reg_ref(list,OP_SUB,size,NR_R4,href);
  3704. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3705. end;
  3706. end
  3707. else
  3708. internalerror(200309189);
  3709. end;
  3710. paraloc:=next;
  3711. end;
  3712. end;
  3713. function tthumbcgarm.handle_load_store(list: TAsmList; op: tasmop; oppostfix: toppostfix; reg: tregister; ref: treference): treference;
  3714. var
  3715. href : treference;
  3716. tmpreg : TRegister;
  3717. begin
  3718. href:=ref;
  3719. if { LDR/STR limitations }
  3720. (
  3721. (((op=A_LDR) and (oppostfix=PF_None)) or
  3722. ((op=A_STR) and (oppostfix=PF_None))) and
  3723. (ref.base<>NR_STACK_POINTER_REG) and
  3724. (abs(ref.offset)>124)
  3725. ) or
  3726. { LDRB/STRB limitations }
  3727. (
  3728. (((op=A_LDR) and (oppostfix=PF_B)) or
  3729. ((op=A_LDRB) and (oppostfix=PF_None)) or
  3730. ((op=A_STR) and (oppostfix=PF_B)) or
  3731. ((op=A_STRB) and (oppostfix=PF_None))) and
  3732. ((ref.base=NR_STACK_POINTER_REG) or
  3733. (ref.index=NR_STACK_POINTER_REG) or
  3734. (abs(ref.offset)>31)
  3735. )
  3736. ) or
  3737. { LDRH/STRH limitations }
  3738. (
  3739. (((op=A_LDR) and (oppostfix=PF_H)) or
  3740. ((op=A_LDRH) and (oppostfix=PF_None)) or
  3741. ((op=A_STR) and (oppostfix=PF_H)) or
  3742. ((op=A_STRH) and (oppostfix=PF_None))) and
  3743. ((ref.base=NR_STACK_POINTER_REG) or
  3744. (ref.index=NR_STACK_POINTER_REG) or
  3745. (abs(ref.offset)>62) or
  3746. ((abs(ref.offset) mod 2)<>0)
  3747. )
  3748. ) then
  3749. begin
  3750. tmpreg:=getintregister(list,OS_ADDR);
  3751. a_loadaddr_ref_reg(list,ref,tmpreg);
  3752. reference_reset_base(href,tmpreg,0,ref.temppos,ref.alignment,ref.volatility);
  3753. end
  3754. else if (op=A_LDR) and
  3755. (oppostfix in [PF_None]) and
  3756. (ref.base=NR_STACK_POINTER_REG) and
  3757. (abs(ref.offset)>1020) then
  3758. begin
  3759. tmpreg:=getintregister(list,OS_ADDR);
  3760. a_loadaddr_ref_reg(list,ref,tmpreg);
  3761. reference_reset_base(href,tmpreg,0,ref.temppos,ref.alignment,ref.volatility);
  3762. end
  3763. else if (op=A_LDR) and
  3764. ((oppostfix in [PF_SH,PF_SB]) or
  3765. (abs(ref.offset)>124)) then
  3766. begin
  3767. tmpreg:=getintregister(list,OS_ADDR);
  3768. a_loadaddr_ref_reg(list,ref,tmpreg);
  3769. reference_reset_base(href,tmpreg,0,ref.temppos,ref.alignment,ref.volatility);
  3770. end;
  3771. Result:=inherited handle_load_store(list, op, oppostfix, reg, href);
  3772. end;
  3773. procedure tthumbcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  3774. var
  3775. tmpreg : tregister;
  3776. begin
  3777. case op of
  3778. OP_NEG:
  3779. list.concat(taicpu.op_reg_reg(A_NEG,dst,src));
  3780. OP_NOT:
  3781. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  3782. OP_DIV,OP_IDIV:
  3783. internalerror(200308284);
  3784. OP_ROL:
  3785. begin
  3786. if not(size in [OS_32,OS_S32]) then
  3787. internalerror(2008072801);
  3788. { simulate ROL by ror'ing 32-value }
  3789. tmpreg:=getintregister(list,OS_32);
  3790. a_load_const_reg(list,OS_32,32,tmpreg);
  3791. list.concat(taicpu.op_reg_reg(A_SUB,tmpreg,src));
  3792. list.concat(taicpu.op_reg_reg(A_ROR,dst,src));
  3793. end;
  3794. else
  3795. begin
  3796. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3797. list.concat(setoppostfix(
  3798. taicpu.op_reg_reg(op_reg_opcg2asmop[op],dst,src),op_reg_postfix[op]));
  3799. end;
  3800. end;
  3801. maybeadjustresult(list,op,size,dst);
  3802. end;
  3803. procedure tthumbcgarm.a_op_const_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; dst: tregister);
  3804. var
  3805. tmpreg : tregister;
  3806. {$ifdef DUMMY}
  3807. l1 : longint;
  3808. {$endif DUMMY}
  3809. begin
  3810. //!!! ovloc.loc:=LOC_VOID;
  3811. if {$ifopt R+}(a<>-2147483648) and{$endif} {!!!!!! not setflags and } is_thumb_imm(-a) then
  3812. case op of
  3813. OP_ADD:
  3814. begin
  3815. op:=OP_SUB;
  3816. a:=aint(dword(-a));
  3817. end;
  3818. OP_SUB:
  3819. begin
  3820. op:=OP_ADD;
  3821. a:=aint(dword(-a));
  3822. end
  3823. else
  3824. ;
  3825. end;
  3826. if is_thumb_imm(a) and (op in [OP_ADD,OP_SUB]) then
  3827. begin
  3828. // if cgsetflags or setflags then
  3829. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3830. list.concat(setoppostfix(
  3831. taicpu.op_reg_const(op_reg_opcg2asmop[op],dst,a),op_reg_postfix[op]));
  3832. if (cgsetflags {!!! or setflags }) and (size in [OS_8,OS_16,OS_32]) then
  3833. begin
  3834. //!!! ovloc.loc:=LOC_FLAGS;
  3835. case op of
  3836. OP_ADD:
  3837. //!!! ovloc.resflags:=F_CS;
  3838. ;
  3839. OP_SUB:
  3840. //!!! ovloc.resflags:=F_CC;
  3841. ;
  3842. else
  3843. ;
  3844. end;
  3845. end;
  3846. end
  3847. else
  3848. begin
  3849. { there could be added some more sophisticated optimizations }
  3850. if (op in [OP_MUL,OP_IMUL,OP_DIV,OP_IDIV]) and (a=1) then
  3851. a_load_reg_reg(list,size,size,dst,dst)
  3852. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  3853. a_load_const_reg(list,size,0,dst)
  3854. else if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then
  3855. a_op_reg_reg(list,OP_NEG,size,dst,dst)
  3856. { we do this here instead in the peephole optimizer because
  3857. it saves us a register }
  3858. {$ifdef DUMMY}
  3859. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  3860. a_op_const_reg_reg(list,OP_SHL,size,l1,dst,dst)
  3861. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  3862. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  3863. begin
  3864. if l1>32 then{roozbeh does this ever happen?}
  3865. internalerror(200308296);
  3866. shifterop_reset(so);
  3867. so.shiftmode:=SM_LSL;
  3868. so.shiftimm:=l1;
  3869. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,dst,dst,so));
  3870. end
  3871. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  3872. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  3873. begin
  3874. if l1>32 then{does this ever happen?}
  3875. internalerror(201205181);
  3876. shifterop_reset(so);
  3877. so.shiftmode:=SM_LSL;
  3878. so.shiftimm:=l1;
  3879. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,dst,dst,so));
  3880. end
  3881. else if (op in [OP_MUL,OP_IMUL]) and not(cgsetflags or setflags) and try_optimized_mul32_const_reg_reg(list,a,dst,dst) then
  3882. begin
  3883. { nothing to do on success }
  3884. end
  3885. {$endif DUMMY}
  3886. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  3887. Just using mov x, #0 might allow some easier optimizations down the line. }
  3888. else if (op = OP_AND) and (dword(a)=0) then
  3889. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  3890. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  3891. else if (op = OP_AND) and (not(dword(a))=0) then
  3892. // do nothing
  3893. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  3894. broader range of shifterconstants.}
  3895. {$ifdef DUMMY}
  3896. else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  3897. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,not(dword(a))))
  3898. else if (op = OP_AND) and split_into_shifter_const(not(dword(a)), imm1, imm2) then
  3899. begin
  3900. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm1));
  3901. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm2));
  3902. end
  3903. else if (op in [OP_ADD, OP_SUB, OP_OR]) and
  3904. not(cgsetflags or setflags) and
  3905. split_into_shifter_const(a, imm1, imm2) then
  3906. begin
  3907. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm1));
  3908. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm2));
  3909. end
  3910. {$endif DUMMY}
  3911. else if (op in [OP_SHL, OP_SHR, OP_SAR]) then
  3912. begin
  3913. list.concat(taicpu.op_reg_reg_const(op_reg_opcg2asmop[op],dst,dst,a));
  3914. end
  3915. else
  3916. begin
  3917. tmpreg:=getintregister(list,size);
  3918. a_load_const_reg(list,size,a,tmpreg);
  3919. a_op_reg_reg(list,op,size,tmpreg,dst);
  3920. end;
  3921. end;
  3922. maybeadjustresult(list,op,size,dst);
  3923. end;
  3924. procedure tthumbcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  3925. begin
  3926. if (op=OP_ADD) and (src=NR_R13) and (dst<>NR_R13) and ((a mod 4)=0) and (a>0) and (a<=1020) then
  3927. list.concat(taicpu.op_reg_reg_const(A_ADD,dst,src,a))
  3928. else
  3929. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  3930. end;
  3931. procedure tthumbcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  3932. var
  3933. l1,l2 : tasmlabel;
  3934. ai : taicpu;
  3935. begin
  3936. current_asmdata.getjumplabel(l1);
  3937. current_asmdata.getjumplabel(l2);
  3938. ai:=setcondition(taicpu.op_sym(A_B,l1),flags_to_cond(f));
  3939. ai.is_jmp:=true;
  3940. list.concat(ai);
  3941. list.concat(taicpu.op_reg_const(A_MOV,reg,0));
  3942. list.concat(taicpu.op_sym(A_B,l2));
  3943. cg.a_label(list,l1);
  3944. list.concat(taicpu.op_reg_const(A_MOV,reg,1));
  3945. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3946. cg.a_label(list,l2);
  3947. end;
  3948. procedure tthumb2cgarm.init_register_allocators;
  3949. begin
  3950. inherited init_register_allocators;
  3951. { currently, we save R14 always, so we can use it }
  3952. if (target_info.system<>system_arm_darwin) then
  3953. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3954. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3955. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  3956. else
  3957. { r9 is not available on Darwin according to the llvm code generator }
  3958. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3959. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3960. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  3961. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  3962. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  3963. if FPUARM_HAS_32REGS in fpu_capabilities[current_settings.fputype] then
  3964. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  3965. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  3966. RS_D16,RS_D17,RS_D18,RS_D19,RS_D20,RS_D21,RS_D22,RS_D23,RS_D24,RS_D25,RS_D26,RS_D27,RS_D28,RS_D29,RS_D30,RS_D31,
  3967. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  3968. ],first_mm_imreg,[])
  3969. else if FPUARM_HAS_VFP_EXTENSION in fpu_capabilities[current_settings.fputype] then
  3970. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  3971. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  3972. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  3973. ],first_mm_imreg,[])
  3974. else
  3975. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  3976. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  3977. end;
  3978. procedure tthumb2cgarm.done_register_allocators;
  3979. begin
  3980. rg[R_INTREGISTER].free;
  3981. rg[R_FPUREGISTER].free;
  3982. rg[R_MMREGISTER].free;
  3983. inherited done_register_allocators;
  3984. end;
  3985. procedure tthumb2cgarm.a_call_reg(list : TAsmList;reg: tregister);
  3986. begin
  3987. list.concat(taicpu.op_reg(A_BLX, reg));
  3988. {
  3989. the compiler does not properly set this flag anymore in pass 1, and
  3990. for now we only need it after pass 2 (I hope) (JM)
  3991. if not(pi_do_call in current_procinfo.flags) then
  3992. internalerror(2003060703);
  3993. }
  3994. include(current_procinfo.flags,pi_do_call);
  3995. end;
  3996. procedure tthumb2cgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3997. var
  3998. l : tasmlabel;
  3999. hr : treference;
  4000. begin
  4001. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  4002. internalerror(2002090902);
  4003. if is_thumb32_imm(a) then
  4004. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  4005. else if is_thumb32_imm(not(a)) then
  4006. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  4007. else if (a and $FFFF)=a then
  4008. list.concat(taicpu.op_reg_const(A_MOVW,reg,a))
  4009. else
  4010. begin
  4011. reference_reset(hr,4,[]);
  4012. current_asmdata.getjumplabel(l);
  4013. cg.a_label(current_procinfo.aktlocaldata,l);
  4014. hr.symboldata:=current_procinfo.aktlocaldata.last;
  4015. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  4016. hr.symbol:=l;
  4017. hr.base:=NR_PC;
  4018. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  4019. end;
  4020. end;
  4021. procedure tthumb2cgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  4022. var
  4023. oppostfix:toppostfix;
  4024. usedtmpref: treference;
  4025. tmpreg,tmpreg2 : tregister;
  4026. so : tshifterop;
  4027. dir : integer;
  4028. begin
  4029. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  4030. FromSize := ToSize;
  4031. case FromSize of
  4032. { signed integer registers }
  4033. OS_8:
  4034. oppostfix:=PF_B;
  4035. OS_S8:
  4036. oppostfix:=PF_SB;
  4037. OS_16:
  4038. oppostfix:=PF_H;
  4039. OS_S16:
  4040. oppostfix:=PF_SH;
  4041. OS_32,
  4042. OS_S32:
  4043. oppostfix:=PF_None;
  4044. else
  4045. InternalError(200308299);
  4046. end;
  4047. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  4048. begin
  4049. if target_info.endian=endian_big then
  4050. dir:=-1
  4051. else
  4052. dir:=1;
  4053. case FromSize of
  4054. OS_16,OS_S16:
  4055. begin
  4056. { only complicated references need an extra loadaddr }
  4057. if assigned(ref.symbol) or
  4058. (ref.index<>NR_NO) or
  4059. (ref.offset<-255) or
  4060. (ref.offset>4094) or
  4061. { sometimes the compiler reused registers }
  4062. (reg=ref.index) or
  4063. (reg=ref.base) then
  4064. begin
  4065. tmpreg2:=getintregister(list,OS_INT);
  4066. a_loadaddr_ref_reg(list,ref,tmpreg2);
  4067. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  4068. end
  4069. else
  4070. usedtmpref:=ref;
  4071. if target_info.endian=endian_big then
  4072. inc(usedtmpref.offset,1);
  4073. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  4074. tmpreg:=getintregister(list,OS_INT);
  4075. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  4076. inc(usedtmpref.offset,dir);
  4077. if FromSize=OS_16 then
  4078. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  4079. else
  4080. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  4081. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4082. end;
  4083. OS_32,OS_S32:
  4084. begin
  4085. tmpreg:=getintregister(list,OS_INT);
  4086. { only complicated references need an extra loadaddr }
  4087. if assigned(ref.symbol) or
  4088. (ref.index<>NR_NO) or
  4089. (ref.offset<-255) or
  4090. (ref.offset>4092) or
  4091. { sometimes the compiler reused registers }
  4092. (reg=ref.index) or
  4093. (reg=ref.base) then
  4094. begin
  4095. tmpreg2:=getintregister(list,OS_INT);
  4096. a_loadaddr_ref_reg(list,ref,tmpreg2);
  4097. reference_reset_base(usedtmpref,tmpreg2,0,ref.temppos,ref.alignment,ref.volatility);
  4098. end
  4099. else
  4100. usedtmpref:=ref;
  4101. shifterop_reset(so);so.shiftmode:=SM_LSL;
  4102. if ref.alignment=2 then
  4103. begin
  4104. if target_info.endian=endian_big then
  4105. inc(usedtmpref.offset,2);
  4106. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  4107. inc(usedtmpref.offset,dir*2);
  4108. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  4109. so.shiftimm:=16;
  4110. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4111. end
  4112. else
  4113. begin
  4114. if target_info.endian=endian_big then
  4115. inc(usedtmpref.offset,3);
  4116. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  4117. inc(usedtmpref.offset,dir);
  4118. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4119. so.shiftimm:=8;
  4120. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4121. inc(usedtmpref.offset,dir);
  4122. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4123. so.shiftimm:=16;
  4124. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4125. inc(usedtmpref.offset,dir);
  4126. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4127. so.shiftimm:=24;
  4128. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4129. end;
  4130. end
  4131. else
  4132. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  4133. end;
  4134. end
  4135. else
  4136. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  4137. if (fromsize=OS_S8) and (tosize = OS_16) then
  4138. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  4139. end;
  4140. procedure tthumb2cgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  4141. begin
  4142. if op = OP_NOT then
  4143. begin
  4144. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  4145. case size of
  4146. OS_8: list.concat(taicpu.op_reg_reg(A_UXTB,dst,dst));
  4147. OS_S8: list.concat(taicpu.op_reg_reg(A_SXTB,dst,dst));
  4148. OS_16: list.concat(taicpu.op_reg_reg(A_UXTH,dst,dst));
  4149. OS_S16: list.concat(taicpu.op_reg_reg(A_SXTH,dst,dst));
  4150. OS_32,
  4151. OS_S32:
  4152. ;
  4153. else
  4154. internalerror(2019050916);
  4155. end;
  4156. end
  4157. else
  4158. inherited a_op_reg_reg(list, op, size, src, dst);
  4159. end;
  4160. procedure tthumb2cgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  4161. var
  4162. shift, width : byte;
  4163. tmpreg : tregister;
  4164. so : tshifterop;
  4165. l1 : longint;
  4166. begin
  4167. ovloc.loc:=LOC_VOID;
  4168. if (a<>-2147483648) and is_shifter_const(-a,shift) then
  4169. case op of
  4170. OP_ADD:
  4171. begin
  4172. op:=OP_SUB;
  4173. a:=aint(dword(-a));
  4174. end;
  4175. OP_SUB:
  4176. begin
  4177. op:=OP_ADD;
  4178. a:=aint(dword(-a));
  4179. end
  4180. else
  4181. ;
  4182. end;
  4183. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  4184. case op of
  4185. OP_NEG,OP_NOT,
  4186. OP_DIV,OP_IDIV:
  4187. internalerror(200308285);
  4188. OP_SHL:
  4189. begin
  4190. if a>32 then
  4191. internalerror(2014020703);
  4192. if a<>0 then
  4193. begin
  4194. shifterop_reset(so);
  4195. so.shiftmode:=SM_LSL;
  4196. so.shiftimm:=a;
  4197. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4198. end
  4199. else
  4200. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4201. end;
  4202. OP_ROL:
  4203. begin
  4204. if a>32 then
  4205. internalerror(2014020704);
  4206. if a<>0 then
  4207. begin
  4208. shifterop_reset(so);
  4209. so.shiftmode:=SM_ROR;
  4210. so.shiftimm:=32-a;
  4211. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4212. end
  4213. else
  4214. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4215. end;
  4216. OP_ROR:
  4217. begin
  4218. if a>32 then
  4219. internalerror(2014020705);
  4220. if a<>0 then
  4221. begin
  4222. shifterop_reset(so);
  4223. so.shiftmode:=SM_ROR;
  4224. so.shiftimm:=a;
  4225. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4226. end
  4227. else
  4228. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4229. end;
  4230. OP_SHR:
  4231. begin
  4232. if a>32 then
  4233. internalerror(200308292);
  4234. shifterop_reset(so);
  4235. if a<>0 then
  4236. begin
  4237. so.shiftmode:=SM_LSR;
  4238. so.shiftimm:=a;
  4239. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4240. end
  4241. else
  4242. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4243. end;
  4244. OP_SAR:
  4245. begin
  4246. if a>32 then
  4247. internalerror(200308295);
  4248. if a<>0 then
  4249. begin
  4250. shifterop_reset(so);
  4251. so.shiftmode:=SM_ASR;
  4252. so.shiftimm:=a;
  4253. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4254. end
  4255. else
  4256. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4257. end;
  4258. else
  4259. if (op in [OP_SUB, OP_ADD]) and
  4260. ((a < 0) or
  4261. (a > 4095)) then
  4262. begin
  4263. tmpreg:=getintregister(list,size);
  4264. a_load_const_reg(list, size, a, tmpreg);
  4265. if cgsetflags or setflags then
  4266. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4267. list.concat(setoppostfix(
  4268. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4269. end
  4270. else
  4271. begin
  4272. if cgsetflags or setflags then
  4273. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4274. list.concat(setoppostfix(
  4275. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4276. end;
  4277. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  4278. begin
  4279. ovloc.loc:=LOC_FLAGS;
  4280. case op of
  4281. OP_ADD:
  4282. ovloc.resflags:=F_CS;
  4283. OP_SUB:
  4284. ovloc.resflags:=F_CC;
  4285. else
  4286. ;
  4287. end;
  4288. end;
  4289. end
  4290. else
  4291. begin
  4292. { there could be added some more sophisticated optimizations }
  4293. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  4294. a_load_reg_reg(list,size,size,src,dst)
  4295. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  4296. a_load_const_reg(list,size,0,dst)
  4297. else if (op in [OP_IMUL]) and (a=-1) then
  4298. a_op_reg_reg(list,OP_NEG,size,src,dst)
  4299. { we do this here instead in the peephole optimizer because
  4300. it saves us a register }
  4301. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  4302. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  4303. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  4304. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  4305. begin
  4306. if l1>32 then{roozbeh does this ever happen?}
  4307. internalerror(200308296);
  4308. shifterop_reset(so);
  4309. so.shiftmode:=SM_LSL;
  4310. so.shiftimm:=l1;
  4311. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  4312. end
  4313. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  4314. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  4315. begin
  4316. if l1>32 then{does this ever happen?}
  4317. internalerror(201205181);
  4318. shifterop_reset(so);
  4319. so.shiftmode:=SM_LSL;
  4320. so.shiftimm:=l1;
  4321. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  4322. end
  4323. else if (op in [OP_MUL,OP_IMUL]) and not(cgsetflags or setflags) and try_optimized_mul32_const_reg_reg(list,a,src,dst) then
  4324. begin
  4325. { nothing to do on success }
  4326. end
  4327. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  4328. Just using mov x, #0 might allow some easier optimizations down the line. }
  4329. else if (op = OP_AND) and (dword(a)=0) then
  4330. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  4331. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  4332. else if (op = OP_AND) and (not(dword(a))=0) then
  4333. list.concat(taicpu.op_reg_reg(A_MOV,dst,src))
  4334. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  4335. broader range of shifterconstants.}
  4336. {else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  4337. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))}
  4338. else if (op = OP_AND) and is_thumb32_imm(a) then
  4339. list.concat(taicpu.op_reg_reg_const(A_AND,dst,src,dword(a)))
  4340. else if (op = OP_AND) and (a = $FFFF) then
  4341. list.concat(taicpu.op_reg_reg(A_UXTH,dst,src))
  4342. else if (op = OP_AND) and is_thumb32_imm(not(dword(a))) then
  4343. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))
  4344. else if (op = OP_AND) and is_continuous_mask(aword(not(a)), shift, width) then
  4345. begin
  4346. a_load_reg_reg(list,size,size,src,dst);
  4347. list.concat(taicpu.op_reg_const_const(A_BFC,dst,shift,width))
  4348. end
  4349. else
  4350. begin
  4351. tmpreg:=getintregister(list,size);
  4352. a_load_const_reg(list,size,a,tmpreg);
  4353. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  4354. end;
  4355. end;
  4356. maybeadjustresult(list,op,size,dst);
  4357. end;
  4358. const
  4359. op_reg_reg_opcg2asmopThumb2: array[TOpCG] of tasmop =
  4360. (A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NONE,A_MVN,A_ORR,
  4361. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  4362. procedure tthumb2cgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  4363. var
  4364. so : tshifterop;
  4365. tmpreg,overflowreg : tregister;
  4366. asmop : tasmop;
  4367. begin
  4368. ovloc.loc:=LOC_VOID;
  4369. case op of
  4370. OP_NEG,OP_NOT:
  4371. internalerror(200308286);
  4372. OP_ROL:
  4373. begin
  4374. if not(size in [OS_32,OS_S32]) then
  4375. internalerror(2008072801);
  4376. { simulate ROL by ror'ing 32-value }
  4377. tmpreg:=getintregister(list,OS_32);
  4378. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  4379. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  4380. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  4381. end;
  4382. OP_ROR:
  4383. begin
  4384. if not(size in [OS_32,OS_S32]) then
  4385. internalerror(2008072802);
  4386. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  4387. end;
  4388. OP_IMUL,
  4389. OP_MUL:
  4390. begin
  4391. if cgsetflags or setflags then
  4392. begin
  4393. overflowreg:=getintregister(list,size);
  4394. if op=OP_IMUL then
  4395. asmop:=A_SMULL
  4396. else
  4397. asmop:=A_UMULL;
  4398. { the arm doesn't allow that rd and rm are the same }
  4399. if dst=src2 then
  4400. begin
  4401. if dst<>src1 then
  4402. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  4403. else
  4404. begin
  4405. tmpreg:=getintregister(list,size);
  4406. a_load_reg_reg(list,size,size,src2,dst);
  4407. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  4408. end;
  4409. end
  4410. else
  4411. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  4412. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4413. if op=OP_IMUL then
  4414. begin
  4415. shifterop_reset(so);
  4416. so.shiftmode:=SM_ASR;
  4417. so.shiftimm:=31;
  4418. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  4419. end
  4420. else
  4421. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  4422. ovloc.loc:=LOC_FLAGS;
  4423. ovloc.resflags:=F_NE;
  4424. end
  4425. else
  4426. begin
  4427. { the arm doesn't allow that rd and rm are the same }
  4428. if dst=src2 then
  4429. begin
  4430. if dst<>src1 then
  4431. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  4432. else
  4433. begin
  4434. tmpreg:=getintregister(list,size);
  4435. a_load_reg_reg(list,size,size,src2,dst);
  4436. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  4437. end;
  4438. end
  4439. else
  4440. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  4441. end;
  4442. end;
  4443. else
  4444. begin
  4445. if cgsetflags or setflags then
  4446. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4447. {$ifdef dummy}
  4448. { R13 is not allowed for certain instruction operands }
  4449. if op_reg_reg_opcg2asmopThumb2[op] in [A_ADD,A_SUB,A_AND,A_BIC,A_EOR] then
  4450. begin
  4451. if getsupreg(dst)=RS_R13 then
  4452. begin
  4453. tmpreg:=getintregister(list,OS_INT);
  4454. a_load_reg_reg(list,OS_INT,OS_INT,dst,tmpreg);
  4455. dst:=tmpreg;
  4456. end;
  4457. if getsupreg(src1)=RS_R13 then
  4458. begin
  4459. tmpreg:=getintregister(list,OS_INT);
  4460. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg);
  4461. src1:=tmpreg;
  4462. end;
  4463. end;
  4464. {$endif}
  4465. list.concat(setoppostfix(
  4466. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmopThumb2[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4467. end;
  4468. end;
  4469. maybeadjustresult(list,op,size,dst);
  4470. end;
  4471. procedure tthumb2cgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  4472. begin
  4473. list.concat(taicpu.op_cond(A_ITE, flags_to_cond(f)));
  4474. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  4475. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  4476. end;
  4477. procedure tthumb2cgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  4478. var
  4479. ref : treference;
  4480. shift : byte;
  4481. firstfloatreg,lastfloatreg,
  4482. r : byte;
  4483. regs : tcpuregisterset;
  4484. stackmisalignment: pint;
  4485. begin
  4486. LocalSize:=align(LocalSize,4);
  4487. { call instruction does not put anything on the stack }
  4488. stackmisalignment:=0;
  4489. if not(nostackframe) then
  4490. begin
  4491. firstfloatreg:=RS_NO;
  4492. lastfloatreg:=RS_NO;
  4493. { save floating point registers? }
  4494. for r:=RS_F0 to RS_F7 do
  4495. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  4496. begin
  4497. if firstfloatreg=RS_NO then
  4498. firstfloatreg:=r;
  4499. lastfloatreg:=r;
  4500. inc(stackmisalignment,12);
  4501. end;
  4502. a_reg_alloc(list,NR_STACK_POINTER_REG);
  4503. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4504. begin
  4505. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  4506. a_reg_alloc(list,NR_R12);
  4507. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  4508. end;
  4509. { save int registers }
  4510. reference_reset(ref,4,[]);
  4511. ref.index:=NR_STACK_POINTER_REG;
  4512. ref.addressmode:=AM_PREINDEXED;
  4513. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4514. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4515. regs:=regs+[RS_FRAME_POINTER_REG,RS_R14]
  4516. else if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  4517. include(regs,RS_R14);
  4518. if regs<>[] then
  4519. begin
  4520. for r:=RS_R0 to RS_R15 do
  4521. if (r in regs) then
  4522. inc(stackmisalignment,4);
  4523. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4524. end;
  4525. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4526. begin
  4527. { the framepointer now points to the saved R15, so the saved
  4528. framepointer is at R11-12 (for get_caller_frame) }
  4529. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  4530. a_reg_dealloc(list,NR_R12);
  4531. end;
  4532. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4533. if (LocalSize<>0) or
  4534. ((stackmisalignment<>0) and
  4535. ((pi_do_call in current_procinfo.flags) or
  4536. (po_assembler in current_procinfo.procdef.procoptions))) then
  4537. begin
  4538. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4539. if not(is_shifter_const(localsize,shift)) then
  4540. begin
  4541. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  4542. a_reg_alloc(list,NR_R12);
  4543. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4544. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  4545. a_reg_dealloc(list,NR_R12);
  4546. end
  4547. else
  4548. begin
  4549. a_reg_dealloc(list,NR_R12);
  4550. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  4551. end;
  4552. end;
  4553. if firstfloatreg<>RS_NO then
  4554. begin
  4555. reference_reset(ref,4,[]);
  4556. if tg.direction*tcpuprocinfo(current_procinfo).floatregstart>=1023 then
  4557. begin
  4558. a_load_const_reg(list,OS_ADDR,-tcpuprocinfo(current_procinfo).floatregstart,NR_R12);
  4559. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4560. ref.base:=NR_R12;
  4561. end
  4562. else
  4563. begin
  4564. ref.base:=current_procinfo.framepointer;
  4565. ref.offset:=tcpuprocinfo(current_procinfo).floatregstart;
  4566. end;
  4567. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4568. lastfloatreg-firstfloatreg+1,ref));
  4569. end;
  4570. end;
  4571. end;
  4572. procedure tthumb2cgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  4573. var
  4574. ref : treference;
  4575. firstfloatreg,lastfloatreg,
  4576. r : byte;
  4577. shift : byte;
  4578. regs : tcpuregisterset;
  4579. LocalSize : longint;
  4580. stackmisalignment: pint;
  4581. begin
  4582. if not(nostackframe) then
  4583. begin
  4584. stackmisalignment:=0;
  4585. { restore floating point register }
  4586. firstfloatreg:=RS_NO;
  4587. lastfloatreg:=RS_NO;
  4588. { save floating point registers? }
  4589. for r:=RS_F0 to RS_F7 do
  4590. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  4591. begin
  4592. if firstfloatreg=RS_NO then
  4593. firstfloatreg:=r;
  4594. lastfloatreg:=r;
  4595. { floating point register space is already included in
  4596. localsize below by calc_stackframe_size
  4597. inc(stackmisalignment,12);
  4598. }
  4599. end;
  4600. if firstfloatreg<>RS_NO then
  4601. begin
  4602. reference_reset(ref,4,[]);
  4603. if tg.direction*tcpuprocinfo(current_procinfo).floatregstart>=1023 then
  4604. begin
  4605. a_load_const_reg(list,OS_ADDR,-tcpuprocinfo(current_procinfo).floatregstart,NR_R12);
  4606. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4607. ref.base:=NR_R12;
  4608. end
  4609. else
  4610. begin
  4611. ref.base:=current_procinfo.framepointer;
  4612. ref.offset:=tcpuprocinfo(current_procinfo).floatregstart;
  4613. end;
  4614. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4615. lastfloatreg-firstfloatreg+1,ref));
  4616. end;
  4617. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4618. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  4619. begin
  4620. exclude(regs,RS_R14);
  4621. include(regs,RS_R15);
  4622. end;
  4623. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  4624. regs:=regs+[RS_FRAME_POINTER_REG,RS_R15];
  4625. for r:=RS_R0 to RS_R15 do
  4626. if (r in regs) then
  4627. inc(stackmisalignment,4);
  4628. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4629. LocalSize:=current_procinfo.calc_stackframe_size;
  4630. if (LocalSize<>0) or
  4631. ((stackmisalignment<>0) and
  4632. ((pi_do_call in current_procinfo.flags) or
  4633. (po_assembler in current_procinfo.procdef.procoptions))) then
  4634. begin
  4635. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4636. if not(is_shifter_const(LocalSize,shift)) then
  4637. begin
  4638. a_reg_alloc(list,NR_R12);
  4639. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4640. list.concat(taicpu.op_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_R12));
  4641. a_reg_dealloc(list,NR_R12);
  4642. end
  4643. else
  4644. begin
  4645. a_reg_dealloc(list,NR_R12);
  4646. list.concat(taicpu.op_reg_const(A_ADD,NR_STACK_POINTER_REG,LocalSize));
  4647. end;
  4648. end;
  4649. if regs=[] then
  4650. list.concat(taicpu.op_reg(A_BX,NR_R14))
  4651. else
  4652. begin
  4653. reference_reset(ref,4,[]);
  4654. ref.index:=NR_STACK_POINTER_REG;
  4655. ref.addressmode:=AM_PREINDEXED;
  4656. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4657. end;
  4658. end
  4659. else
  4660. list.concat(taicpu.op_reg(A_BX,NR_R14));
  4661. end;
  4662. function tthumb2cgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  4663. var
  4664. tmpreg : tregister;
  4665. tmpref : treference;
  4666. l : tasmlabel;
  4667. begin
  4668. tmpreg:=NR_NO;
  4669. { Be sure to have a base register }
  4670. if (ref.base=NR_NO) then
  4671. begin
  4672. if ref.shiftmode<>SM_None then
  4673. internalerror(2014020706);
  4674. ref.base:=ref.index;
  4675. ref.index:=NR_NO;
  4676. end;
  4677. { absolute symbols can't be handled directly, we've to store the symbol reference
  4678. in the text segment and access it pc relative
  4679. For now, we assume that references where base or index equals to PC are already
  4680. relative, all other references are assumed to be absolute and thus they need
  4681. to be handled extra.
  4682. A proper solution would be to change refoptions to a set and store the information
  4683. if the symbol is absolute or relative there.
  4684. }
  4685. if (assigned(ref.symbol) and
  4686. not(is_pc(ref.base)) and
  4687. not(is_pc(ref.index))
  4688. ) or
  4689. { [#xxx] isn't a valid address operand }
  4690. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  4691. //(ref.offset<-4095) or
  4692. (ref.offset<-255) or
  4693. (ref.offset>4095) or
  4694. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  4695. ((ref.offset<-255) or
  4696. (ref.offset>255)
  4697. )
  4698. ) or
  4699. (((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and
  4700. ((ref.offset<-1020) or
  4701. (ref.offset>1020) or
  4702. ((abs(ref.offset) mod 4)<>0) or
  4703. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  4704. assigned(ref.symbol)
  4705. )
  4706. ) then
  4707. begin
  4708. reference_reset(tmpref,4,[]);
  4709. { load symbol }
  4710. tmpreg:=getintregister(list,OS_INT);
  4711. if assigned(ref.symbol) then
  4712. begin
  4713. current_asmdata.getjumplabel(l);
  4714. cg.a_label(current_procinfo.aktlocaldata,l);
  4715. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  4716. if ref.refaddr=addr_gottpoff then
  4717. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_gottpoff,ref.symbol,ref.relsymbol,ref.offset))
  4718. else if ref.refaddr=addr_tlsgd then
  4719. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_tlsgd,ref.symbol,ref.relsymbol,ref.offset))
  4720. else if ref.refaddr=addr_tlsdesc then
  4721. current_procinfo.aktlocaldata.concat(tai_const.Create_rel_sym_offset(aitconst_tlsdesc,ref.symbol,ref.relsymbol,ref.offset))
  4722. else if ref.refaddr=addr_tpoff then
  4723. begin
  4724. if assigned(ref.relsymbol) or (ref.offset<>0) then
  4725. Internalerror(2019092805);
  4726. current_procinfo.aktlocaldata.concat(tai_const.Create_type_sym(aitconst_tpoff,ref.symbol));
  4727. end
  4728. else
  4729. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  4730. { load consts entry }
  4731. tmpref.symbol:=l;
  4732. tmpref.base:=NR_R15;
  4733. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  4734. { in case of LDF/STF, we got rid of the NR_R15 }
  4735. if is_pc(ref.base) then
  4736. ref.base:=NR_NO;
  4737. if is_pc(ref.index) then
  4738. ref.index:=NR_NO;
  4739. end
  4740. else
  4741. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  4742. if (ref.base<>NR_NO) then
  4743. begin
  4744. if ref.index<>NR_NO then
  4745. begin
  4746. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4747. ref.base:=tmpreg;
  4748. end
  4749. else
  4750. begin
  4751. ref.index:=tmpreg;
  4752. ref.shiftimm:=0;
  4753. ref.signindex:=1;
  4754. ref.shiftmode:=SM_None;
  4755. end;
  4756. end
  4757. else
  4758. ref.base:=tmpreg;
  4759. ref.offset:=0;
  4760. ref.symbol:=nil;
  4761. end;
  4762. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  4763. begin
  4764. if tmpreg<>NR_NO then
  4765. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  4766. else
  4767. begin
  4768. tmpreg:=getintregister(list,OS_ADDR);
  4769. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  4770. ref.base:=tmpreg;
  4771. end;
  4772. ref.offset:=0;
  4773. end;
  4774. { Hack? Thumb2 doesn't allow PC indexed addressing modes(although it does in the specification) }
  4775. if (ref.base=NR_R15) and (ref.index<>NR_NO) and (ref.shiftmode <> sm_none) then
  4776. begin
  4777. tmpreg:=getintregister(list,OS_ADDR);
  4778. list.concat(taicpu.op_reg_reg(A_MOV, tmpreg, NR_R15));
  4779. ref.base := tmpreg;
  4780. end;
  4781. { floating point operations have only limited references
  4782. we expect here, that a base is already set }
  4783. if ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and (ref.index<>NR_NO) then
  4784. begin
  4785. if ref.shiftmode<>SM_none then
  4786. internalerror(200309121);
  4787. if tmpreg<>NR_NO then
  4788. begin
  4789. if ref.base=tmpreg then
  4790. begin
  4791. if ref.signindex<0 then
  4792. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  4793. else
  4794. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  4795. ref.index:=NR_NO;
  4796. end
  4797. else
  4798. begin
  4799. if ref.index<>tmpreg then
  4800. internalerror(200403161);
  4801. if ref.signindex<0 then
  4802. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  4803. else
  4804. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4805. ref.base:=tmpreg;
  4806. ref.index:=NR_NO;
  4807. end;
  4808. end
  4809. else
  4810. begin
  4811. tmpreg:=getintregister(list,OS_ADDR);
  4812. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  4813. ref.base:=tmpreg;
  4814. ref.index:=NR_NO;
  4815. end;
  4816. end;
  4817. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  4818. Result := ref;
  4819. end;
  4820. procedure tthumb2cgarm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister; shuffle: pmmshuffle);
  4821. var
  4822. instr: taicpu;
  4823. begin
  4824. if (fromsize=OS_F32) and
  4825. (tosize=OS_F32) then
  4826. begin
  4827. instr:=setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32);
  4828. list.Concat(instr);
  4829. add_move_instruction(instr);
  4830. { VMOV cannot generate an FPU exception, so we do not need a check here }
  4831. end
  4832. else if (fromsize=OS_F64) and
  4833. (tosize=OS_F64) then
  4834. begin
  4835. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,tregister(longint(reg2)+1),tregister(longint(reg1)+1)), PF_F32));
  4836. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32));
  4837. end
  4838. else if (fromsize=OS_F32) and
  4839. (tosize=OS_F64) then
  4840. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,reg2,reg1), PF_F32))
  4841. begin
  4842. //list.concat(nil);
  4843. end;
  4844. end;
  4845. procedure tthumb2cgarm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  4846. begin
  4847. handle_load_store(list,A_VLDR,PF_None,reg,ref);
  4848. end;
  4849. procedure tthumb2cgarm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  4850. begin
  4851. handle_load_store(list,A_VSTR,PF_None,reg,ref);
  4852. { VSTR cannot generate an FPU exception, so we do not need a check here }
  4853. end;
  4854. procedure tthumb2cgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  4855. begin
  4856. if //(shuffle=nil) and
  4857. (tosize=OS_F32) then
  4858. list.Concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg))
  4859. else
  4860. internalerror(2012100813);
  4861. end;
  4862. procedure tthumb2cgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; mmreg, intreg: tregister; shuffle: pmmshuffle);
  4863. begin
  4864. if //(shuffle=nil) and
  4865. (fromsize=OS_F32) then
  4866. begin
  4867. list.Concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg));
  4868. { VMOV cannot generate an FPU exception, so we do not need a check here }
  4869. end
  4870. else
  4871. internalerror(2012100814);
  4872. end;
  4873. procedure tthumb2cg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  4874. var tmpreg: tregister;
  4875. begin
  4876. case op of
  4877. OP_NEG:
  4878. begin
  4879. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4880. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  4881. tmpreg:=cg.getintregister(list,OS_32);
  4882. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,0));
  4883. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,tmpreg,regsrc.reghi));
  4884. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4885. end;
  4886. else
  4887. inherited a_op64_reg_reg(list, op, size, regsrc, regdst);
  4888. end;
  4889. end;
  4890. procedure tthumbcg64farm.a_op64_reg_reg(list: TAsmList; op: TOpCG; size: tcgsize; regsrc, regdst: tregister64);
  4891. begin
  4892. case op of
  4893. OP_NEG:
  4894. begin
  4895. list.concat(taicpu.op_reg_const(A_MOV,regdst.reglo,0));
  4896. list.concat(taicpu.op_reg_const(A_MOV,regdst.reghi,0));
  4897. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4898. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4899. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4900. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4901. end;
  4902. OP_NOT:
  4903. begin
  4904. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  4905. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  4906. end;
  4907. OP_AND,OP_OR,OP_XOR:
  4908. begin
  4909. cg.a_op_reg_reg(list,op,OS_32,regsrc.reglo,regdst.reglo);
  4910. cg.a_op_reg_reg(list,op,OS_32,regsrc.reghi,regdst.reghi);
  4911. end;
  4912. OP_ADD:
  4913. begin
  4914. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4915. list.concat(taicpu.op_reg_reg(A_ADD,regdst.reglo,regsrc.reglo));
  4916. list.concat(taicpu.op_reg_reg(A_ADC,regdst.reghi,regsrc.reghi));
  4917. end;
  4918. OP_SUB:
  4919. begin
  4920. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4921. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4922. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4923. end;
  4924. else
  4925. internalerror(2003083101);
  4926. end;
  4927. end;
  4928. procedure tthumbcg64farm.a_op64_const_reg(list: TAsmList; op: TOpCG; size: tcgsize; value: int64; reg: tregister64);
  4929. var
  4930. tmpreg : tregister;
  4931. begin
  4932. case op of
  4933. OP_AND,OP_OR,OP_XOR:
  4934. begin
  4935. cg.a_op_const_reg(list,op,OS_32,aint(lo(value)),reg.reglo);
  4936. cg.a_op_const_reg(list,op,OS_32,aint(hi(value)),reg.reghi);
  4937. end;
  4938. OP_ADD:
  4939. begin
  4940. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4941. begin
  4942. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4943. list.concat(taicpu.op_reg_const(A_ADD,reg.reglo,aint(lo(value))));
  4944. end
  4945. else
  4946. begin
  4947. tmpreg:=cg.getintregister(list,OS_32);
  4948. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4949. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4950. list.concat(taicpu.op_reg_reg(A_ADD,reg.reglo,tmpreg));
  4951. end;
  4952. tmpreg:=cg.getintregister(list,OS_32);
  4953. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  4954. list.concat(taicpu.op_reg_reg(A_ADC,reg.reghi,tmpreg));
  4955. end;
  4956. OP_SUB:
  4957. begin
  4958. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4959. begin
  4960. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4961. list.concat(taicpu.op_reg_const(A_SUB,reg.reglo,aint(lo(value))))
  4962. end
  4963. else
  4964. begin
  4965. tmpreg:=cg.getintregister(list,OS_32);
  4966. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4967. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4968. list.concat(taicpu.op_reg_reg(A_SUB,reg.reglo,tmpreg));
  4969. end;
  4970. tmpreg:=cg.getintregister(list,OS_32);
  4971. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  4972. list.concat(taicpu.op_reg_reg(A_SBC,reg.reghi,tmpreg));
  4973. end;
  4974. else
  4975. internalerror(2003083101);
  4976. end;
  4977. end;
  4978. procedure create_codegen;
  4979. begin
  4980. if GenerateThumb2Code then
  4981. begin
  4982. cg:=tthumb2cgarm.create;
  4983. cg64:=tthumb2cg64farm.create;
  4984. casmoptimizer:=TCpuThumb2AsmOptimizer;
  4985. end
  4986. else if GenerateThumbCode then
  4987. begin
  4988. cg:=tthumbcgarm.create;
  4989. cg64:=tthumbcg64farm.create;
  4990. // casmoptimizer:=TCpuThumbAsmOptimizer;
  4991. end
  4992. else
  4993. begin
  4994. cg:=tarmcgarm.create;
  4995. cg64:=tarmcg64farm.create;
  4996. casmoptimizer:=TCpuAsmOptimizer;
  4997. end;
  4998. end;
  4999. end.