cgcpu.pas 110 KB

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