cgcpu.pas 213 KB

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