2
0

cgcpu.pas 92 KB

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