cgcpu.pas 213 KB

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