cgcpu.pas 213 KB

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