cgcpu.pas 212 KB

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