cgcpu.pas 138 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the code generator for the i8086
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cgbase,cgobj,cg64f32,cgx86,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. cpubase,parabase,cgutils,
  25. symconst,symdef
  26. ;
  27. type
  28. { tcg8086 }
  29. tcg8086 = class(tcgx86)
  30. procedure init_register_allocators;override;
  31. procedure do_register_allocation(list:TAsmList;headertai:tai);override;
  32. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  33. procedure a_call_name_far(list : TAsmList;const s : string; weak: boolean);
  34. procedure a_call_name_static(list : TAsmList;const s : string);override;
  35. procedure a_call_name_static_far(list : TAsmList;const s : string);
  36. procedure a_call_reg(list : TAsmList;reg : tregister);override;
  37. procedure a_call_reg_far(list : TAsmList;reg : tregister);
  38. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  39. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  42. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  43. procedure push_const(list:TAsmList;size:tcgsize;a:tcgint);
  44. { passing parameter using push instead of mov }
  45. procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  46. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
  47. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  48. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
  49. { move instructions }
  50. procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
  51. procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
  52. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  53. { use a_load_ref_reg_internal() instead }
  54. //procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  55. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  56. { comparison operations }
  57. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  58. l : tasmlabel);override;
  59. procedure a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  60. l : tasmlabel);override;
  61. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  62. procedure a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;const ref: treference; reg : tregister; l : tasmlabel); override;
  63. procedure a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg : tregister; const ref: treference; l : tasmlabel); override;
  64. procedure gen_cmp32_jmp1(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  65. procedure gen_cmp32_jmp2(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);override;
  67. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);override;
  68. procedure g_stackpointer_alloc(list : TAsmList;localsize: longint);override;
  69. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  70. procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  71. procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  72. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);override;
  73. procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
  74. procedure add_move_instruction(instr:Taicpu);override;
  75. protected
  76. procedure a_load_ref_reg_internal(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister;isdirect:boolean);override;
  77. end;
  78. tcg64f8086 = class(tcg64f32)
  79. procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;
  80. procedure a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);override;
  81. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  82. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  83. procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;
  84. private
  85. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  86. end;
  87. procedure create_codegen;
  88. implementation
  89. uses
  90. globals,verbose,systems,cutils,
  91. paramgr,procinfo,fmodule,
  92. rgcpu,rgx86,cpuinfo,
  93. symtype,symsym,symcpu,
  94. tgobj,
  95. hlcgobj;
  96. function use_push(const cgpara:tcgpara):boolean;
  97. begin
  98. result:=(not paramanager.use_fixed_stack) and
  99. assigned(cgpara.location) and
  100. (cgpara.location^.loc=LOC_REFERENCE) and
  101. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  102. end;
  103. procedure tcg8086.init_register_allocators;
  104. begin
  105. inherited init_register_allocators;
  106. if cs_create_pic in current_settings.moduleswitches then
  107. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI],first_int_imreg,[RS_BP])
  108. else
  109. if (cs_useebp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer<>NR_BP) then
  110. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI,RS_BP],first_int_imreg,[])
  111. else
  112. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_BX,RS_SI,RS_DI],first_int_imreg,[RS_BP]);
  113. rg[R_MMXREGISTER]:=trgcpu.create(R_MMXREGISTER,R_SUBNONE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  114. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBWHOLE,[RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7],first_mm_imreg,[]);
  115. rgfpu:=Trgx86fpu.create;
  116. end;
  117. procedure tcg8086.do_register_allocation(list:TAsmList;headertai:tai);
  118. begin
  119. if (pi_needs_got in current_procinfo.flags) then
  120. begin
  121. if getsupreg(current_procinfo.got) < first_int_imreg then
  122. include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
  123. end;
  124. inherited do_register_allocation(list,headertai);
  125. end;
  126. procedure tcg8086.a_call_name(list: TAsmList; const s: string; weak: boolean);
  127. begin
  128. if current_settings.x86memorymodel in x86_far_code_models then
  129. a_call_name_far(list,s,weak)
  130. else
  131. a_call_name_near(list,s,weak);
  132. end;
  133. procedure tcg8086.a_call_name_far(list: TAsmList; const s: string;
  134. weak: boolean);
  135. var
  136. sym : tasmsymbol;
  137. begin
  138. if not(weak) then
  139. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION)
  140. else
  141. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION);
  142. list.concat(taicpu.op_sym(A_CALL,S_FAR,sym));
  143. end;
  144. procedure tcg8086.a_call_name_static(list: TAsmList; const s: string);
  145. begin
  146. if current_settings.x86memorymodel in x86_far_code_models then
  147. a_call_name_static_far(list,s)
  148. else
  149. a_call_name_static_near(list,s);
  150. end;
  151. procedure tcg8086.a_call_name_static_far(list: TAsmList; const s: string);
  152. var
  153. sym : tasmsymbol;
  154. begin
  155. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  156. list.concat(taicpu.op_sym(A_CALL,S_FAR,sym));
  157. end;
  158. procedure tcg8086.a_call_reg(list: TAsmList; reg: tregister);
  159. begin
  160. if current_settings.x86memorymodel in x86_far_code_models then
  161. a_call_reg_far(list,reg)
  162. else
  163. a_call_reg_near(list,reg);
  164. end;
  165. procedure tcg8086.a_call_reg_far(list: TAsmList; reg: tregister);
  166. var
  167. href: treference;
  168. begin
  169. { unfortunately, x86 doesn't have a 'call far reg:reg' instruction, so }
  170. { we have to use a temp }
  171. tg.gettemp(list,4,2,tt_normal,href);
  172. { HACK!!! at this point all registers are allocated, due to the fact that
  173. in the pascal calling convention, all registers are caller saved. This
  174. causes the register allocator to fail on the next move instruction, so we
  175. temporarily deallocate 2 registers.
  176. TODO: figure out a better way to do this. }
  177. cg.ungetcpuregister(list,NR_BX);
  178. cg.ungetcpuregister(list,NR_SI);
  179. a_load_reg_ref(list,OS_32,OS_32,reg,href);
  180. cg.getcpuregister(list,NR_BX);
  181. cg.getcpuregister(list,NR_SI);
  182. href.segment:=NR_NO;
  183. list.concat(taicpu.op_ref(A_CALL,S_FAR,href));
  184. tg.ungettemp(list,href);
  185. end;
  186. procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  187. a: tcgint; reg: TRegister);
  188. type
  189. trox32method=(rm_unspecified,rm_unrolledleftloop,rm_unrolledrightloop,
  190. rm_loopleft,rm_loopright,rm_fast_386);
  191. var
  192. tmpreg: tregister;
  193. op1, op2: TAsmOp;
  194. ax_subreg: tregister;
  195. hl_loop_start: tasmlabel;
  196. ai: taicpu;
  197. use_loop, use_186_fast_shift, use_8086_fast_shift,
  198. use_386_fast_shift: Boolean;
  199. rox32method: trox32method=rm_unspecified;
  200. i: Integer;
  201. rol_amount, ror_amount: TCGInt;
  202. begin
  203. optimize_op_const(size, op, a);
  204. check_register_size(size,reg);
  205. if size in [OS_64, OS_S64] then
  206. internalerror(2013030904);
  207. if size in [OS_32, OS_S32] then
  208. begin
  209. case op of
  210. OP_NONE:
  211. begin
  212. { Opcode is optimized away }
  213. end;
  214. OP_MOVE:
  215. begin
  216. { Optimized, replaced with a simple load }
  217. a_load_const_reg(list,size,a,reg);
  218. end;
  219. OP_ADD, OP_SUB:
  220. begin
  221. get_32bit_ops(op, op1, op2);
  222. { Optimization when the low 16-bits of the constant are 0 }
  223. if aint(a and $FFFF) = 0 then
  224. begin
  225. { use a_op_const_reg to allow the use of inc/dec }
  226. a_op_const_reg(list,op,OS_16,aint(a shr 16),GetNextReg(reg));
  227. end
  228. else
  229. begin
  230. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  231. list.concat(taicpu.op_const_reg(op1,S_W,aint(a and $FFFF),reg));
  232. list.concat(taicpu.op_const_reg(op2,S_W,aint(a shr 16),GetNextReg(reg)));
  233. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  234. end;
  235. end;
  236. OP_AND, OP_OR, OP_XOR:
  237. begin
  238. { low word operation }
  239. if aint(a and $FFFF) = aint(0) then
  240. begin
  241. case op of
  242. OP_AND:
  243. a_load_const_reg(list,OS_16,aint(0),reg);
  244. OP_OR,OP_XOR:
  245. {do nothing};
  246. else
  247. InternalError(2013100701);
  248. end;
  249. end
  250. else if aint(a and $FFFF) = aint($FFFF) then
  251. begin
  252. case op of
  253. OP_AND:
  254. {do nothing};
  255. OP_OR:
  256. a_load_const_reg(list,OS_16,aint($FFFF),reg);
  257. OP_XOR:
  258. list.concat(taicpu.op_reg(A_NOT,S_W,reg));
  259. else
  260. InternalError(2013100701);
  261. end;
  262. end
  263. else
  264. a_op_const_reg(list,op,OS_16,aint(a and $FFFF),reg);
  265. { high word operation }
  266. if aint(a shr 16) = aint(0) then
  267. begin
  268. case op of
  269. OP_AND:
  270. a_load_const_reg(list,OS_16,aint(0),GetNextReg(reg));
  271. OP_OR,OP_XOR:
  272. {do nothing};
  273. else
  274. InternalError(2013100701);
  275. end;
  276. end
  277. else if aint(a shr 16) = aint($FFFF) then
  278. begin
  279. case op of
  280. OP_AND:
  281. {do nothing};
  282. OP_OR:
  283. a_load_const_reg(list,OS_16,aint($FFFF),GetNextReg(reg));
  284. OP_XOR:
  285. list.concat(taicpu.op_reg(A_NOT,S_W,GetNextReg(reg)));
  286. else
  287. InternalError(2013100701);
  288. end;
  289. end
  290. else
  291. a_op_const_reg(list,op,OS_16,aint(a shr 16),GetNextReg(reg));
  292. end;
  293. OP_SHR,OP_SHL,OP_SAR:
  294. begin
  295. a:=a and 31;
  296. { for shl with const >= 16, we can just move the low register
  297. to the high reg, then zero the low register, then do the
  298. remaining part of the shift (by const-16) in 16 bit on the
  299. high register. the same thing applies to shr with low and high
  300. reversed. sar is exactly like shr, except that instead of
  301. zeroing the high register, we sar it by 15. }
  302. if a>=16 then
  303. case op of
  304. OP_SHR:
  305. begin
  306. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  307. a_load_const_reg(list,OS_16,0,GetNextReg(reg));
  308. a_op_const_reg(list,OP_SHR,OS_16,a-16,reg);
  309. end;
  310. OP_SHL:
  311. begin
  312. a_load_reg_reg(list,OS_16,OS_16,reg,GetNextReg(reg));
  313. a_load_const_reg(list,OS_16,0,reg);
  314. a_op_const_reg(list,OP_SHL,OS_16,a-16,GetNextReg(reg));
  315. end;
  316. OP_SAR:
  317. begin
  318. if a=31 then
  319. begin
  320. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  321. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  322. end
  323. else
  324. begin
  325. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),reg);
  326. a_op_const_reg(list,OP_SAR,OS_16,15,GetNextReg(reg));
  327. a_op_const_reg(list,OP_SAR,OS_16,a-16,reg);
  328. end;
  329. end;
  330. else
  331. internalerror(2013060201);
  332. end
  333. else if a<>0 then
  334. begin
  335. use_loop:=a>2;
  336. use_386_fast_shift:=(current_settings.cputype>=cpu_386) and (a>1);
  337. use_186_fast_shift:=not use_386_fast_shift
  338. and (current_settings.cputype>=cpu_186) and (a>2)
  339. and not (cs_opt_size in current_settings.optimizerswitches);
  340. use_8086_fast_shift:=(current_settings.cputype<cpu_186) and (a>2)
  341. and not (cs_opt_size in current_settings.optimizerswitches);
  342. if use_386_fast_shift then
  343. begin
  344. case op of
  345. OP_SHR:
  346. begin
  347. list.concat(taicpu.op_const_reg_reg(A_SHRD,S_W,a,GetNextReg(reg),reg));
  348. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,GetNextReg(reg)));
  349. end;
  350. OP_SAR:
  351. begin
  352. list.concat(taicpu.op_const_reg_reg(A_SHRD,S_W,a,GetNextReg(reg),reg));
  353. list.concat(taicpu.op_const_reg(A_SAR,S_W,a,GetNextReg(reg)));
  354. end;
  355. OP_SHL:
  356. begin
  357. list.concat(taicpu.op_const_reg_reg(A_SHLD,S_W,a,reg,GetNextReg(reg)));
  358. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,reg));
  359. end;
  360. else
  361. internalerror(2017040401);
  362. end;
  363. end
  364. else if use_186_fast_shift then
  365. begin
  366. tmpreg:=getintregister(list,OS_16);
  367. case op of
  368. OP_SHR:
  369. begin
  370. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  371. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,GetNextReg(reg)));
  372. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,reg));
  373. list.concat(taicpu.op_const_reg(A_SHL,S_W,16-a,tmpreg));
  374. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  375. end;
  376. OP_SAR:
  377. begin
  378. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  379. list.concat(taicpu.op_const_reg(A_SAR,S_W,a,GetNextReg(reg)));
  380. list.concat(taicpu.op_const_reg(A_SHR,S_W,a,reg));
  381. list.concat(taicpu.op_const_reg(A_SHL,S_W,16-a,tmpreg));
  382. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  383. end;
  384. OP_SHL:
  385. begin
  386. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  387. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,reg));
  388. list.concat(taicpu.op_const_reg(A_SHL,S_W,a,GetNextReg(reg)));
  389. list.concat(taicpu.op_const_reg(A_SHR,S_W,16-a,tmpreg));
  390. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,GetNextReg(reg)));
  391. end;
  392. else
  393. internalerror(2017040301);
  394. end;
  395. end
  396. else if use_8086_fast_shift then
  397. begin
  398. getcpuregister(list,NR_CX);
  399. a_load_const_reg(list,OS_8,a,NR_CL);
  400. tmpreg:=getintregister(list,OS_16);
  401. case op of
  402. OP_SHR:
  403. begin
  404. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  405. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,GetNextReg(reg)));
  406. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,reg));
  407. if a<>8 then
  408. a_load_const_reg(list,OS_8,16-a,NR_CL);
  409. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,tmpreg));
  410. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  411. end;
  412. OP_SAR:
  413. begin
  414. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  415. list.concat(taicpu.op_reg_reg(A_SAR,S_W,NR_CL,GetNextReg(reg)));
  416. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,reg));
  417. if a<>8 then
  418. a_load_const_reg(list,OS_8,16-a,NR_CL);
  419. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,tmpreg));
  420. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,reg));
  421. end;
  422. OP_SHL:
  423. begin
  424. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  425. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,reg));
  426. list.concat(taicpu.op_reg_reg(A_SHL,S_W,NR_CL,GetNextReg(reg)));
  427. if a<>8 then
  428. a_load_const_reg(list,OS_8,16-a,NR_CL);
  429. list.concat(taicpu.op_reg_reg(A_SHR,S_W,NR_CL,tmpreg));
  430. list.concat(taicpu.op_reg_reg(A_OR,S_W,tmpreg,GetNextReg(reg)));
  431. end;
  432. else
  433. internalerror(2017040301);
  434. end;
  435. ungetcpuregister(list,NR_CX);
  436. end
  437. else if use_loop then
  438. begin
  439. getcpuregister(list,NR_CX);
  440. a_load_const_reg(list,OS_16,a,NR_CX);
  441. current_asmdata.getjumplabel(hl_loop_start);
  442. a_label(list,hl_loop_start);
  443. case op of
  444. OP_SHR:
  445. begin
  446. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  447. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  448. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  449. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  450. end;
  451. OP_SAR:
  452. begin
  453. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  454. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  455. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  456. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  457. end;
  458. OP_SHL:
  459. begin
  460. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  461. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  462. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  463. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  464. end;
  465. else
  466. internalerror(2013030903);
  467. end;
  468. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  469. ai.is_jmp:=true;
  470. list.concat(ai);
  471. ungetcpuregister(list,NR_CX);
  472. end
  473. else
  474. begin
  475. for i:=1 to a do
  476. begin
  477. case op of
  478. OP_SHR:
  479. begin
  480. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  481. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  482. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  483. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  484. end;
  485. OP_SAR:
  486. begin
  487. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  488. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  489. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  490. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  491. end;
  492. OP_SHL:
  493. begin
  494. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  495. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  496. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  497. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  498. end;
  499. else
  500. internalerror(2013030903);
  501. end;
  502. end;
  503. end;
  504. end;
  505. end;
  506. OP_ROL,OP_ROR:
  507. begin
  508. a:=a and 31;
  509. if a=0 then
  510. exit;
  511. if op=OP_ROL then
  512. begin
  513. rol_amount:=a;
  514. ror_amount:=32-a;
  515. end
  516. else
  517. begin
  518. rol_amount:=32-a;
  519. ror_amount:=a;
  520. end;
  521. case rol_amount of
  522. 1,17:
  523. rox32method:=rm_unrolledleftloop;
  524. 2,18:
  525. if current_settings.cputype>=cpu_386 then
  526. rox32method:=rm_fast_386
  527. else if not (cs_opt_size in current_settings.optimizerswitches) then
  528. rox32method:=rm_unrolledleftloop
  529. else
  530. rox32method:=rm_loopleft;
  531. 3..8,19..24:
  532. if current_settings.cputype>=cpu_386 then
  533. rox32method:=rm_fast_386
  534. else
  535. rox32method:=rm_loopleft;
  536. 15,31:
  537. rox32method:=rm_unrolledrightloop;
  538. 14,30:
  539. if current_settings.cputype>=cpu_386 then
  540. rox32method:=rm_fast_386
  541. else if not (cs_opt_size in current_settings.optimizerswitches) then
  542. rox32method:=rm_unrolledrightloop
  543. else
  544. { the left loop has a smaller size }
  545. rox32method:=rm_loopleft;
  546. 9..13,25..29:
  547. if current_settings.cputype>=cpu_386 then
  548. rox32method:=rm_fast_386
  549. else if not (cs_opt_size in current_settings.optimizerswitches) then
  550. rox32method:=rm_loopright
  551. else
  552. { the left loop has a smaller size }
  553. rox32method:=rm_loopleft;
  554. 16:
  555. rox32method:=rm_unrolledleftloop;
  556. else
  557. internalerror(2017040601);
  558. end;
  559. case rox32method of
  560. rm_unrolledleftloop:
  561. begin
  562. if rol_amount>=16 then
  563. begin
  564. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  565. dec(rol_amount,16);
  566. end;
  567. for i:=1 to rol_amount do
  568. begin
  569. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  570. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(reg)));
  571. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,reg));
  572. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(reg)));
  573. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  574. end;
  575. end;
  576. rm_unrolledrightloop:
  577. begin
  578. if ror_amount>=16 then
  579. begin
  580. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  581. dec(ror_amount,16);
  582. end;
  583. tmpreg:=getintregister(list,OS_16);
  584. for i:=1 to ror_amount do
  585. begin
  586. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  587. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  588. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  589. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(reg)));
  590. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  591. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  592. end;
  593. end;
  594. rm_loopleft:
  595. begin
  596. if (rol_amount>=16) and not (cs_opt_size in current_settings.optimizerswitches) then
  597. begin
  598. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  599. dec(rol_amount,16);
  600. if rol_amount=0 then
  601. exit;
  602. end;
  603. getcpuregister(list,NR_CX);
  604. a_load_const_reg(list,OS_16,rol_amount,NR_CX);
  605. current_asmdata.getjumplabel(hl_loop_start);
  606. a_label(list,hl_loop_start);
  607. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  608. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(reg)));
  609. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,reg));
  610. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(reg)));
  611. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  612. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  613. ai.is_jmp:=true;
  614. list.concat(ai);
  615. ungetcpuregister(list,NR_CX);
  616. end;
  617. rm_loopright:
  618. begin
  619. if (ror_amount>=16) and not (cs_opt_size in current_settings.optimizerswitches) then
  620. begin
  621. list.Concat(taicpu.op_reg_reg(A_XCHG,S_W,reg,GetNextReg(reg)));
  622. dec(ror_amount,16);
  623. if ror_amount=0 then
  624. exit;
  625. end;
  626. getcpuregister(list,NR_CX);
  627. a_load_const_reg(list,OS_16,ror_amount,NR_CX);
  628. current_asmdata.getjumplabel(hl_loop_start);
  629. a_label(list,hl_loop_start);
  630. tmpreg:=getintregister(list,OS_16);
  631. a_load_reg_reg(list,OS_16,OS_16,reg,tmpreg);
  632. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  633. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  634. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(reg)));
  635. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  636. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  637. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  638. ai.is_jmp:=true;
  639. list.concat(ai);
  640. ungetcpuregister(list,NR_CX);
  641. end;
  642. rm_fast_386:
  643. begin
  644. tmpreg:=getintregister(list,OS_16);
  645. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(reg),tmpreg);
  646. if op=OP_ROL then
  647. begin
  648. list.Concat(taicpu.op_const_reg_reg(A_SHLD,S_W,rol_amount,reg,GetNextReg(reg)));
  649. list.Concat(taicpu.op_const_reg_reg(A_SHLD,S_W,rol_amount,tmpreg,reg));
  650. end
  651. else
  652. begin
  653. list.Concat(taicpu.op_const_reg_reg(A_SHRD,S_W,ror_amount,reg,GetNextReg(reg)));
  654. list.Concat(taicpu.op_const_reg_reg(A_SHRD,S_W,ror_amount,tmpreg,reg));
  655. end;
  656. end;
  657. else
  658. internalerror(2017040602);
  659. end;
  660. end;
  661. else
  662. begin
  663. tmpreg:=getintregister(list,size);
  664. a_load_const_reg(list,size,a,tmpreg);
  665. a_op_reg_reg(list,op,size,tmpreg,reg);
  666. end;
  667. end;
  668. end
  669. else
  670. begin
  671. { size <= 16-bit }
  672. { 8086 doesn't support 'imul reg,const', so we handle it here }
  673. if (current_settings.cputype<cpu_186) and (op in [OP_MUL,OP_IMUL]) then
  674. begin
  675. if op = OP_IMUL then
  676. begin
  677. if size in [OS_16,OS_S16] then
  678. ax_subreg := NR_AX
  679. else
  680. if size in [OS_8,OS_S8] then
  681. ax_subreg := NR_AL
  682. else
  683. internalerror(2013050102);
  684. getcpuregister(list,NR_AX);
  685. a_load_const_reg(list,size,a,ax_subreg);
  686. if size in [OS_16,OS_S16] then
  687. getcpuregister(list,NR_DX);
  688. { prefer MUL over IMUL when overflow checking is off, }
  689. { because it's faster on the 8086 & 8088 }
  690. if not (cs_check_overflow in current_settings.localswitches) then
  691. list.concat(taicpu.op_reg(A_MUL,TCgSize2OpSize[size],reg))
  692. else
  693. list.concat(taicpu.op_reg(A_IMUL,TCgSize2OpSize[size],reg));
  694. if size in [OS_16,OS_S16] then
  695. ungetcpuregister(list,NR_DX);
  696. a_load_reg_reg(list,size,size,ax_subreg,reg);
  697. ungetcpuregister(list,NR_AX);
  698. exit;
  699. end
  700. else
  701. { OP_MUL should be handled specifically in the code }
  702. { generator because of the silly register usage restraints }
  703. internalerror(200109225);
  704. end
  705. else
  706. inherited a_op_const_reg(list, Op, size, a, reg);
  707. end;
  708. end;
  709. procedure tcg8086.a_op_const_ref(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  710. var
  711. tmpref: treference;
  712. op1,op2: TAsmOp;
  713. tmpreg: TRegister;
  714. begin
  715. optimize_op_const(size, op, a);
  716. tmpref:=ref;
  717. make_simple_ref(list,tmpref);
  718. if size in [OS_64, OS_S64] then
  719. internalerror(2013050801);
  720. if size in [OS_32, OS_S32] then
  721. begin
  722. case Op of
  723. OP_NONE :
  724. begin
  725. { Opcode is optimized away }
  726. end;
  727. OP_MOVE :
  728. begin
  729. { Optimized, replaced with a simple load }
  730. a_load_const_ref(list,size,a,ref);
  731. end;
  732. OP_ADD, OP_SUB:
  733. begin
  734. get_32bit_ops(op, op1, op2);
  735. { Optimization when the low 16-bits of the constant are 0 }
  736. if aint(a and $FFFF) = 0 then
  737. begin
  738. inc(tmpref.offset, 2);
  739. { use a_op_const_ref to allow the use of inc/dec }
  740. a_op_const_ref(list,op,OS_16,aint(a shr 16),tmpref);
  741. end
  742. else
  743. begin
  744. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  745. list.concat(taicpu.op_const_ref(op1,S_W,aint(a and $FFFF),tmpref));
  746. inc(tmpref.offset, 2);
  747. list.concat(taicpu.op_const_ref(op2,S_W,aint(a shr 16),tmpref));
  748. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  749. end;
  750. end;
  751. OP_AND, OP_OR, OP_XOR:
  752. begin
  753. { low word operation }
  754. if aint(a and $FFFF) = aint(0) then
  755. begin
  756. case op of
  757. OP_AND:
  758. a_load_const_ref(list,OS_16,aint(0),ref);
  759. OP_OR,OP_XOR:
  760. {do nothing};
  761. else
  762. InternalError(2013100701);
  763. end;
  764. end
  765. else if aint(a and $FFFF) = aint($FFFF) then
  766. begin
  767. case op of
  768. OP_AND:
  769. {do nothing};
  770. OP_OR:
  771. a_load_const_ref(list,OS_16,aint($FFFF),tmpref);
  772. OP_XOR:
  773. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  774. else
  775. InternalError(2013100701);
  776. end;
  777. end
  778. else
  779. a_op_const_ref(list,op,OS_16,aint(a and $FFFF),tmpref);
  780. { high word operation }
  781. inc(tmpref.offset, 2);
  782. if aint(a shr 16) = aint(0) then
  783. begin
  784. case op of
  785. OP_AND:
  786. a_load_const_ref(list,OS_16,aint(0),tmpref);
  787. OP_OR,OP_XOR:
  788. {do nothing};
  789. else
  790. InternalError(2013100701);
  791. end;
  792. end
  793. else if aint(a shr 16) = aint($FFFF) then
  794. begin
  795. case op of
  796. OP_AND:
  797. {do nothing};
  798. OP_OR:
  799. a_load_const_ref(list,OS_16,aint($FFFF),tmpref);
  800. OP_XOR:
  801. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  802. else
  803. InternalError(2013100701);
  804. end;
  805. end
  806. else
  807. a_op_const_ref(list,op,OS_16,aint(a shr 16),tmpref);
  808. end;
  809. OP_SHR,OP_SHL,OP_SAR:
  810. begin
  811. a:=a and 31;
  812. if a=1 then
  813. begin
  814. case op of
  815. OP_SHR:
  816. begin
  817. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  818. inc(tmpref.offset, 2);
  819. list.concat(taicpu.op_const_ref(A_SHR,S_W,1,tmpref));
  820. dec(tmpref.offset, 2);
  821. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  822. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  823. end;
  824. OP_SAR:
  825. begin
  826. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  827. inc(tmpref.offset, 2);
  828. list.concat(taicpu.op_const_ref(A_SAR,S_W,1,tmpref));
  829. dec(tmpref.offset, 2);
  830. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  831. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  832. end;
  833. OP_SHL:
  834. begin
  835. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  836. list.concat(taicpu.op_const_ref(A_SHL,S_W,1,tmpref));
  837. inc(tmpref.offset, 2);
  838. list.concat(taicpu.op_const_ref(A_RCL,S_W,1,tmpref));
  839. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  840. end;
  841. else
  842. internalerror(2015042501);
  843. end;
  844. end
  845. else
  846. begin
  847. tmpreg:=getintregister(list,size);
  848. a_load_ref_reg(list,size,size,ref,tmpreg);
  849. a_op_const_reg(list,Op,size,a,tmpreg);
  850. a_load_reg_ref(list,size,size,tmpreg,ref);
  851. end;
  852. end;
  853. OP_ROL,OP_ROR:
  854. begin
  855. tmpreg:=getintregister(list,size);
  856. a_load_ref_reg(list,size,size,ref,tmpreg);
  857. a_op_const_reg(list,Op,size,a,tmpreg);
  858. a_load_reg_ref(list,size,size,tmpreg,ref);
  859. end;
  860. else
  861. internalerror(2013050802);
  862. end;
  863. end
  864. else
  865. inherited a_op_const_ref(list,Op,size,a,tmpref);
  866. end;
  867. procedure tcg8086.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  868. src, dst: TRegister);
  869. var
  870. op1, op2: TAsmOp;
  871. hl_skip, hl_loop_start: TAsmLabel;
  872. ai: taicpu;
  873. tmpreg: TRegister;
  874. begin
  875. check_register_size(size,src);
  876. check_register_size(size,dst);
  877. if size in [OS_64, OS_S64] then
  878. internalerror(2013030902);
  879. if size in [OS_32, OS_S32] then
  880. begin
  881. case op of
  882. OP_NEG:
  883. begin
  884. if src<>dst then
  885. a_load_reg_reg(list,size,size,src,dst);
  886. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  887. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  888. list.concat(taicpu.op_reg(A_NEG, S_W, dst));
  889. list.concat(taicpu.op_const_reg(A_SBB, S_W,-1, GetNextReg(dst)));
  890. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  891. end;
  892. OP_NOT:
  893. begin
  894. if src<>dst then
  895. a_load_reg_reg(list,size,size,src,dst);
  896. list.concat(taicpu.op_reg(A_NOT, S_W, dst));
  897. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  898. end;
  899. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  900. begin
  901. get_32bit_ops(op, op1, op2);
  902. if op in [OP_ADD,OP_SUB] then
  903. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  904. list.concat(taicpu.op_reg_reg(op1, S_W, src, dst));
  905. list.concat(taicpu.op_reg_reg(op2, S_W, GetNextReg(src), GetNextReg(dst)));
  906. if op in [OP_ADD,OP_SUB] then
  907. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  908. end;
  909. OP_SHR,OP_SHL,OP_SAR:
  910. begin
  911. getcpuregister(list,NR_CX);
  912. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  913. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  914. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  915. current_asmdata.getjumplabel(hl_skip);
  916. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  917. ai.SetCondition(C_Z);
  918. ai.is_jmp:=true;
  919. list.concat(ai);
  920. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  921. current_asmdata.getjumplabel(hl_loop_start);
  922. a_label(list,hl_loop_start);
  923. case op of
  924. OP_SHR:
  925. begin
  926. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  927. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(dst)));
  928. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  929. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  930. end;
  931. OP_SAR:
  932. begin
  933. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  934. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(dst)));
  935. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  936. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  937. end;
  938. OP_SHL:
  939. begin
  940. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  941. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,dst));
  942. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(dst)));
  943. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  944. end;
  945. else
  946. internalerror(2013030903);
  947. end;
  948. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  949. ai.is_jmp:=true;
  950. list.concat(ai);
  951. a_label(list,hl_skip);
  952. ungetcpuregister(list,NR_CX);
  953. end;
  954. OP_ROL,OP_ROR:
  955. begin
  956. getcpuregister(list,NR_CX);
  957. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  958. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  959. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  960. current_asmdata.getjumplabel(hl_skip);
  961. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  962. ai.SetCondition(C_Z);
  963. ai.is_jmp:=true;
  964. list.concat(ai);
  965. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  966. current_asmdata.getjumplabel(hl_loop_start);
  967. a_label(list,hl_loop_start);
  968. case op of
  969. OP_ROL:
  970. begin
  971. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  972. list.Concat(taicpu.op_const_reg(A_SHL,S_W,1,GetNextReg(dst)));
  973. list.Concat(taicpu.op_const_reg(A_RCL,S_W,1,dst));
  974. list.Concat(taicpu.op_const_reg(A_ADC,S_W,0,GetNextReg(dst)));
  975. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  976. end;
  977. OP_ROR:
  978. begin
  979. tmpreg:=getintregister(list,OS_16);
  980. a_load_reg_reg(list,OS_16,OS_16,dst,tmpreg);
  981. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  982. list.Concat(taicpu.op_const_reg(A_SHR,S_W,1,tmpreg));
  983. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,GetNextReg(dst)));
  984. list.Concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  985. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  986. end;
  987. else
  988. internalerror(2017042502);
  989. end;
  990. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  991. ai.is_jmp:=true;
  992. list.concat(ai);
  993. a_label(list,hl_skip);
  994. ungetcpuregister(list,NR_CX);
  995. end;
  996. else
  997. internalerror(2013030901);
  998. end;
  999. end
  1000. else
  1001. inherited a_op_reg_reg(list, Op, size, src, dst);
  1002. end;
  1003. procedure tcg8086.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  1004. var
  1005. tmpref : treference;
  1006. op1, op2: TAsmOp;
  1007. begin
  1008. tmpref:=ref;
  1009. make_simple_ref(list,tmpref);
  1010. check_register_size(size,reg);
  1011. if size in [OS_64, OS_S64] then
  1012. internalerror(2013030902);
  1013. if size in [OS_32, OS_S32] then
  1014. begin
  1015. case op of
  1016. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  1017. begin
  1018. get_32bit_ops(op, op1, op2);
  1019. if op in [OP_ADD,OP_SUB] then
  1020. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1021. list.concat(taicpu.op_ref_reg(op1, S_W, tmpref, reg));
  1022. inc(tmpref.offset, 2);
  1023. list.concat(taicpu.op_ref_reg(op2, S_W, tmpref, GetNextReg(reg)));
  1024. if op in [OP_ADD,OP_SUB] then
  1025. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1026. end;
  1027. else
  1028. internalerror(2013050701);
  1029. end;
  1030. end
  1031. else
  1032. inherited a_op_ref_reg(list,Op,size,tmpref,reg);
  1033. end;
  1034. procedure tcg8086.a_op_reg_ref(list: TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference);
  1035. var
  1036. tmpref: treference;
  1037. op1,op2: TAsmOp;
  1038. hl_skip, hl_loop_start: TAsmLabel;
  1039. ai: taicpu;
  1040. tmpreg: TRegister;
  1041. begin
  1042. tmpref:=ref;
  1043. make_simple_ref(list,tmpref);
  1044. if not (op in [OP_NEG,OP_NOT,OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR]) then
  1045. check_register_size(size,reg);
  1046. if size in [OS_64, OS_S64] then
  1047. internalerror(2013050803);
  1048. if size in [OS_32, OS_S32] then
  1049. begin
  1050. case op of
  1051. OP_NEG:
  1052. begin
  1053. if reg<>NR_NO then
  1054. internalerror(200109237);
  1055. inc(tmpref.offset, 2);
  1056. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1057. dec(tmpref.offset, 2);
  1058. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1059. list.concat(taicpu.op_ref(A_NEG, S_W, tmpref));
  1060. inc(tmpref.offset, 2);
  1061. list.concat(taicpu.op_const_ref(A_SBB, S_W,-1, tmpref));
  1062. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1063. end;
  1064. OP_NOT:
  1065. begin
  1066. if reg<>NR_NO then
  1067. internalerror(200109237);
  1068. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1069. inc(tmpref.offset, 2);
  1070. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  1071. end;
  1072. OP_IMUL:
  1073. begin
  1074. { this one needs a load/imul/store, which is the default }
  1075. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  1076. end;
  1077. OP_MUL,OP_DIV,OP_IDIV:
  1078. { special stuff, needs separate handling inside code }
  1079. { generator }
  1080. internalerror(200109238);
  1081. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  1082. begin
  1083. get_32bit_ops(op, op1, op2);
  1084. if op in [OP_ADD,OP_SUB] then
  1085. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1086. list.concat(taicpu.op_reg_ref(op1, S_W, reg, tmpref));
  1087. inc(tmpref.offset, 2);
  1088. list.concat(taicpu.op_reg_ref(op2, S_W, GetNextReg(reg), tmpref));
  1089. if op in [OP_ADD,OP_SUB] then
  1090. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1091. end;
  1092. OP_SHR,OP_SHL,OP_SAR:
  1093. begin
  1094. getcpuregister(list,NR_CX);
  1095. a_load_reg_reg(list,size,OS_16,reg,NR_CX);
  1096. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1097. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  1098. current_asmdata.getjumplabel(hl_skip);
  1099. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  1100. ai.SetCondition(C_Z);
  1101. ai.is_jmp:=true;
  1102. list.concat(ai);
  1103. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1104. current_asmdata.getjumplabel(hl_loop_start);
  1105. a_label(list,hl_loop_start);
  1106. case op of
  1107. OP_SHR:
  1108. begin
  1109. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1110. inc(tmpref.offset, 2);
  1111. list.concat(taicpu.op_const_ref(A_SHR,S_W,1,tmpref));
  1112. dec(tmpref.offset, 2);
  1113. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  1114. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1115. end;
  1116. OP_SAR:
  1117. begin
  1118. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1119. inc(tmpref.offset, 2);
  1120. list.concat(taicpu.op_const_ref(A_SAR,S_W,1,tmpref));
  1121. dec(tmpref.offset, 2);
  1122. list.concat(taicpu.op_const_ref(A_RCR,S_W,1,tmpref));
  1123. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1124. end;
  1125. OP_SHL:
  1126. begin
  1127. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1128. list.concat(taicpu.op_const_ref(A_SHL,S_W,1,tmpref));
  1129. inc(tmpref.offset, 2);
  1130. list.concat(taicpu.op_const_ref(A_RCL,S_W,1,tmpref));
  1131. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1132. end;
  1133. else
  1134. internalerror(2013030903);
  1135. end;
  1136. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  1137. ai.is_jmp:=true;
  1138. list.concat(ai);
  1139. a_label(list,hl_skip);
  1140. ungetcpuregister(list,NR_CX);
  1141. end;
  1142. OP_ROL,OP_ROR:
  1143. begin
  1144. tmpreg:=getintregister(list,size);
  1145. a_load_ref_reg(list,size,size,ref,tmpreg);
  1146. a_op_reg_reg(list,Op,size,reg,tmpreg);
  1147. a_load_reg_ref(list,size,size,tmpreg,ref);
  1148. end;
  1149. else
  1150. internalerror(2013050804);
  1151. end;
  1152. end
  1153. else
  1154. inherited a_op_reg_ref(list,Op,size,reg,tmpref);
  1155. end;
  1156. procedure tcg8086.push_const(list: TAsmList; size: tcgsize; a: tcgint);
  1157. var
  1158. tmpreg: TRegister;
  1159. begin
  1160. if not (size in [OS_16,OS_S16]) then
  1161. internalerror(2013043001);
  1162. if current_settings.cputype < cpu_186 then
  1163. begin
  1164. tmpreg:=getintregister(list,size);
  1165. a_load_const_reg(list,size,a,tmpreg);
  1166. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1167. end
  1168. else
  1169. list.concat(taicpu.op_const(A_PUSH,TCGSize2OpSize[size],a));
  1170. end;
  1171. procedure tcg8086.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  1172. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  1173. var
  1174. ref : treference;
  1175. begin
  1176. paramanager.allocparaloc(list,paraloc);
  1177. case paraloc^.loc of
  1178. LOC_REGISTER,LOC_CREGISTER:
  1179. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  1180. LOC_REFERENCE,LOC_CREFERENCE:
  1181. begin
  1182. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]);
  1183. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  1184. end;
  1185. else
  1186. internalerror(2002071004);
  1187. end;
  1188. end;
  1189. var
  1190. pushsize,pushsize2 : tcgsize;
  1191. begin
  1192. check_register_size(size,r);
  1193. if use_push(cgpara) then
  1194. begin
  1195. if tcgsize2size[cgpara.Size] > 2 then
  1196. begin
  1197. if tcgsize2size[cgpara.Size] <> 4 then
  1198. internalerror(2013031101);
  1199. if cgpara.location^.Next = nil then
  1200. begin
  1201. if tcgsize2size[cgpara.location^.size] <> 4 then
  1202. internalerror(2013031101);
  1203. end
  1204. else
  1205. begin
  1206. if tcgsize2size[cgpara.location^.size] <> 2 then
  1207. internalerror(2013031101);
  1208. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1209. internalerror(2013031101);
  1210. if cgpara.location^.Next^.Next <> nil then
  1211. internalerror(2013031101);
  1212. end;
  1213. if tcgsize2size[cgpara.size]>cgpara.alignment then
  1214. pushsize:=cgpara.size
  1215. else
  1216. pushsize:=int_cgsize(cgpara.alignment);
  1217. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  1218. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  1219. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  1220. end
  1221. else
  1222. begin
  1223. cgpara.check_simple_location;
  1224. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  1225. pushsize:=cgpara.location^.size
  1226. else
  1227. pushsize:=int_cgsize(cgpara.alignment);
  1228. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  1229. end;
  1230. end
  1231. else
  1232. begin
  1233. if tcgsize2size[cgpara.Size]=4 then
  1234. begin
  1235. if (cgpara.location^.Next=nil) or
  1236. (tcgsize2size[cgpara.location^.size]<>2) or
  1237. (tcgsize2size[cgpara.location^.Next^.size]<>2) or
  1238. (cgpara.location^.Next^.Next<>nil) or
  1239. (cgpara.location^.shiftval<>0) then
  1240. internalerror(2013031102);
  1241. load_para_loc(r,cgpara.Location);
  1242. load_para_loc(GetNextReg(r),cgpara.Location^.Next);
  1243. end
  1244. else
  1245. inherited a_load_reg_cgpara(list,size,r,cgpara);
  1246. end;
  1247. end;
  1248. procedure tcg8086.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
  1249. var
  1250. pushsize : tcgsize;
  1251. begin
  1252. if use_push(cgpara) then
  1253. begin
  1254. if tcgsize2size[cgpara.Size] > 2 then
  1255. begin
  1256. if tcgsize2size[cgpara.Size] <> 4 then
  1257. internalerror(2013031101);
  1258. if cgpara.location^.Next = nil then
  1259. begin
  1260. if tcgsize2size[cgpara.location^.size] <> 4 then
  1261. internalerror(2013031101);
  1262. end
  1263. else
  1264. begin
  1265. if tcgsize2size[cgpara.location^.size] <> 2 then
  1266. internalerror(2013031101);
  1267. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1268. internalerror(2013031101);
  1269. if cgpara.location^.Next^.Next <> nil then
  1270. internalerror(2013031101);
  1271. end;
  1272. if (cgpara.alignment <> 4) and (cgpara.alignment <> 2) then
  1273. internalerror(2013031101);
  1274. push_const(list,OS_16,a shr 16);
  1275. push_const(list,OS_16,a and $FFFF);
  1276. end
  1277. else
  1278. begin
  1279. cgpara.check_simple_location;
  1280. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  1281. pushsize:=cgpara.location^.size
  1282. else
  1283. pushsize:=int_cgsize(cgpara.alignment);
  1284. push_const(list,pushsize,a);
  1285. end;
  1286. end
  1287. else if (tcgsize2size[cgpara.Size]>2) and
  1288. (cgpara.location^.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  1289. (cgpara.location^.Next<>nil) then
  1290. begin
  1291. if (tcgsize2size[cgpara.Size]<>4) or
  1292. (tcgsize2size[cgpara.location^.Size]<>2) or
  1293. not (cgpara.location^.Next^.Loc in [LOC_REGISTER,LOC_CREGISTER]) or
  1294. (tcgsize2size[cgpara.location^.Next^.Size]<>2) or
  1295. (cgpara.location^.Next^.Next<>nil) then
  1296. internalerror(2018041801);
  1297. a_load_const_reg(list,cgpara.location^.size,a and $FFFF,cgpara.location^.register);
  1298. a_load_const_reg(list,cgpara.location^.Next^.size,a shr 16,cgpara.location^.Next^.register);
  1299. end
  1300. else
  1301. inherited a_load_const_cgpara(list,size,a,cgpara);
  1302. end;
  1303. procedure tcg8086.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
  1304. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  1305. var
  1306. pushsize : tcgsize;
  1307. opsize : topsize;
  1308. tmpreg : tregister;
  1309. href,tmpref: treference;
  1310. begin
  1311. if not assigned(paraloc) then
  1312. exit;
  1313. if (paraloc^.loc<>LOC_REFERENCE) or
  1314. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  1315. (tcgsize2size[paraloc^.size]>4) then
  1316. internalerror(200501162);
  1317. { Pushes are needed in reverse order, add the size of the
  1318. current location to the offset where to load from. This
  1319. prevents wrong calculations for the last location when
  1320. the size is not a power of 2 }
  1321. if assigned(paraloc^.next) then
  1322. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  1323. { Push the data starting at ofs }
  1324. href:=r;
  1325. inc(href.offset,ofs);
  1326. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  1327. pushsize:=paraloc^.size
  1328. else
  1329. pushsize:=int_cgsize(cgpara.alignment);
  1330. opsize:=TCgsize2opsize[pushsize];
  1331. { for go32v2 we obtain OS_F32,
  1332. but pushs is not valid, we need pushl }
  1333. if opsize=S_FS then
  1334. opsize:=S_W;
  1335. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  1336. begin
  1337. tmpreg:=getintregister(list,pushsize);
  1338. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  1339. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  1340. end
  1341. else
  1342. begin
  1343. make_simple_ref(list,href);
  1344. if tcgsize2size[pushsize] > 2 then
  1345. begin
  1346. tmpref := href;
  1347. Inc(tmpref.offset, 2);
  1348. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  1349. end;
  1350. list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  1351. end;
  1352. end;
  1353. var
  1354. len : tcgint;
  1355. href : treference;
  1356. begin
  1357. { cgpara.size=OS_NO requires a copy on the stack }
  1358. if use_push(cgpara) then
  1359. begin
  1360. { Record copy? }
  1361. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  1362. begin
  1363. cgpara.check_simple_location;
  1364. len:=align(cgpara.intsize,cgpara.alignment);
  1365. g_stackpointer_alloc(list,len);
  1366. reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
  1367. g_concatcopy(list,r,href,len);
  1368. end
  1369. else
  1370. begin
  1371. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  1372. internalerror(200501161);
  1373. { We need to push the data in reverse order,
  1374. therefor we use a recursive algorithm }
  1375. pushdata(cgpara.location,0);
  1376. end
  1377. end
  1378. else
  1379. inherited a_load_ref_cgpara(list,size,r,cgpara);
  1380. end;
  1381. procedure tcg8086.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
  1382. var
  1383. tmpreg : tregister;
  1384. tmpref : treference;
  1385. begin
  1386. with r do
  1387. begin
  1388. if use_push(cgpara) then
  1389. begin
  1390. if tcgsize2size[cgpara.Size] > 2 then
  1391. begin
  1392. if tcgsize2size[cgpara.Size] <> 4 then
  1393. internalerror(2014032401);
  1394. if cgpara.location^.Next = nil then
  1395. begin
  1396. if tcgsize2size[cgpara.location^.size] <> 4 then
  1397. internalerror(2014032401);
  1398. end
  1399. else
  1400. begin
  1401. if tcgsize2size[cgpara.location^.size] <> 2 then
  1402. internalerror(2014032401);
  1403. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  1404. internalerror(2014032401);
  1405. if cgpara.location^.Next^.Next <> nil then
  1406. internalerror(2014032401);
  1407. end;
  1408. if cgpara.alignment > 4 then
  1409. internalerror(2014032401);
  1410. if segment<>NR_NO then
  1411. begin
  1412. list.concat(Taicpu.op_reg(A_PUSH,S_W,segment));
  1413. tmpref:=r;
  1414. tmpref.segment:=NR_NO;
  1415. tmpreg:=getaddressregister(list);
  1416. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1417. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1418. end
  1419. else
  1420. begin
  1421. if (base=NR_NO) and (index=NR_NO) then
  1422. begin
  1423. if assigned(symbol) then
  1424. begin
  1425. tmpref:=r;
  1426. tmpref.refaddr:=addr_seg;
  1427. tmpref.offset:=0;
  1428. if current_settings.cputype < cpu_186 then
  1429. begin
  1430. tmpreg:=getaddressregister(list);
  1431. a_load_ref_reg(list,OS_16,OS_16,tmpref,tmpreg);
  1432. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1433. end
  1434. else
  1435. list.concat(Taicpu.Op_ref(A_PUSH,S_W,tmpref));
  1436. if current_settings.cputype < cpu_186 then
  1437. begin
  1438. tmpreg:=getaddressregister(list);
  1439. a_loadaddr_ref_reg(list,r,tmpreg);
  1440. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1441. end
  1442. else
  1443. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_W,symbol,offset));
  1444. end
  1445. else
  1446. internalerror(2014032402);
  1447. end
  1448. else if assigned(symbol) then
  1449. begin
  1450. reference_reset_symbol(tmpref,r.symbol,0,r.alignment,r.volatility);
  1451. tmpref.refaddr:=addr_seg;
  1452. if current_settings.cputype < cpu_186 then
  1453. begin
  1454. tmpreg:=getaddressregister(list);
  1455. a_load_ref_reg(list,OS_16,OS_16,tmpref,tmpreg);
  1456. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1457. end
  1458. else
  1459. list.concat(Taicpu.Op_ref(A_PUSH,S_W,tmpref));
  1460. tmpreg:=getaddressregister(list);
  1461. a_loadaddr_ref_reg(list,r,tmpreg);
  1462. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1463. end
  1464. else if base=NR_BP then
  1465. begin
  1466. list.concat(Taicpu.op_reg(A_PUSH,S_W,NR_SS));
  1467. tmpreg:=getaddressregister(list);
  1468. a_loadaddr_ref_reg(list,r,tmpreg);
  1469. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1470. end
  1471. else
  1472. internalerror(2014032403);
  1473. end;
  1474. end
  1475. else
  1476. begin
  1477. cgpara.check_simple_location;
  1478. tmpref:=r;
  1479. tmpref.segment:=NR_NO;
  1480. with tmpref do
  1481. begin
  1482. if (base=NR_NO) and (index=NR_NO) then
  1483. begin
  1484. if assigned(symbol) then
  1485. begin
  1486. if current_settings.cputype < cpu_186 then
  1487. begin
  1488. tmpreg:=getaddressregister(list);
  1489. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1490. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1491. end
  1492. else
  1493. list.concat(Taicpu.Op_sym_ofs(A_PUSH,S_W,symbol,offset));
  1494. end
  1495. else
  1496. push_const(list,OS_16,offset);
  1497. end
  1498. else if (base=NR_NO) and (index<>NR_NO) and
  1499. (offset=0) and (scalefactor=0) and (symbol=nil) then
  1500. list.concat(Taicpu.Op_reg(A_PUSH,S_W,index))
  1501. else if (base<>NR_NO) and (index=NR_NO) and
  1502. (offset=0) and (symbol=nil) then
  1503. list.concat(Taicpu.Op_reg(A_PUSH,S_W,base))
  1504. else
  1505. begin
  1506. tmpreg:=getaddressregister(list);
  1507. a_loadaddr_ref_reg(list,tmpref,tmpreg);
  1508. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  1509. end;
  1510. end;
  1511. end;
  1512. end
  1513. else
  1514. inherited a_loadaddr_ref_cgpara(list,r,cgpara);
  1515. end;
  1516. end;
  1517. procedure tcg8086.a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);
  1518. begin
  1519. check_register_size(tosize,reg);
  1520. if tosize in [OS_S32,OS_32] then
  1521. begin
  1522. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a and $ffff),reg));
  1523. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a shr 16),GetNextReg(reg)));
  1524. end
  1525. else
  1526. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg));
  1527. end;
  1528. procedure tcg8086.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
  1529. var
  1530. tmpref : treference;
  1531. begin
  1532. tmpref:=ref;
  1533. make_simple_ref(list,tmpref);
  1534. if tosize in [OS_S32,OS_32] then
  1535. begin
  1536. a_load_const_ref(list,OS_16,longint(a and $ffff),tmpref);
  1537. inc(tmpref.offset,2);
  1538. a_load_const_ref(list,OS_16,longint(a shr 16),tmpref);
  1539. end
  1540. else
  1541. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
  1542. end;
  1543. procedure tcg8086.a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);
  1544. var
  1545. tmpreg : tregister;
  1546. tmpref : treference;
  1547. begin
  1548. tmpref:=ref;
  1549. make_simple_ref(list,tmpref);
  1550. check_register_size(fromsize,reg);
  1551. case tosize of
  1552. OS_8,OS_S8:
  1553. if fromsize in [OS_8,OS_S8] then
  1554. list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
  1555. else
  1556. internalerror(2013030310);
  1557. OS_16,OS_S16:
  1558. case fromsize of
  1559. OS_8,OS_S8:
  1560. begin
  1561. tmpreg:=getintregister(list,tosize);
  1562. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  1563. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  1564. end;
  1565. OS_16,OS_S16:
  1566. begin
  1567. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1568. end;
  1569. else
  1570. internalerror(2013030312);
  1571. end;
  1572. OS_32,OS_S32:
  1573. case fromsize of
  1574. OS_8,OS_S8,OS_S16:
  1575. begin
  1576. tmpreg:=getintregister(list,tosize);
  1577. a_load_reg_reg(list,fromsize,tosize,reg,tmpreg);
  1578. a_load_reg_ref(list,tosize,tosize,tmpreg,tmpref);
  1579. end;
  1580. OS_16:
  1581. begin
  1582. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1583. inc(tmpref.offset, 2);
  1584. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  1585. end;
  1586. OS_32,OS_S32:
  1587. begin
  1588. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  1589. inc(tmpref.offset, 2);
  1590. list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
  1591. end;
  1592. else
  1593. internalerror(2013030313);
  1594. end;
  1595. else
  1596. internalerror(2013030311);
  1597. end;
  1598. end;
  1599. procedure tcg8086.a_load_ref_reg_internal(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister;isdirect:boolean);
  1600. procedure add_mov(instr: Taicpu);
  1601. begin
  1602. { Notify the register allocator that we have written a move instruction so
  1603. it can try to eliminate it. }
  1604. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1605. add_move_instruction(instr);
  1606. list.concat(instr);
  1607. end;
  1608. var
  1609. tmpref : treference;
  1610. begin
  1611. tmpref:=ref;
  1612. make_simple_ref(list,tmpref,isdirect);
  1613. check_register_size(tosize,reg);
  1614. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1615. internalerror(2011021307);
  1616. { if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1617. fromsize:=tosize;}
  1618. case tosize of
  1619. OS_8,OS_S8:
  1620. if fromsize in [OS_8,OS_S8] then
  1621. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
  1622. else
  1623. internalerror(2013030210);
  1624. OS_16,OS_S16:
  1625. case fromsize of
  1626. OS_8:
  1627. begin
  1628. if current_settings.cputype>=cpu_386 then
  1629. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1630. else
  1631. begin
  1632. reg := makeregsize(list, reg, OS_8);
  1633. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1634. setsubreg(reg, R_SUBH);
  1635. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1636. makeregsize(list, reg, OS_16);
  1637. end;
  1638. end;
  1639. OS_S8:
  1640. begin
  1641. if current_settings.cputype>=cpu_386 then
  1642. list.concat(taicpu.op_ref_reg(A_MOVSX, S_BW, tmpref, reg))
  1643. else
  1644. begin
  1645. getcpuregister(list, NR_AX);
  1646. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1647. list.concat(taicpu.op_none(A_CBW));
  1648. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1649. ungetcpuregister(list, NR_AX);
  1650. end;
  1651. end;
  1652. OS_16,OS_S16:
  1653. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1654. else
  1655. internalerror(2013030212);
  1656. end;
  1657. OS_32,OS_S32:
  1658. case fromsize of
  1659. OS_8:
  1660. begin
  1661. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1662. if current_settings.cputype>=cpu_386 then
  1663. list.concat(taicpu.op_ref_reg(A_MOVZX, S_BW, tmpref, reg))
  1664. else
  1665. begin
  1666. reg := makeregsize(list, reg, OS_8);
  1667. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  1668. setsubreg(reg, R_SUBH);
  1669. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  1670. makeregsize(list, reg, OS_16);
  1671. end;
  1672. end;
  1673. OS_S8:
  1674. begin
  1675. getcpuregister(list, NR_AX);
  1676. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  1677. getcpuregister(list, NR_DX);
  1678. list.concat(taicpu.op_none(A_CBW));
  1679. list.concat(taicpu.op_none(A_CWD));
  1680. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1681. ungetcpuregister(list, NR_AX);
  1682. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1683. ungetcpuregister(list, NR_DX);
  1684. end;
  1685. OS_16:
  1686. begin
  1687. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1688. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  1689. end;
  1690. OS_S16:
  1691. begin
  1692. getcpuregister(list, NR_AX);
  1693. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  1694. getcpuregister(list, NR_DX);
  1695. list.concat(taicpu.op_none(A_CWD));
  1696. ungetcpuregister(list, NR_AX);
  1697. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  1698. ungetcpuregister(list, NR_DX);
  1699. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  1700. end;
  1701. OS_32,OS_S32:
  1702. begin
  1703. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  1704. inc(tmpref.offset, 2);
  1705. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  1706. end;
  1707. else
  1708. internalerror(2013030213);
  1709. end;
  1710. else
  1711. internalerror(2013030211);
  1712. end;
  1713. end;
  1714. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  1715. procedure add_mov(instr: Taicpu);
  1716. begin
  1717. { Notify the register allocator that we have written a move instruction so
  1718. it can try to eliminate it. }
  1719. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  1720. add_move_instruction(instr);
  1721. list.concat(instr);
  1722. end;
  1723. begin
  1724. check_register_size(fromsize,reg1);
  1725. check_register_size(tosize,reg2);
  1726. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1727. begin
  1728. if tosize in [OS_32, OS_S32] then
  1729. internalerror(2013031801);
  1730. reg1:=makeregsize(list,reg1,tosize);
  1731. fromsize:=tosize;
  1732. end;
  1733. if (reg1<>reg2) or (fromsize<>tosize) then
  1734. begin
  1735. case tosize of
  1736. OS_8,OS_S8:
  1737. if fromsize in [OS_8,OS_S8] then
  1738. begin
  1739. if reg1<>reg2 then
  1740. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1741. end
  1742. else
  1743. internalerror(2013030210);
  1744. OS_16,OS_S16:
  1745. case fromsize of
  1746. OS_8:
  1747. begin
  1748. if current_settings.cputype>=cpu_386 then
  1749. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1750. else
  1751. begin
  1752. reg2 := makeregsize(list, reg2, OS_8);
  1753. if reg1<>reg2 then
  1754. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1755. setsubreg(reg2,R_SUBH);
  1756. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1757. makeregsize(list, reg2, OS_16);
  1758. end;
  1759. end;
  1760. OS_S8:
  1761. begin
  1762. if current_settings.cputype>=cpu_386 then
  1763. add_mov(taicpu.op_reg_reg(A_MOVSX, S_BW, reg1, reg2))
  1764. else
  1765. begin
  1766. getcpuregister(list, NR_AX);
  1767. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1768. list.concat(taicpu.op_none(A_CBW));
  1769. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1770. ungetcpuregister(list, NR_AX);
  1771. end;
  1772. end;
  1773. OS_16,OS_S16:
  1774. begin
  1775. if reg1<>reg2 then
  1776. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1777. end
  1778. else
  1779. internalerror(2013030212);
  1780. end;
  1781. OS_32,OS_S32:
  1782. case fromsize of
  1783. OS_8:
  1784. begin
  1785. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
  1786. if current_settings.cputype>=cpu_386 then
  1787. add_mov(taicpu.op_reg_reg(A_MOVZX, S_BW, reg1, reg2))
  1788. else
  1789. begin
  1790. reg2 := makeregsize(list, reg2, OS_8);
  1791. if reg1<>reg2 then
  1792. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1793. setsubreg(reg2,R_SUBH);
  1794. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1795. makeregsize(list, reg2, OS_16);
  1796. end;
  1797. end;
  1798. OS_S8:
  1799. begin
  1800. getcpuregister(list, NR_AX);
  1801. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1802. getcpuregister(list, NR_DX);
  1803. list.concat(taicpu.op_none(A_CBW));
  1804. list.concat(taicpu.op_none(A_CWD));
  1805. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1806. ungetcpuregister(list, NR_AX);
  1807. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1808. ungetcpuregister(list, NR_DX);
  1809. end;
  1810. OS_16:
  1811. begin
  1812. if reg1<>reg2 then
  1813. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1814. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1815. end;
  1816. OS_S16:
  1817. begin
  1818. getcpuregister(list, NR_AX);
  1819. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1820. getcpuregister(list, NR_DX);
  1821. list.concat(taicpu.op_none(A_CWD));
  1822. if reg1<>reg2 then
  1823. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1824. ungetcpuregister(list, NR_AX);
  1825. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1826. ungetcpuregister(list, NR_DX);
  1827. end;
  1828. OS_32,OS_S32:
  1829. begin
  1830. if reg1<>reg2 then
  1831. begin
  1832. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1833. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1834. end;
  1835. end;
  1836. else
  1837. internalerror(2013030213);
  1838. end;
  1839. else
  1840. internalerror(2013030211);
  1841. end;
  1842. end;
  1843. end;
  1844. procedure tcg8086.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1845. var
  1846. hl_skip: TAsmLabel;
  1847. begin
  1848. if size in [OS_32, OS_S32] then
  1849. begin
  1850. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1851. if (longint(a shr 16) = 0) then
  1852. list.concat(taicpu.op_reg_reg(A_TEST,S_W,GetNextReg(reg),GetNextReg(reg)))
  1853. else
  1854. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a shr 16),GetNextReg(reg)));
  1855. current_asmdata.getjumplabel(hl_skip);
  1856. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1857. if (longint(a and $ffff) = 0) then
  1858. list.concat(taicpu.op_reg_reg(A_TEST,S_W,reg,reg))
  1859. else
  1860. list.concat(taicpu.op_const_reg(A_CMP,S_W,longint(a and $ffff),reg));
  1861. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1862. a_label(list,hl_skip);
  1863. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1864. end
  1865. else
  1866. inherited a_cmp_const_reg_label(list, size, cmp_op, a, reg, l);
  1867. end;
  1868. procedure tcg8086.a_cmp_const_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
  1869. var
  1870. tmpref: treference;
  1871. hl_skip: TAsmLabel;
  1872. begin
  1873. if size in [OS_32, OS_S32] then
  1874. begin
  1875. tmpref:=ref;
  1876. make_simple_ref(list,tmpref);
  1877. inc(tmpref.offset,2);
  1878. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1879. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a shr 16),tmpref));
  1880. current_asmdata.getjumplabel(hl_skip);
  1881. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1882. dec(tmpref.offset,2);
  1883. list.concat(taicpu.op_const_ref(A_CMP,S_W,longint(a and $ffff),tmpref));
  1884. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1885. a_label(list,hl_skip);
  1886. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1887. end
  1888. else
  1889. inherited a_cmp_const_ref_label(list, size, cmp_op, a, ref, l);
  1890. end;
  1891. procedure tcg8086.a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  1892. var
  1893. hl_skip: TAsmLabel;
  1894. begin
  1895. if size in [OS_32, OS_S32] then
  1896. begin
  1897. check_register_size(size,reg1);
  1898. check_register_size(size,reg2);
  1899. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1900. list.concat(taicpu.op_reg_reg(A_CMP,S_W,GetNextReg(reg1),GetNextReg(reg2)));
  1901. current_asmdata.getjumplabel(hl_skip);
  1902. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1903. list.concat(taicpu.op_reg_reg(A_CMP,S_W,reg1,reg2));
  1904. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1905. a_label(list,hl_skip);
  1906. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1907. end
  1908. else
  1909. inherited a_cmp_reg_reg_label(list, size, cmp_op, reg1, reg2, l);
  1910. end;
  1911. procedure tcg8086.a_cmp_ref_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
  1912. var
  1913. tmpref: treference;
  1914. hl_skip: TAsmLabel;
  1915. begin
  1916. if size in [OS_32, OS_S32] then
  1917. begin
  1918. tmpref:=ref;
  1919. make_simple_ref(list,tmpref);
  1920. check_register_size(size,reg);
  1921. inc(tmpref.offset,2);
  1922. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1923. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,GetNextReg(reg)));
  1924. current_asmdata.getjumplabel(hl_skip);
  1925. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1926. dec(tmpref.offset,2);
  1927. list.concat(taicpu.op_ref_reg(A_CMP,S_W,tmpref,reg));
  1928. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1929. a_label(list,hl_skip);
  1930. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1931. end
  1932. else
  1933. inherited a_cmp_ref_reg_label(list, size, cmp_op, ref, reg, l);
  1934. end;
  1935. procedure tcg8086.a_cmp_reg_ref_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
  1936. var
  1937. tmpref: treference;
  1938. hl_skip: TAsmLabel;
  1939. begin
  1940. if size in [OS_32, OS_S32] then
  1941. begin
  1942. tmpref:=ref;
  1943. make_simple_ref(list,tmpref);
  1944. check_register_size(size,reg);
  1945. inc(tmpref.offset,2);
  1946. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1947. list.concat(taicpu.op_reg_ref(A_CMP,S_W,GetNextReg(reg),tmpref));
  1948. current_asmdata.getjumplabel(hl_skip);
  1949. gen_cmp32_jmp1(list, cmp_op, hl_skip, l);
  1950. dec(tmpref.offset,2);
  1951. list.concat(taicpu.op_reg_ref(A_CMP,S_W,reg,tmpref));
  1952. gen_cmp32_jmp2(list, cmp_op, hl_skip, l);
  1953. a_label(list,hl_skip);
  1954. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1955. end
  1956. else
  1957. inherited a_cmp_reg_ref_label(list, size, cmp_op, reg, ref, l);
  1958. end;
  1959. procedure tcg8086.gen_cmp32_jmp1(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1960. begin
  1961. case cmp_op of
  1962. OC_EQ:
  1963. a_jmp_cond(list, OC_NE, l_skip);
  1964. OC_NE:
  1965. a_jmp_cond(list, OC_NE, l_target);
  1966. OC_GT,OC_GTE:
  1967. begin
  1968. a_jmp_cond(list, OC_GT, l_target);
  1969. a_jmp_cond(list, OC_LT, l_skip);
  1970. end;
  1971. OC_LT,OC_LTE:
  1972. begin
  1973. a_jmp_cond(list, OC_LT, l_target);
  1974. a_jmp_cond(list, OC_GT, l_skip);
  1975. end;
  1976. OC_B,OC_BE:
  1977. begin
  1978. a_jmp_cond(list, OC_B, l_target);
  1979. a_jmp_cond(list, OC_A, l_skip);
  1980. end;
  1981. OC_A,OC_AE:
  1982. begin
  1983. a_jmp_cond(list, OC_A, l_target);
  1984. a_jmp_cond(list, OC_B, l_skip);
  1985. end;
  1986. else
  1987. internalerror(2014010305);
  1988. end;
  1989. end;
  1990. procedure tcg8086.gen_cmp32_jmp2(list: TAsmList; cmp_op: topcmp; l_skip, l_target: TAsmLabel);
  1991. begin
  1992. case cmp_op of
  1993. OC_EQ:
  1994. a_jmp_cond(list, OC_EQ, l_target);
  1995. OC_GT:
  1996. a_jmp_cond(list, OC_A, l_target);
  1997. OC_LT:
  1998. a_jmp_cond(list, OC_B, l_target);
  1999. OC_GTE:
  2000. a_jmp_cond(list, OC_AE, l_target);
  2001. OC_LTE:
  2002. a_jmp_cond(list, OC_BE, l_target);
  2003. OC_NE:
  2004. a_jmp_cond(list, OC_NE, l_target);
  2005. OC_BE:
  2006. a_jmp_cond(list, OC_BE, l_target);
  2007. OC_B:
  2008. a_jmp_cond(list, OC_B, l_target);
  2009. OC_AE:
  2010. a_jmp_cond(list, OC_AE, l_target);
  2011. OC_A:
  2012. a_jmp_cond(list, OC_A, l_target);
  2013. else
  2014. internalerror(2014010306);
  2015. end;
  2016. end;
  2017. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  2018. var
  2019. ai : taicpu;
  2020. hreg16 : tregister;
  2021. hl_skip: TAsmLabel;
  2022. invf: TResFlags;
  2023. tmpsize: TCgSize;
  2024. tmpopsize: topsize;
  2025. begin
  2026. { optimized case for the carry flag, using ADC/RCL }
  2027. if f in [F_C,F_B,F_FB] then
  2028. begin
  2029. case size of
  2030. OS_8,OS_S8:
  2031. begin
  2032. tmpsize:=OS_8;
  2033. tmpopsize:=S_B;
  2034. end;
  2035. OS_16,OS_S16,OS_32,OS_S32:
  2036. begin
  2037. tmpsize:=OS_16;
  2038. tmpopsize:=S_W;
  2039. end;
  2040. else
  2041. internalerror(2013123101);
  2042. end;
  2043. list.concat(Taicpu.op_const_reg(A_MOV, tmpopsize, 0, reg));
  2044. hl_skip:=nil;
  2045. if f=F_FB then
  2046. begin
  2047. current_asmdata.getjumplabel(hl_skip);
  2048. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  2049. ai.SetCondition(C_P);
  2050. ai.is_jmp:=true;
  2051. list.concat(ai);
  2052. end;
  2053. { RCL is faster than ADC on 8086/8088. On the 80286, it is
  2054. equally fast and it also has the same size. In these cases,
  2055. we still prefer it over ADC, because it's a better choice in
  2056. case the register is spilled. }
  2057. if (cs_opt_size in current_settings.optimizerswitches) or
  2058. (current_settings.optimizecputype<=cpu_286) then
  2059. list.concat(Taicpu.op_const_reg(A_RCL, tmpopsize, 1, reg))
  2060. else
  2061. { ADC is much faster on the 386. }
  2062. list.concat(Taicpu.op_reg_reg(A_ADC, tmpopsize, reg, reg));
  2063. if f=F_FB then
  2064. a_label(list,hl_skip);
  2065. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2066. end
  2067. { optimized case for the inverted carry flag, using SBB }
  2068. else if f in [F_NC,F_AE,F_FAE] then
  2069. begin
  2070. case size of
  2071. OS_8,OS_S8:
  2072. begin
  2073. tmpsize:=OS_8;
  2074. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 1, reg));
  2075. list.concat(Taicpu.op_const_reg(A_SBB, S_B, 0, reg));
  2076. end;
  2077. OS_16,OS_S16,OS_32,OS_S32:
  2078. begin
  2079. tmpsize:=OS_16;
  2080. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 1, reg));
  2081. list.concat(Taicpu.op_const_reg(A_SBB, S_W, 0, reg));
  2082. end;
  2083. else
  2084. internalerror(2013123101);
  2085. end;
  2086. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2087. end
  2088. else
  2089. begin
  2090. invf := f;
  2091. inverse_flags(invf);
  2092. case size of
  2093. OS_8,OS_S8:
  2094. begin
  2095. tmpsize:=OS_8;
  2096. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  2097. end;
  2098. OS_16,OS_S16,OS_32,OS_S32:
  2099. begin
  2100. tmpsize:=OS_16;
  2101. list.concat(Taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  2102. end;
  2103. else
  2104. internalerror(2013123101);
  2105. end;
  2106. current_asmdata.getjumplabel(hl_skip);
  2107. { we can't just forward invf to a_jmp_flags for FA,FAE,FB and FBE, because
  2108. in the case of NaNs:
  2109. not(F_FA )<>F_FBE
  2110. not(F_FAE)<>F_FB
  2111. not(F_FB )<>F_FAE
  2112. not(F_FBE)<>F_FA
  2113. }
  2114. case f of
  2115. F_FA:
  2116. invf:=FPUFlags2Flags[invf];
  2117. F_FAE,F_FB:
  2118. { F_FAE and F_FB are handled above, using ADC/RCL/SBB }
  2119. internalerror(2015102101);
  2120. F_FBE:
  2121. begin
  2122. ai:=Taicpu.op_sym(A_Jcc,S_NO,hl_skip);
  2123. ai.SetCondition(C_P);
  2124. ai.is_jmp:=true;
  2125. list.concat(ai);
  2126. invf:=FPUFlags2Flags[invf];
  2127. end;
  2128. end;
  2129. a_jmp_flags(list,invf,hl_skip);
  2130. { 16-bit INC is shorter than 8-bit }
  2131. hreg16:=makeregsize(list,reg,OS_16);
  2132. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  2133. makeregsize(list,hreg16,tmpsize);
  2134. a_label(list,hl_skip);
  2135. a_load_reg_reg(list,tmpsize,size,reg,reg);
  2136. end;
  2137. end;
  2138. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  2139. var
  2140. tmpreg : tregister;
  2141. tmpregsize: TCgSize;
  2142. tmpref: treference;
  2143. begin
  2144. if size in [OS_8,OS_S8,OS_16,OS_S16] then
  2145. tmpregsize:=size
  2146. else
  2147. tmpregsize:=OS_16;
  2148. tmpreg:=getintregister(list,tmpregsize);
  2149. g_flags2reg(list,tmpregsize,f,tmpreg);
  2150. tmpref:=ref;
  2151. make_simple_ref(list,tmpref);
  2152. if size in [OS_64,OS_S64] then
  2153. begin
  2154. a_load_reg_ref(list,tmpregsize,OS_32,tmpreg,tmpref);
  2155. inc(tmpref.offset,4);
  2156. a_load_const_ref(list,OS_32,0,tmpref);
  2157. end
  2158. else
  2159. a_load_reg_ref(list,tmpregsize,size,tmpreg,tmpref);
  2160. end;
  2161. procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
  2162. begin
  2163. if cs_check_stack in current_settings.localswitches then
  2164. begin
  2165. cg.getcpuregister(list,NR_AX);
  2166. cg.a_load_const_reg(list,OS_16, localsize,NR_AX);
  2167. cg.a_call_name(list,'FPC_STACKCHECK_I8086',false);
  2168. cg.ungetcpuregister(list, NR_AX);
  2169. end;
  2170. if localsize>0 then
  2171. list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
  2172. end;
  2173. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  2174. var
  2175. stacksize : longint;
  2176. ret_instr: TAsmOp;
  2177. sp_moved : boolean;
  2178. procedure maybe_move_sp;
  2179. var
  2180. ref : treference;
  2181. begin
  2182. if sp_moved then
  2183. exit;
  2184. if not(pi_has_open_array_parameter in current_procinfo.flags) then
  2185. exit;
  2186. { Restore SP position before SP change }
  2187. if current_settings.x86memorymodel=mm_huge then
  2188. stacksize:=stacksize + 2;
  2189. reference_reset_base(ref,NR_BP,-stacksize,ctempposinvalid,2,[]);
  2190. list.concat(Taicpu.op_ref_reg(A_LEA,S_W,ref,NR_SP));
  2191. sp_moved:=true;
  2192. end;
  2193. begin
  2194. if is_proc_far(current_procinfo.procdef) then
  2195. ret_instr:=A_RETF
  2196. else
  2197. ret_instr:=A_RET;
  2198. { MMX needs to call EMMS }
  2199. if assigned(rg[R_MMXREGISTER]) and
  2200. (rg[R_MMXREGISTER].uses_registers) then
  2201. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  2202. sp_moved:=false;
  2203. { remove stackframe }
  2204. if not nostackframe then
  2205. begin
  2206. stacksize:=current_procinfo.calc_stackframe_size;
  2207. if (target_info.stackalign>4) and
  2208. ((stacksize <> 0) or
  2209. (pi_do_call in current_procinfo.flags) or
  2210. { can't detect if a call in this case -> use nostackframe }
  2211. { if you (think you) know what you are doing }
  2212. (po_assembler in current_procinfo.procdef.procoptions)) then
  2213. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  2214. if (po_exports in current_procinfo.procdef.procoptions) and
  2215. (target_info.system=system_i8086_win16) then
  2216. begin
  2217. maybe_move_sp;
  2218. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  2219. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  2220. end;
  2221. if ((current_settings.x86memorymodel=mm_huge) and
  2222. not (po_interrupt in current_procinfo.procdef.procoptions)) or
  2223. ((po_exports in current_procinfo.procdef.procoptions) and
  2224. (target_info.system=system_i8086_win16)) then
  2225. begin
  2226. maybe_move_sp;
  2227. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  2228. end;
  2229. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  2230. begin
  2231. if (stacksize<>0) then
  2232. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  2233. end
  2234. else
  2235. begin
  2236. generate_leave(list);
  2237. if ((ts_x86_far_procs_push_odd_bp in current_settings.targetswitches) or
  2238. ((po_exports in current_procinfo.procdef.procoptions) and
  2239. (target_info.system=system_i8086_win16))) and
  2240. is_proc_far(current_procinfo.procdef) then
  2241. cg.a_op_const_reg(list,OP_SUB,OS_ADDR,1,current_procinfo.framepointer);
  2242. end;
  2243. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  2244. end;
  2245. { return from interrupt }
  2246. if po_interrupt in current_procinfo.procdef.procoptions then
  2247. begin
  2248. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  2249. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  2250. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DI));
  2251. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_SI));
  2252. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DX));
  2253. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_CX));
  2254. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_BX));
  2255. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_AX));
  2256. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  2257. end
  2258. { Routines with the poclearstack flag set use only a ret }
  2259. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  2260. (not paramanager.use_fixed_stack) then
  2261. begin
  2262. { complex return values are removed from stack in C code PM }
  2263. { but not on win32 }
  2264. { and not for safecall with hidden exceptions, because the result }
  2265. { wich contains the exception is passed in EAX }
  2266. if (target_info.system <> system_i386_win32) and
  2267. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  2268. (tf_safecall_exceptions in target_info.flags)) and
  2269. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  2270. current_procinfo.procdef) then
  2271. list.concat(Taicpu.Op_const(ret_instr,S_W,sizeof(aint)))
  2272. else
  2273. list.concat(Taicpu.Op_none(ret_instr,S_NO));
  2274. end
  2275. { ... also routines with parasize=0 }
  2276. else if (parasize=0) then
  2277. list.concat(Taicpu.Op_none(ret_instr,S_NO))
  2278. else
  2279. begin
  2280. { parameters are limited to 65535 bytes because ret allows only imm16 }
  2281. if (parasize>65535) then
  2282. CGMessage(cg_e_parasize_too_big);
  2283. list.concat(Taicpu.Op_const(ret_instr,S_W,parasize));
  2284. end;
  2285. end;
  2286. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  2287. var
  2288. power : longint;
  2289. opsize : topsize;
  2290. saved_ds: Boolean;
  2291. begin
  2292. { get stack space }
  2293. getcpuregister(list,NR_DI);
  2294. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  2295. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  2296. { Now DI contains (high+1). }
  2297. include(current_procinfo.flags, pi_has_open_array_parameter);
  2298. { special case handling for elesize=2:
  2299. set CX = (high+1) instead of CX = (high+1)*elesize.
  2300. This allows us to avoid the SHR later. }
  2301. if elesize=2 then
  2302. begin
  2303. { Now DI contains (high+1). Copy it to CX for later use. }
  2304. getcpuregister(list,NR_CX);
  2305. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  2306. end;
  2307. { DI := DI * elesize }
  2308. if (elesize<>1) then
  2309. begin
  2310. if ispowerof2(elesize, power) then
  2311. a_op_const_reg(list,OP_SHL,OS_16,power,NR_DI)
  2312. else
  2313. a_op_const_reg(list,OP_IMUL,OS_16,elesize,NR_DI);
  2314. end;
  2315. if elesize<>2 then
  2316. begin
  2317. { Now DI contains (high+1)*elesize. Copy it to CX for later use. }
  2318. getcpuregister(list,NR_CX);
  2319. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  2320. end;
  2321. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  2322. by (size div pagesize)*pagesize, otherwise EDI=size.
  2323. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  2324. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  2325. { align stack on 2 bytes }
  2326. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  2327. { load destination, don't use a_load_reg_reg, that will add a move instruction
  2328. that can confuse the reg allocator }
  2329. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  2330. {$ifdef volatile_es}
  2331. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS));
  2332. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  2333. {$endif volatile_es}
  2334. { Allocate SI and load it with source }
  2335. getcpuregister(list,NR_SI);
  2336. if ((ref.segment=NR_NO) and (segment_regs_equal(NR_SS,NR_DS) or (ref.base<>NR_BP))) or
  2337. (is_segment_reg(ref.segment) and segment_regs_equal(ref.segment,NR_DS)) then
  2338. begin
  2339. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  2340. saved_ds:=false;
  2341. end
  2342. else
  2343. begin
  2344. hlcg.a_loadaddr_ref_reg(list,voidnearpointertype,voidnearpointertype,ref,NR_SI);
  2345. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  2346. saved_ds:=true;
  2347. if ref.segment<>NR_NO then
  2348. list.concat(taicpu.op_reg(A_PUSH,S_W,ref.segment))
  2349. else if ref.base=NR_BP then
  2350. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_SS))
  2351. else
  2352. internalerror(2014040403);
  2353. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  2354. end;
  2355. { calculate size }
  2356. opsize:=S_B;
  2357. if elesize=2 then
  2358. begin
  2359. opsize:=S_W;
  2360. { CX is already number of words, so no need to SHL/SHR }
  2361. end
  2362. else if (elesize and 1)=0 then
  2363. begin
  2364. opsize:=S_W;
  2365. { CX is number of bytes, convert to words }
  2366. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX))
  2367. end;
  2368. if ts_cld in current_settings.targetswitches then
  2369. list.concat(Taicpu.op_none(A_CLD,S_NO));
  2370. if (opsize=S_B) and not (cs_opt_size in current_settings.optimizerswitches) then
  2371. begin
  2372. { SHR CX,1 moves the lowest (odd/even) bit to the carry flag }
  2373. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2374. list.concat(Taicpu.op_const_reg(A_SHR,S_W,1,NR_CX));
  2375. list.concat(Taicpu.op_none(A_REP,S_NO));
  2376. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  2377. { ADC CX,CX will set CX to 1 if the number of bytes was odd }
  2378. list.concat(Taicpu.op_reg_reg(A_ADC,S_W,NR_CX,NR_CX));
  2379. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2380. list.concat(Taicpu.op_none(A_REP,S_NO));
  2381. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  2382. end
  2383. else
  2384. begin
  2385. list.concat(Taicpu.op_none(A_REP,S_NO));
  2386. case opsize of
  2387. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  2388. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  2389. end;
  2390. end;
  2391. ungetcpuregister(list,NR_DI);
  2392. ungetcpuregister(list,NR_CX);
  2393. ungetcpuregister(list,NR_SI);
  2394. if saved_ds then
  2395. list.concat(taicpu.op_reg(A_POP,S_W,NR_DS));
  2396. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  2397. that can confuse the reg allocator }
  2398. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  2399. if current_settings.x86memorymodel in x86_far_data_models then
  2400. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SS,GetNextReg(destreg)));
  2401. end;
  2402. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  2403. begin
  2404. { Nothing to do }
  2405. end;
  2406. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  2407. begin
  2408. case op of
  2409. OP_ADD :
  2410. begin
  2411. op1:=A_ADD;
  2412. op2:=A_ADC;
  2413. end;
  2414. OP_SUB :
  2415. begin
  2416. op1:=A_SUB;
  2417. op2:=A_SBB;
  2418. end;
  2419. OP_XOR :
  2420. begin
  2421. op1:=A_XOR;
  2422. op2:=A_XOR;
  2423. end;
  2424. OP_OR :
  2425. begin
  2426. op1:=A_OR;
  2427. op2:=A_OR;
  2428. end;
  2429. OP_AND :
  2430. begin
  2431. op1:=A_AND;
  2432. op2:=A_AND;
  2433. end;
  2434. else
  2435. internalerror(200203241);
  2436. end;
  2437. end;
  2438. procedure tcg8086.add_move_instruction(instr: Taicpu);
  2439. begin
  2440. { HACK: when regvars are on, don't notify the register allocator of any
  2441. direct moves to BX, so it doesn't try to coalesce them. Currently,
  2442. direct moves to BX are only used when returning an int64 value in
  2443. AX:BX:CX:DX. This hack fixes a common issue with functions, returning
  2444. int64, for example:
  2445. function RandomFrom(const AValues: array of Int64): Int64;
  2446. begin
  2447. result:=AValues[random(High(AValues)+1)];
  2448. end;
  2449. push bp
  2450. mov bp,sp
  2451. ; Var AValues located in register ireg20w
  2452. ; Var $highAVALUES located in register ireg21w
  2453. ; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
  2454. mov ireg20w,word [bp+6]
  2455. mov ireg21w,word [bp+4]
  2456. ; [3] result:=AValues[random(High(AValues)+1)];
  2457. mov ireg22w,ireg21w
  2458. inc ireg22w
  2459. mov ax,ireg22w
  2460. cwd
  2461. mov ireg23w,ax
  2462. mov ireg24w,dx
  2463. push ireg24w
  2464. push ireg23w
  2465. call SYSTEM_$$_RANDOM$LONGINT$$LONGINT
  2466. mov ireg25w,ax
  2467. mov ireg26w,dx
  2468. mov ireg27w,ireg25w
  2469. mov ireg28w,ireg27w
  2470. mov ireg29w,ireg28w
  2471. mov cl,3
  2472. shl ireg29w,cl
  2473. ; Var $result located in register ireg32w:ireg30w
  2474. mov ireg30w,word [ireg20w+ireg29w]
  2475. mov ireg31w,word [ireg20w+ireg29w+2]
  2476. mov ireg32w,word [ireg20w+ireg29w+4] ; problematic section start
  2477. mov ireg33w,word [ireg20w+ireg29w+6]
  2478. ; [4] end;
  2479. mov bx,ireg32w ; problematic section end
  2480. mov ax,ireg33w
  2481. mov dx,ireg30w
  2482. mov cx,ireg31w
  2483. mov sp,bp
  2484. pop bp
  2485. ret 4
  2486. the problem arises, because the register allocator tries to coalesce
  2487. mov bx,ireg32w
  2488. however, in the references [ireg20w+ireg29w+const], due to the
  2489. constraints of i8086, ireg20w can only be BX (or BP, which isn't available
  2490. to the register allocator, because it's used as a base pointer) }
  2491. if (cs_opt_regvar in current_settings.optimizerswitches) and
  2492. (instr.opcode=A_MOV) and (instr.ops=2) and
  2493. (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
  2494. exit
  2495. else
  2496. inherited add_move_instruction(instr);
  2497. end;
  2498. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2499. var
  2500. hsym : tsym;
  2501. href : treference;
  2502. paraloc : Pcgparalocation;
  2503. return_address_size: Integer;
  2504. begin
  2505. if current_settings.x86memorymodel in x86_far_code_models then
  2506. return_address_size:=4
  2507. else
  2508. return_address_size:=2;
  2509. { calculate the parameter info for the procdef }
  2510. procdef.init_paraloc_info(callerside);
  2511. hsym:=tsym(procdef.parast.Find('self'));
  2512. if not(assigned(hsym) and
  2513. (hsym.typ=paravarsym)) then
  2514. internalerror(200305251);
  2515. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2516. with paraloc^ do
  2517. begin
  2518. case loc of
  2519. LOC_REGISTER:
  2520. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  2521. LOC_REFERENCE:
  2522. begin
  2523. { offset in the wrapper needs to be adjusted for the stored
  2524. return address }
  2525. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  2526. and (reference.index<>NR_SI) then
  2527. begin
  2528. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  2529. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  2530. if reference.index=NR_SP then
  2531. reference_reset_base(href,NR_DI,reference.offset+return_address_size+2,ctempposinvalid,sizeof(pint),[])
  2532. else
  2533. reference_reset_base(href,NR_DI,reference.offset+return_address_size,ctempposinvalid,sizeof(pint),[]);
  2534. href.segment:=NR_SS;
  2535. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2536. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  2537. end
  2538. else
  2539. begin
  2540. reference_reset_base(href,reference.index,reference.offset+return_address_size,ctempposinvalid,sizeof(pint),[]);
  2541. href.segment:=NR_SS;
  2542. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2543. end;
  2544. end
  2545. else
  2546. internalerror(200309189);
  2547. end;
  2548. paraloc:=next;
  2549. end;
  2550. end;
  2551. { ************* 64bit operations ************ }
  2552. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  2553. begin
  2554. case op of
  2555. OP_ADD :
  2556. begin
  2557. op1:=A_ADD;
  2558. op2:=A_ADC;
  2559. end;
  2560. OP_SUB :
  2561. begin
  2562. op1:=A_SUB;
  2563. op2:=A_SBB;
  2564. end;
  2565. OP_XOR :
  2566. begin
  2567. op1:=A_XOR;
  2568. op2:=A_XOR;
  2569. end;
  2570. OP_OR :
  2571. begin
  2572. op1:=A_OR;
  2573. op2:=A_OR;
  2574. end;
  2575. OP_AND :
  2576. begin
  2577. op1:=A_AND;
  2578. op2:=A_AND;
  2579. end;
  2580. else
  2581. internalerror(200203241);
  2582. end;
  2583. end;
  2584. procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  2585. var
  2586. op1,op2 : TAsmOp;
  2587. tempref : treference;
  2588. begin
  2589. if not(op in [OP_NEG,OP_NOT]) then
  2590. begin
  2591. get_64bit_ops(op,op1,op2);
  2592. tempref:=ref;
  2593. tcgx86(cg).make_simple_ref(list,tempref);
  2594. if op in [OP_ADD,OP_SUB] then
  2595. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2596. list.concat(taicpu.op_ref_reg(op1,S_W,tempref,reg.reglo));
  2597. inc(tempref.offset,2);
  2598. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,cg.GetNextReg(reg.reglo)));
  2599. inc(tempref.offset,2);
  2600. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,reg.reghi));
  2601. inc(tempref.offset,2);
  2602. list.concat(taicpu.op_ref_reg(op2,S_W,tempref,cg.GetNextReg(reg.reghi)));
  2603. if op in [OP_ADD,OP_SUB] then
  2604. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2605. end
  2606. else
  2607. begin
  2608. a_load64_ref_reg(list,ref,reg);
  2609. a_op64_reg_reg(list,op,size,reg,reg);
  2610. end;
  2611. end;
  2612. procedure tcg64f8086.a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64; const ref: treference);
  2613. var
  2614. op1,op2 : TAsmOp;
  2615. tempref : treference;
  2616. begin
  2617. case op of
  2618. OP_NOT:
  2619. begin
  2620. tempref:=ref;
  2621. tcgx86(cg).make_simple_ref(list,tempref);
  2622. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2623. inc(tempref.offset,2);
  2624. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2625. inc(tempref.offset,2);
  2626. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2627. inc(tempref.offset,2);
  2628. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2629. end;
  2630. OP_NEG:
  2631. begin
  2632. tempref:=ref;
  2633. tcgx86(cg).make_simple_ref(list,tempref);
  2634. inc(tempref.offset,6);
  2635. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2636. dec(tempref.offset,2);
  2637. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2638. dec(tempref.offset,2);
  2639. list.concat(taicpu.op_ref(A_NOT,S_W,tempref));
  2640. dec(tempref.offset,2);
  2641. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2642. list.concat(taicpu.op_ref(A_NEG,S_W,tempref));
  2643. inc(tempref.offset,2);
  2644. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2645. inc(tempref.offset,2);
  2646. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2647. inc(tempref.offset,2);
  2648. list.concat(taicpu.op_const_ref(A_SBB,S_W,-1,tempref));
  2649. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2650. end;
  2651. else
  2652. begin
  2653. get_64bit_ops(op,op1,op2);
  2654. tempref:=ref;
  2655. tcgx86(cg).make_simple_ref(list,tempref);
  2656. if op in [OP_ADD,OP_SUB] then
  2657. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2658. list.concat(taicpu.op_reg_ref(op1,S_W,reg.reglo,tempref));
  2659. inc(tempref.offset,2);
  2660. list.concat(taicpu.op_reg_ref(op2,S_W,cg.GetNextReg(reg.reglo),tempref));
  2661. inc(tempref.offset,2);
  2662. list.concat(taicpu.op_reg_ref(op2,S_W,reg.reghi,tempref));
  2663. inc(tempref.offset,2);
  2664. list.concat(taicpu.op_reg_ref(op2,S_W,cg.GetNextReg(reg.reghi),tempref));
  2665. if op in [OP_ADD,OP_SUB] then
  2666. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2667. end;
  2668. end;
  2669. end;
  2670. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2671. var
  2672. op1,op2 : TAsmOp;
  2673. l2, l3: TAsmLabel;
  2674. ai: taicpu;
  2675. begin
  2676. case op of
  2677. OP_NEG :
  2678. begin
  2679. if (regsrc.reglo<>regdst.reglo) then
  2680. a_load64_reg_reg(list,regsrc,regdst);
  2681. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2682. list.concat(taicpu.op_reg(A_NOT,S_W,cg.GetNextReg(regdst.reglo)));
  2683. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2684. list.concat(taicpu.op_reg(A_NEG,S_W,regdst.reglo));
  2685. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,cg.GetNextReg(regdst.reglo)));
  2686. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  2687. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,cg.GetNextReg(regdst.reghi)));
  2688. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2689. exit;
  2690. end;
  2691. OP_NOT :
  2692. begin
  2693. if (regsrc.reglo<>regdst.reglo) then
  2694. a_load64_reg_reg(list,regsrc,regdst);
  2695. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  2696. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  2697. exit;
  2698. end;
  2699. OP_SHR,OP_SHL,OP_SAR:
  2700. begin
  2701. { load right operators in a register }
  2702. cg.getcpuregister(list,NR_CX);
  2703. cg.a_load_reg_reg(list,OS_16,OS_16,regsrc.reglo,NR_CX);
  2704. current_asmdata.getjumplabel(l2);
  2705. current_asmdata.getjumplabel(l3);
  2706. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2707. list.concat(taicpu.op_const_reg(A_AND,S_W,63,NR_CX));
  2708. cg.a_jmp_flags(list,F_E,l3);
  2709. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2710. cg.a_label(list,l2);
  2711. case op of
  2712. OP_SHL:
  2713. begin
  2714. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2715. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,regdst.reglo));
  2716. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(regdst.reglo)));
  2717. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,regdst.reghi));
  2718. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(regdst.reghi)));
  2719. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2720. end;
  2721. OP_SHR,OP_SAR:
  2722. begin
  2723. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2724. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(regdst.reghi));
  2725. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,regdst.reghi));
  2726. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(regdst.reglo)));
  2727. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,regdst.reglo));
  2728. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2729. end;
  2730. end;
  2731. ai:=Taicpu.Op_Sym(A_LOOP,S_W,l2);
  2732. ai.is_jmp := True;
  2733. list.Concat(ai);
  2734. cg.a_label(list,l3);
  2735. cg.ungetcpuregister(list,NR_CX);
  2736. exit;
  2737. end;
  2738. end;
  2739. get_64bit_ops(op,op1,op2);
  2740. if op in [OP_ADD,OP_SUB] then
  2741. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2742. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  2743. list.concat(taicpu.op_reg_reg(op2,S_W,cg.GetNextReg(regsrc.reglo),cg.GetNextReg(regdst.reglo)));
  2744. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  2745. list.concat(taicpu.op_reg_reg(op2,S_W,cg.GetNextReg(regsrc.reghi),cg.GetNextReg(regdst.reghi)));
  2746. if op in [OP_ADD,OP_SUB] then
  2747. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2748. end;
  2749. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2750. var
  2751. op1,op2 : TAsmOp;
  2752. loop_start: TAsmLabel;
  2753. ai: taicpu;
  2754. begin
  2755. case op of
  2756. OP_AND,OP_OR,OP_XOR:
  2757. begin
  2758. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  2759. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  2760. end;
  2761. OP_ADD, OP_SUB:
  2762. begin
  2763. get_64bit_ops(op,op1,op2);
  2764. if (value and $ffffffffffff) = 0 then
  2765. begin
  2766. { use a_op_const_reg to allow the use of inc/dec }
  2767. cg.a_op_const_reg(list,op,OS_16,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi));
  2768. end
  2769. // can't use a_op_const_ref because this may use dec/inc
  2770. else if (value and $ffffffff) = 0 then
  2771. begin
  2772. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2773. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2774. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2775. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2776. end
  2777. else if (value and $ffff) = 0 then
  2778. begin
  2779. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2780. list.concat(taicpu.op_const_reg(op1,S_W,aint((value shr 16) and $ffff),cg.GetNextReg(reg.reglo)));
  2781. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2782. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2783. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2784. end
  2785. else
  2786. begin
  2787. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2788. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  2789. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),cg.GetNextReg(reg.reglo)));
  2790. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  2791. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),cg.GetNextReg(reg.reghi)));
  2792. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2793. end;
  2794. end;
  2795. OP_SHR,OP_SHL,OP_SAR:
  2796. begin
  2797. value:=value and 63;
  2798. case value of
  2799. 0:
  2800. { ultra hyper fast shift by 0 };
  2801. 1:
  2802. case op of
  2803. OP_SHL:
  2804. begin
  2805. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2806. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg.reglo));
  2807. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reglo)));
  2808. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2809. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2810. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2811. end;
  2812. OP_SHR,OP_SAR:
  2813. begin
  2814. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2815. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(reg.reghi));
  2816. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reghi));
  2817. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2818. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2819. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2820. end;
  2821. end;
  2822. 2..15:
  2823. begin
  2824. cg.getcpuregister(list,NR_CX);
  2825. cg.a_load_const_reg(list,OS_16,value,NR_CX);
  2826. current_asmdata.getjumplabel(loop_start);
  2827. cg.a_label(list,loop_start);
  2828. case op of
  2829. OP_SHL:
  2830. begin
  2831. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2832. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg.reglo));
  2833. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reglo)));
  2834. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2835. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2836. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2837. end;
  2838. OP_SHR,OP_SAR:
  2839. begin
  2840. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2841. cg.a_op_const_reg(list,op,OS_16,1,cg.GetNextReg(reg.reghi));
  2842. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reghi));
  2843. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2844. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2845. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2846. end;
  2847. end;
  2848. ai:=Taicpu.Op_Sym(A_LOOP,S_W,loop_start);
  2849. ai.is_jmp := True;
  2850. list.Concat(ai);
  2851. cg.ungetcpuregister(list,NR_CX);
  2852. end;
  2853. 16,17:
  2854. begin
  2855. case op of
  2856. OP_SHL:
  2857. begin
  2858. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2859. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  2860. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reglo));
  2861. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2862. end;
  2863. OP_SHR:
  2864. begin
  2865. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2866. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2867. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2868. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2869. end;
  2870. OP_SAR:
  2871. begin
  2872. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2873. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2874. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2875. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2876. end;
  2877. end;
  2878. if value=17 then
  2879. case op of
  2880. OP_SHL:
  2881. begin
  2882. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2883. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,cg.GetNextReg(reg.reglo)));
  2884. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2885. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2886. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2887. end;
  2888. OP_SHR,OP_SAR:
  2889. begin
  2890. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2891. cg.a_op_const_reg(list,op,OS_16,1,reg.reghi);
  2892. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2893. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2894. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2895. end;
  2896. end;
  2897. end;
  2898. 18..31:
  2899. begin
  2900. case op of
  2901. OP_SHL:
  2902. begin
  2903. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2904. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  2905. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reglo));
  2906. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2907. end;
  2908. OP_SHR:
  2909. begin
  2910. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2911. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2912. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2913. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2914. end;
  2915. OP_SAR:
  2916. begin
  2917. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reglo);
  2918. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reglo));
  2919. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2920. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2921. end;
  2922. end;
  2923. cg.getcpuregister(list,NR_CX);
  2924. cg.a_load_const_reg(list,OS_16,value-16,NR_CX);
  2925. current_asmdata.getjumplabel(loop_start);
  2926. cg.a_label(list,loop_start);
  2927. case op of
  2928. OP_SHL:
  2929. begin
  2930. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2931. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,cg.GetNextReg(reg.reglo)));
  2932. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,reg.reghi));
  2933. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,cg.GetNextReg(reg.reghi)));
  2934. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2935. end;
  2936. OP_SHR,OP_SAR:
  2937. begin
  2938. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2939. cg.a_op_const_reg(list,op,OS_16,1,reg.reghi);
  2940. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,cg.GetNextReg(reg.reglo)));
  2941. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg.reglo));
  2942. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2943. end;
  2944. end;
  2945. ai:=Taicpu.Op_Sym(A_LOOP,S_W,loop_start);
  2946. ai.is_jmp := True;
  2947. list.Concat(ai);
  2948. cg.ungetcpuregister(list,NR_CX);
  2949. end;
  2950. 32..47:
  2951. case op of
  2952. OP_SHL:
  2953. begin
  2954. cg.a_op_const_reg_reg(list,OP_SHL,OS_32,value-32,reg.reglo,reg.reghi);
  2955. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2956. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2957. end;
  2958. OP_SHR:
  2959. begin
  2960. cg.a_op_const_reg_reg(list,OP_SHR,OS_32,value-32,reg.reghi,reg.reglo);
  2961. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2962. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2963. end;
  2964. OP_SAR:
  2965. begin
  2966. cg.a_op_const_reg_reg(list,OP_SAR,OS_32,value-32,reg.reghi,reg.reglo);
  2967. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,15-(value-32),cg.GetNextReg(reg.reglo),reg.reghi);
  2968. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reghi,cg.GetNextReg(reg.reghi));
  2969. end;
  2970. end;
  2971. 48..63:
  2972. case op of
  2973. OP_SHL:
  2974. begin
  2975. cg.a_load_reg_reg(list,OS_16,OS_16,reg.reglo,cg.GetNextReg(reg.reghi));
  2976. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reglo,reg.reglo);
  2977. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2978. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2979. cg.a_op_const_reg(list,OP_SHL,OS_16,value-48,cg.GetNextReg(reg.reghi));
  2980. end;
  2981. OP_SHR:
  2982. begin
  2983. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reglo);
  2984. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reghi));
  2985. cg.a_op_reg_reg(list,OP_XOR,OS_16,reg.reghi,reg.reghi);
  2986. cg.a_op_reg_reg(list,OP_XOR,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reglo));
  2987. cg.a_op_const_reg(list,OP_SHR,OS_16,value-48,reg.reglo);
  2988. end;
  2989. OP_SAR:
  2990. if value=63 then
  2991. begin
  2992. cg.a_op_const_reg(list,OP_SAR,OS_16,15,cg.GetNextReg(reg.reghi));
  2993. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reghi);
  2994. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),cg.GetNextReg(reg.reglo));
  2995. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reghi),reg.reglo);
  2996. end
  2997. else
  2998. begin
  2999. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,value-48,cg.GetNextReg(reg.reghi),reg.reglo);
  3000. cg.a_op_const_reg_reg(list,OP_SAR,OS_16,15-(value-48),reg.reglo,cg.GetNextReg(reg.reglo));
  3001. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),reg.reghi);
  3002. cg.a_load_reg_reg(list,OS_16,OS_16,cg.GetNextReg(reg.reglo),cg.GetNextReg(reg.reghi));
  3003. end;
  3004. end;
  3005. end;
  3006. end;
  3007. else
  3008. internalerror(200204021);
  3009. end;
  3010. end;
  3011. procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  3012. var
  3013. op1,op2 : TAsmOp;
  3014. tempref : treference;
  3015. begin
  3016. tempref:=ref;
  3017. tcgx86(cg).make_simple_ref(list,tempref);
  3018. case op of
  3019. OP_AND,OP_OR,OP_XOR:
  3020. begin
  3021. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  3022. inc(tempref.offset,4);
  3023. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  3024. end;
  3025. OP_ADD, OP_SUB:
  3026. begin
  3027. get_64bit_ops(op,op1,op2);
  3028. if (value and $ffffffffffff) = 0 then
  3029. begin
  3030. inc(tempref.offset,6);
  3031. { use a_op_const_ref to allow the use of inc/dec }
  3032. cg.a_op_const_ref(list,op,OS_16,aint((value shr 48) and $ffff),tempref);
  3033. end
  3034. // can't use a_op_const_ref because this may use dec/inc
  3035. else if (value and $ffffffff) = 0 then
  3036. begin
  3037. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3038. inc(tempref.offset,4);
  3039. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 32) and $ffff),tempref));
  3040. inc(tempref.offset,2);
  3041. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3042. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3043. end
  3044. else if (value and $ffff) = 0 then
  3045. begin
  3046. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3047. inc(tempref.offset,2);
  3048. list.concat(taicpu.op_const_ref(op1,S_W,aint((value shr 16) and $ffff),tempref));
  3049. inc(tempref.offset,2);
  3050. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  3051. inc(tempref.offset,2);
  3052. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3053. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3054. end
  3055. else
  3056. begin
  3057. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3058. list.concat(taicpu.op_const_ref(op1,S_W,aint(value and $ffff),tempref));
  3059. inc(tempref.offset,2);
  3060. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 16) and $ffff),tempref));
  3061. inc(tempref.offset,2);
  3062. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 32) and $ffff),tempref));
  3063. inc(tempref.offset,2);
  3064. list.concat(taicpu.op_const_ref(op2,S_W,aint((value shr 48) and $ffff),tempref));
  3065. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3066. end;
  3067. end;
  3068. else
  3069. internalerror(200204022);
  3070. end;
  3071. end;
  3072. procedure create_codegen;
  3073. begin
  3074. cg := tcg8086.create;
  3075. cg64 := tcg64f8086.create;
  3076. end;
  3077. end.