cgcpu.pas 208 KB

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