cgcpu.pas 212 KB

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