cgcpu.pas 92 KB

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