cgcpu.pas 98 KB

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