cgcpu.pas 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831
  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_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  34. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
  35. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  36. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
  37. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
  38. procedure push_const(list:TAsmList;size:tcgsize;a:tcgint);
  39. { passing parameter using push instead of mov }
  40. procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);override;
  41. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);override;
  42. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);override;
  43. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);override;
  44. { move instructions }
  45. procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
  46. procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
  47. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);override;
  48. procedure a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);override;
  49. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);override;
  50. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);override;
  51. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);override;
  52. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
  53. procedure g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  54. procedure g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  55. procedure g_exception_reason_save(list : TAsmList; const href : treference);override;
  56. procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: tcgint);override;
  57. procedure g_exception_reason_load(list : TAsmList; const href : treference);override;
  58. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);override;
  59. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  60. procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
  61. end;
  62. tcg64f8086 = class(tcg64f32)
  63. { procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override;}
  64. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  65. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  66. { procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);override;}
  67. private
  68. procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  69. end;
  70. procedure create_codegen;
  71. implementation
  72. uses
  73. globals,verbose,systems,cutils,
  74. paramgr,procinfo,fmodule,
  75. rgcpu,rgx86,cpuinfo,
  76. symtype,symsym;
  77. function use_push(const cgpara:tcgpara):boolean;
  78. begin
  79. result:=(not paramanager.use_fixed_stack) and
  80. assigned(cgpara.location) and
  81. (cgpara.location^.loc=LOC_REFERENCE) and
  82. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  83. end;
  84. procedure tcg8086.init_register_allocators;
  85. begin
  86. inherited init_register_allocators;
  87. if not(target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  88. (cs_create_pic in current_settings.moduleswitches) then
  89. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI],first_int_imreg,[RS_BP])
  90. else
  91. if (cs_useebp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer<>NR_BP) then
  92. 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,[])
  93. else
  94. 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]);
  95. 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,[]);
  96. 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,[]);
  97. rgfpu:=Trgx86fpu.create;
  98. end;
  99. procedure tcg8086.do_register_allocation(list:TAsmList;headertai:tai);
  100. begin
  101. if (pi_needs_got in current_procinfo.flags) then
  102. begin
  103. if getsupreg(current_procinfo.got) < first_int_imreg then
  104. include(rg[R_INTREGISTER].used_in_proc,getsupreg(current_procinfo.got));
  105. end;
  106. inherited do_register_allocation(list,headertai);
  107. end;
  108. function tcg8086.getintregister(list: TAsmList; size: Tcgsize): Tregister;
  109. begin
  110. case size of
  111. OS_8, OS_S8,
  112. OS_16, OS_S16:
  113. Result := inherited getintregister(list, size);
  114. OS_32, OS_S32:
  115. begin
  116. Result:=inherited getintregister(list, OS_16);
  117. { ensure that the high register can be retrieved by
  118. GetNextReg
  119. }
  120. if inherited getintregister(list, OS_16)<>GetNextReg(Result) then
  121. internalerror(2013030202);
  122. end;
  123. else
  124. internalerror(2013030201);
  125. end;
  126. end;
  127. procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  128. a: tcgint; reg: TRegister);
  129. var
  130. tmpreg: tregister;
  131. op1, op2: TAsmOp;
  132. ax_subreg: tregister;
  133. hl_loop_start: tasmlabel;
  134. ai: taicpu;
  135. use_loop: Boolean;
  136. i: Integer;
  137. begin
  138. optimize_op_const(op, a);
  139. check_register_size(size,reg);
  140. if size in [OS_64, OS_S64] then
  141. internalerror(2013030904);
  142. if size in [OS_32, OS_S32] then
  143. begin
  144. case op of
  145. OP_NONE:
  146. begin
  147. { Opcode is optimized away }
  148. end;
  149. OP_MOVE:
  150. begin
  151. { Optimized, replaced with a simple load }
  152. a_load_const_reg(list,size,a,reg);
  153. end;
  154. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  155. begin
  156. if (longword(a) = high(longword)) and
  157. (op in [OP_AND,OP_OR,OP_XOR]) then
  158. begin
  159. case op of
  160. OP_AND:
  161. exit;
  162. OP_OR:
  163. a_load_const_reg(list,size,high(longword),reg);
  164. OP_XOR:
  165. begin
  166. list.concat(taicpu.op_reg(A_NOT,S_W,reg));
  167. list.concat(taicpu.op_reg(A_NOT,S_W,GetNextReg(reg)));
  168. end;
  169. end
  170. end
  171. else
  172. begin
  173. get_32bit_ops(op, op1, op2);
  174. list.concat(taicpu.op_const_reg(op1,S_W,aint(a and $FFFF),reg));
  175. list.concat(taicpu.op_const_reg(op2,S_W,aint(a shr 16),GetNextReg(reg)));
  176. end;
  177. end;
  178. OP_SHR,OP_SHL,OP_SAR:
  179. begin
  180. a:=a and 31;
  181. if a<>0 then
  182. begin
  183. use_loop:=a>2;
  184. if use_loop then
  185. begin
  186. getcpuregister(list,NR_CX);
  187. a_load_const_reg(list,OS_16,a,NR_CX);
  188. current_asmdata.getjumplabel(hl_loop_start);
  189. a_label(list,hl_loop_start);
  190. case op of
  191. OP_SHR:
  192. begin
  193. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  194. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  195. end;
  196. OP_SAR:
  197. begin
  198. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  199. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  200. end;
  201. OP_SHL:
  202. begin
  203. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  204. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  205. end;
  206. else
  207. internalerror(2013030903);
  208. end;
  209. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  210. ai.is_jmp:=true;
  211. list.concat(ai);
  212. ungetcpuregister(list,NR_CX);
  213. end
  214. else
  215. begin
  216. for i:=1 to a do
  217. begin
  218. case op of
  219. OP_SHR:
  220. begin
  221. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(reg)));
  222. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  223. end;
  224. OP_SAR:
  225. begin
  226. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(reg)));
  227. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,reg));
  228. end;
  229. OP_SHL:
  230. begin
  231. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,reg));
  232. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(reg)));
  233. end;
  234. else
  235. internalerror(2013030903);
  236. end;
  237. end;
  238. end;
  239. end;
  240. end;
  241. else
  242. begin
  243. tmpreg:=getintregister(list,size);
  244. a_load_const_reg(list,size,a,tmpreg);
  245. a_op_reg_reg(list,op,size,tmpreg,reg);
  246. end;
  247. end;
  248. end
  249. else
  250. begin
  251. { size <= 16-bit }
  252. { 8086 doesn't support 'imul reg,const', so we handle it here }
  253. if (current_settings.cputype<cpu_186) and (op in [OP_MUL,OP_IMUL]) then
  254. begin
  255. { TODO: also enable the SHL optimization below }
  256. { if not(cs_check_overflow in current_settings.localswitches) and
  257. ispowerof2(int64(a),power) then
  258. begin
  259. list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
  260. exit;
  261. end;}
  262. if op = OP_IMUL then
  263. begin
  264. if size in [OS_16,OS_S16] then
  265. ax_subreg := NR_AX
  266. else
  267. if size in [OS_8,OS_S8] then
  268. ax_subreg := NR_AL
  269. else
  270. internalerror(2013050102);
  271. getcpuregister(list,NR_AX);
  272. if size in [OS_16,OS_S16] then
  273. getcpuregister(list,NR_DX);
  274. a_load_const_reg(list,size,a,ax_subreg);
  275. list.concat(taicpu.op_reg(A_IMUL,TCgSize2OpSize[size],reg));
  276. a_load_reg_reg(list,size,size,ax_subreg,reg);
  277. ungetcpuregister(list,NR_AX);
  278. if size in [OS_16,OS_S16] then
  279. ungetcpuregister(list,NR_DX);
  280. { TODO: implement overflow checking? }
  281. exit;
  282. end
  283. else
  284. { OP_MUL should be handled specifically in the code }
  285. { generator because of the silly register usage restraints }
  286. internalerror(200109225);
  287. end
  288. else
  289. inherited a_op_const_reg(list, Op, size, a, reg);
  290. end;
  291. end;
  292. procedure tcg8086.a_op_const_ref(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  293. var
  294. tmpref: treference;
  295. op1,op2: TAsmOp;
  296. begin
  297. optimize_op_const(op, a);
  298. tmpref:=ref;
  299. make_simple_ref(list,tmpref);
  300. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  301. begin
  302. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  303. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  304. tmpref.segment:=NR_ES;
  305. end;
  306. if size in [OS_64, OS_S64] then
  307. internalerror(2013050801);
  308. if size in [OS_32, OS_S32] then
  309. begin
  310. case Op of
  311. OP_NONE :
  312. begin
  313. { Opcode is optimized away }
  314. end;
  315. OP_MOVE :
  316. begin
  317. { Optimized, replaced with a simple load }
  318. a_load_const_ref(list,size,a,ref);
  319. end;
  320. OP_ADD, OP_AND, OP_OR, OP_SUB, OP_XOR:
  321. begin
  322. if (longword(a) = high(longword)) and
  323. (op in [OP_AND,OP_OR,OP_XOR]) then
  324. begin
  325. case op of
  326. OP_AND:
  327. exit;
  328. OP_OR:
  329. a_load_const_ref(list,size,high(longword),tmpref);
  330. OP_XOR:
  331. begin
  332. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  333. inc(tmpref.offset, 2);
  334. list.concat(taicpu.op_ref(A_NOT,S_W,tmpref));
  335. end;
  336. end
  337. end
  338. else
  339. begin
  340. get_32bit_ops(op, op1, op2);
  341. list.concat(taicpu.op_const_ref(op1,S_W,aint(a and $FFFF),tmpref));
  342. inc(tmpref.offset, 2);
  343. list.concat(taicpu.op_const_ref(op2,S_W,aint(a shr 16),tmpref));
  344. end;
  345. end;
  346. else
  347. internalerror(2013050802);
  348. end;
  349. end
  350. else
  351. inherited a_op_const_ref(list,Op,size,a,tmpref);
  352. end;
  353. procedure tcg8086.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
  354. src, dst: TRegister);
  355. var
  356. op1, op2: TAsmOp;
  357. hl_skip, hl_loop_start: TAsmLabel;
  358. ai: taicpu;
  359. begin
  360. check_register_size(size,src);
  361. check_register_size(size,dst);
  362. if size in [OS_64, OS_S64] then
  363. internalerror(2013030902);
  364. if size in [OS_32, OS_S32] then
  365. begin
  366. case op of
  367. OP_NEG:
  368. begin
  369. if src<>dst then
  370. a_load_reg_reg(list,size,size,src,dst);
  371. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  372. list.concat(taicpu.op_reg(A_NEG, S_W, dst));
  373. list.concat(taicpu.op_const_reg(A_SBB, S_W,-1, GetNextReg(dst)));
  374. end;
  375. OP_NOT:
  376. begin
  377. if src<>dst then
  378. a_load_reg_reg(list,size,size,src,dst);
  379. list.concat(taicpu.op_reg(A_NOT, S_W, dst));
  380. list.concat(taicpu.op_reg(A_NOT, S_W, GetNextReg(dst)));
  381. end;
  382. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  383. begin
  384. get_32bit_ops(op, op1, op2);
  385. list.concat(taicpu.op_reg_reg(op1, S_W, src, dst));
  386. list.concat(taicpu.op_reg_reg(op2, S_W, GetNextReg(src), GetNextReg(dst)));
  387. end;
  388. OP_SHR,OP_SHL,OP_SAR:
  389. begin
  390. getcpuregister(list,NR_CX);
  391. a_load_reg_reg(list,size,OS_16,src,NR_CX);
  392. list.concat(taicpu.op_const_reg(A_AND,S_W,$1f,NR_CX));
  393. current_asmdata.getjumplabel(hl_skip);
  394. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  395. ai.SetCondition(C_Z);
  396. ai.is_jmp:=true;
  397. list.concat(ai);
  398. current_asmdata.getjumplabel(hl_loop_start);
  399. a_label(list,hl_loop_start);
  400. case op of
  401. OP_SHR:
  402. begin
  403. list.concat(taicpu.op_const_reg(A_SHR,S_W,1,GetNextReg(dst)));
  404. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  405. end;
  406. OP_SAR:
  407. begin
  408. list.concat(taicpu.op_const_reg(A_SAR,S_W,1,GetNextReg(dst)));
  409. list.concat(taicpu.op_const_reg(A_RCR,S_W,1,dst));
  410. end;
  411. OP_SHL:
  412. begin
  413. list.concat(taicpu.op_const_reg(A_SHL,S_W,1,dst));
  414. list.concat(taicpu.op_const_reg(A_RCL,S_W,1,GetNextReg(dst)));
  415. end;
  416. else
  417. internalerror(2013030903);
  418. end;
  419. ai:=Taicpu.Op_Sym(A_LOOP,S_W,hl_loop_start);
  420. ai.is_jmp:=true;
  421. list.concat(ai);
  422. a_label(list,hl_skip);
  423. ungetcpuregister(list,NR_CX);
  424. end;
  425. else
  426. internalerror(2013030901);
  427. end;
  428. end
  429. else
  430. inherited a_op_reg_reg(list, Op, size, src, dst);
  431. end;
  432. procedure tcg8086.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  433. var
  434. tmpref : treference;
  435. op1, op2: TAsmOp;
  436. begin
  437. tmpref:=ref;
  438. make_simple_ref(list,tmpref);
  439. check_register_size(size,reg);
  440. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  441. begin
  442. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  443. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  444. tmpref.segment:=NR_ES;
  445. end;
  446. if size in [OS_64, OS_S64] then
  447. internalerror(2013030902);
  448. if size in [OS_32, OS_S32] then
  449. begin
  450. case op of
  451. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  452. begin
  453. get_32bit_ops(op, op1, op2);
  454. list.concat(taicpu.op_ref_reg(op1, S_W, tmpref, reg));
  455. inc(tmpref.offset, 2);
  456. list.concat(taicpu.op_ref_reg(op2, S_W, tmpref, GetNextReg(reg)));
  457. end;
  458. else
  459. internalerror(2013050701);
  460. end;
  461. end
  462. else
  463. inherited a_op_ref_reg(list,Op,size,tmpref,reg);
  464. end;
  465. procedure tcg8086.a_op_reg_ref(list: TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference);
  466. var
  467. tmpref: treference;
  468. op1,op2: TAsmOp;
  469. begin
  470. tmpref:=ref;
  471. make_simple_ref(list,tmpref);
  472. check_register_size(size,reg);
  473. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  474. begin
  475. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  476. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  477. tmpref.segment:=NR_ES;
  478. end;
  479. if size in [OS_64, OS_S64] then
  480. internalerror(2013050803);
  481. if size in [OS_32, OS_S32] then
  482. begin
  483. case op of
  484. OP_NEG:
  485. begin
  486. if reg<>NR_NO then
  487. internalerror(200109237);
  488. inc(tmpref.offset, 2);
  489. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  490. dec(tmpref.offset, 2);
  491. list.concat(taicpu.op_ref(A_NEG, S_W, tmpref));
  492. inc(tmpref.offset, 2);
  493. list.concat(taicpu.op_const_ref(A_SBB, S_W,-1, tmpref));
  494. end;
  495. OP_NOT:
  496. begin
  497. if reg<>NR_NO then
  498. internalerror(200109237);
  499. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  500. inc(tmpref.offset, 2);
  501. list.concat(taicpu.op_ref(A_NOT, S_W, tmpref));
  502. end;
  503. OP_IMUL:
  504. begin
  505. { this one needs a load/imul/store, which is the default }
  506. inherited a_op_ref_reg(list,op,size,tmpref,reg);
  507. end;
  508. OP_MUL,OP_DIV,OP_IDIV:
  509. { special stuff, needs separate handling inside code }
  510. { generator }
  511. internalerror(200109238);
  512. OP_ADD,OP_SUB,OP_XOR,OP_OR,OP_AND:
  513. begin
  514. get_32bit_ops(op, op1, op2);
  515. list.concat(taicpu.op_reg_ref(op1, S_W, reg, tmpref));
  516. inc(tmpref.offset, 2);
  517. list.concat(taicpu.op_reg_ref(op2, S_W, GetNextReg(reg), tmpref));
  518. end;
  519. else
  520. internalerror(2013050804);
  521. end;
  522. end
  523. else
  524. inherited a_op_reg_ref(list,Op,size,reg,tmpref);
  525. end;
  526. procedure tcg8086.push_const(list: TAsmList; size: tcgsize; a: tcgint);
  527. var
  528. tmpreg: TRegister;
  529. begin
  530. if not (size in [OS_16,OS_S16]) then
  531. internalerror(2013043001);
  532. if current_settings.cputype < cpu_186 then
  533. begin
  534. tmpreg:=getintregister(list,size);
  535. a_load_const_reg(list,size,a,tmpreg);
  536. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpreg));
  537. end
  538. else
  539. list.concat(taicpu.op_const(A_PUSH,TCGSize2OpSize[size],a));
  540. end;
  541. procedure tcg8086.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  542. var
  543. pushsize, pushsize2: tcgsize;
  544. begin
  545. check_register_size(size,r);
  546. if use_push(cgpara) then
  547. begin
  548. if tcgsize2size[cgpara.Size] > 2 then
  549. begin
  550. if tcgsize2size[cgpara.Size] <> 4 then
  551. internalerror(2013031101);
  552. if cgpara.location^.Next = nil then
  553. begin
  554. if tcgsize2size[cgpara.location^.size] <> 4 then
  555. internalerror(2013031101);
  556. end
  557. else
  558. begin
  559. if tcgsize2size[cgpara.location^.size] <> 2 then
  560. internalerror(2013031101);
  561. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  562. internalerror(2013031101);
  563. if cgpara.location^.Next^.Next <> nil then
  564. internalerror(2013031101);
  565. end;
  566. if tcgsize2size[cgpara.size]>cgpara.alignment then
  567. pushsize:=cgpara.size
  568. else
  569. pushsize:=int_cgsize(cgpara.alignment);
  570. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  571. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  572. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  573. end
  574. else
  575. begin
  576. cgpara.check_simple_location;
  577. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  578. pushsize:=cgpara.location^.size
  579. else
  580. pushsize:=int_cgsize(cgpara.alignment);
  581. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  582. end;
  583. end
  584. else
  585. inherited a_load_reg_cgpara(list,size,r,cgpara);
  586. end;
  587. procedure tcg8086.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : tcgpara);
  588. var
  589. pushsize : tcgsize;
  590. begin
  591. if use_push(cgpara) then
  592. begin
  593. if tcgsize2size[cgpara.Size] > 2 then
  594. begin
  595. if tcgsize2size[cgpara.Size] <> 4 then
  596. internalerror(2013031101);
  597. if cgpara.location^.Next = nil then
  598. begin
  599. if tcgsize2size[cgpara.location^.size] <> 4 then
  600. internalerror(2013031101);
  601. end
  602. else
  603. begin
  604. if tcgsize2size[cgpara.location^.size] <> 2 then
  605. internalerror(2013031101);
  606. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  607. internalerror(2013031101);
  608. if cgpara.location^.Next^.Next <> nil then
  609. internalerror(2013031101);
  610. end;
  611. if (cgpara.alignment <> 4) and (cgpara.alignment <> 2) then
  612. internalerror(2013031101);
  613. push_const(list,OS_16,a shr 16);
  614. push_const(list,OS_16,a and $FFFF);
  615. end
  616. else
  617. begin
  618. cgpara.check_simple_location;
  619. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  620. pushsize:=cgpara.location^.size
  621. else
  622. pushsize:=int_cgsize(cgpara.alignment);
  623. push_const(list,pushsize,a);
  624. end;
  625. end
  626. else
  627. inherited a_load_const_cgpara(list,size,a,cgpara);
  628. end;
  629. procedure tcg8086.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : tcgpara);
  630. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  631. var
  632. pushsize : tcgsize;
  633. opsize : topsize;
  634. tmpreg : tregister;
  635. href,tmpref: treference;
  636. begin
  637. if not assigned(paraloc) then
  638. exit;
  639. if (paraloc^.loc<>LOC_REFERENCE) or
  640. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  641. (tcgsize2size[paraloc^.size]>4) then
  642. internalerror(200501162);
  643. { Pushes are needed in reverse order, add the size of the
  644. current location to the offset where to load from. This
  645. prevents wrong calculations for the last location when
  646. the size is not a power of 2 }
  647. if assigned(paraloc^.next) then
  648. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  649. { Push the data starting at ofs }
  650. href:=r;
  651. inc(href.offset,ofs);
  652. if tcgsize2size[paraloc^.size]>cgpara.alignment then
  653. pushsize:=paraloc^.size
  654. else
  655. pushsize:=int_cgsize(cgpara.alignment);
  656. opsize:=TCgsize2opsize[pushsize];
  657. { for go32v2 we obtain OS_F32,
  658. but pushs is not valid, we need pushl }
  659. if opsize=S_FS then
  660. opsize:=S_W;
  661. if tcgsize2size[paraloc^.size]<cgpara.alignment then
  662. begin
  663. tmpreg:=getintregister(list,pushsize);
  664. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  665. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  666. end
  667. else
  668. begin
  669. make_simple_ref(list,href);
  670. if tcgsize2size[pushsize] > 2 then
  671. begin
  672. tmpref := href;
  673. Inc(tmpref.offset, 2);
  674. list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  675. end;
  676. list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  677. end;
  678. end;
  679. var
  680. len : tcgint;
  681. href : treference;
  682. begin
  683. { cgpara.size=OS_NO requires a copy on the stack }
  684. if use_push(cgpara) then
  685. begin
  686. { Record copy? }
  687. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  688. begin
  689. cgpara.check_simple_location;
  690. len:=align(cgpara.intsize,cgpara.alignment);
  691. g_stackpointer_alloc(list,len);
  692. reference_reset_base(href,NR_STACK_POINTER_REG,0,4);
  693. g_concatcopy(list,r,href,len);
  694. end
  695. else
  696. begin
  697. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  698. internalerror(200501161);
  699. { We need to push the data in reverse order,
  700. therefor we use a recursive algorithm }
  701. pushdata(cgpara.location,0);
  702. end
  703. end
  704. else
  705. inherited a_load_ref_cgpara(list,size,r,cgpara);
  706. end;
  707. procedure tcg8086.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : tcgpara);
  708. var
  709. tmpreg : tregister;
  710. opsize : topsize;
  711. tmpref : treference;
  712. begin
  713. with r do
  714. begin
  715. if use_push(cgpara) then
  716. begin
  717. cgpara.check_simple_location;
  718. opsize:=tcgsize2opsize[OS_ADDR];
  719. if (segment=NR_NO) and (base=NR_NO) and (index=NR_NO) then
  720. begin
  721. if assigned(symbol) then
  722. begin
  723. if current_settings.cputype < cpu_186 then
  724. begin
  725. tmpreg:=getaddressregister(list);
  726. a_loadaddr_ref_reg(list,r,tmpreg);
  727. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  728. end
  729. else
  730. list.concat(Taicpu.Op_sym_ofs(A_PUSH,opsize,symbol,offset));
  731. end
  732. else
  733. push_const(list,OS_ADDR,offset);
  734. end
  735. else if (segment=NR_NO) and (base=NR_NO) and (index<>NR_NO) and
  736. (offset=0) and (scalefactor=0) and (symbol=nil) then
  737. list.concat(Taicpu.Op_reg(A_PUSH,opsize,index))
  738. else if (segment=NR_NO) and (base<>NR_NO) and (index=NR_NO) and
  739. (offset=0) and (symbol=nil) then
  740. list.concat(Taicpu.Op_reg(A_PUSH,opsize,base))
  741. else
  742. begin
  743. tmpreg:=getaddressregister(list);
  744. a_loadaddr_ref_reg(list,r,tmpreg);
  745. list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  746. end;
  747. end
  748. else
  749. inherited a_loadaddr_ref_cgpara(list,r,cgpara);
  750. end;
  751. end;
  752. procedure tcg8086.a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);
  753. begin
  754. check_register_size(tosize,reg);
  755. if tosize in [OS_S32,OS_32] then
  756. begin
  757. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a and $ffff),reg));
  758. list.concat(taicpu.op_const_reg(A_MOV,S_W,longint(a shr 16),GetNextReg(reg)));
  759. end
  760. else
  761. list.concat(taicpu.op_const_reg(A_MOV,TCGSize2OpSize[tosize],a,reg));
  762. end;
  763. procedure tcg8086.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
  764. var
  765. tmpref : treference;
  766. begin
  767. tmpref:=ref;
  768. make_simple_ref(list,tmpref);
  769. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  770. begin
  771. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  772. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  773. tmpref.segment:=NR_ES;
  774. end;
  775. if tosize in [OS_S32,OS_32] then
  776. begin
  777. a_load_const_ref(list,OS_16,longint(a and $ffff),tmpref);
  778. inc(tmpref.offset,2);
  779. a_load_const_ref(list,OS_16,longint(a shr 16),tmpref);
  780. end
  781. else
  782. list.concat(taicpu.op_const_ref(A_MOV,TCGSize2OpSize[tosize],a,tmpref));
  783. end;
  784. procedure tcg8086.a_load_reg_ref(list : TAsmList;fromsize,tosize: tcgsize; reg : tregister;const ref : treference);
  785. var
  786. tmpsize : tcgsize;
  787. tmpreg : tregister;
  788. tmpref : treference;
  789. begin
  790. tmpref:=ref;
  791. make_simple_ref(list,tmpref);
  792. check_register_size(fromsize,reg);
  793. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  794. begin
  795. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  796. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  797. tmpref.segment:=NR_ES;
  798. end;
  799. case tosize of
  800. OS_8,OS_S8:
  801. if fromsize in [OS_8,OS_S8] then
  802. list.concat(taicpu.op_reg_ref(A_MOV, S_B, reg, tmpref))
  803. else
  804. internalerror(2013030310);
  805. OS_16,OS_S16:
  806. case fromsize of
  807. OS_8:
  808. begin
  809. reg := makeregsize(list, reg, OS_16);
  810. setsubreg(reg, R_SUBH);
  811. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  812. setsubreg(reg, R_SUBW);
  813. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  814. end;
  815. OS_S8: internalerror(2013052503); { TODO }
  816. OS_16,OS_S16:
  817. begin
  818. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  819. end;
  820. else
  821. internalerror(2013030312);
  822. end;
  823. OS_32,OS_S32:
  824. case fromsize of
  825. OS_8:
  826. begin
  827. reg := makeregsize(list, reg, OS_16);
  828. setsubreg(reg, R_SUBH);
  829. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg));
  830. setsubreg(reg, R_SUBW);
  831. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  832. inc(tmpref.offset, 2);
  833. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  834. end;
  835. OS_S8:
  836. internalerror(2013052501); { TODO }
  837. OS_16:
  838. begin
  839. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  840. inc(tmpref.offset, 2);
  841. list.concat(taicpu.op_const_ref(A_MOV, S_W, 0, tmpref));
  842. end;
  843. OS_S16:
  844. internalerror(2013052502); { TODO }
  845. OS_32,OS_S32:
  846. begin
  847. list.concat(taicpu.op_reg_ref(A_MOV, S_W, reg, tmpref));
  848. inc(tmpref.offset, 2);
  849. list.concat(taicpu.op_reg_ref(A_MOV, S_W, GetNextReg(reg), tmpref));
  850. end;
  851. else
  852. internalerror(2013030313);
  853. end;
  854. else
  855. internalerror(2013030311);
  856. end;
  857. end;
  858. procedure tcg8086.a_load_ref_reg(list : TAsmList;fromsize,tosize: tcgsize;const ref : treference;reg : tregister);
  859. procedure add_mov(instr: Taicpu);
  860. begin
  861. { Notify the register allocator that we have written a move instruction so
  862. it can try to eliminate it. }
  863. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  864. add_move_instruction(instr);
  865. list.concat(instr);
  866. end;
  867. var
  868. tmpref : treference;
  869. begin
  870. tmpref:=ref;
  871. make_simple_ref(list,tmpref);
  872. check_register_size(tosize,reg);
  873. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  874. internalerror(2011021307);
  875. { if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  876. fromsize:=tosize;}
  877. if (tmpref.segment<>NR_NO) and (not is_segment_reg(tmpref.segment)) then
  878. begin
  879. list.concat(taicpu.op_reg(A_PUSH,S_W,tmpref.segment));
  880. list.concat(taicpu.op_reg(A_POP,S_L,NR_ES));
  881. tmpref.segment:=NR_ES;
  882. end;
  883. case tosize of
  884. OS_8,OS_S8:
  885. if fromsize in [OS_8,OS_S8] then
  886. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg))
  887. else
  888. internalerror(2013030210);
  889. OS_16,OS_S16:
  890. case fromsize of
  891. OS_8:
  892. begin
  893. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  894. reg := makeregsize(list, reg, OS_8);
  895. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  896. end;
  897. OS_S8:
  898. begin
  899. getcpuregister(list, NR_AX);
  900. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  901. list.concat(taicpu.op_none(A_CBW));
  902. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  903. ungetcpuregister(list, NR_AX);
  904. end;
  905. OS_16,OS_S16:
  906. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  907. else
  908. internalerror(2013030212);
  909. end;
  910. OS_32,OS_S32:
  911. case fromsize of
  912. OS_8:
  913. begin
  914. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  915. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, reg));
  916. reg := makeregsize(list, reg, OS_8);
  917. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, reg));
  918. end;
  919. OS_S8:
  920. begin
  921. getcpuregister(list, NR_AX);
  922. getcpuregister(list, NR_DX);
  923. list.concat(taicpu.op_ref_reg(A_MOV, S_B, tmpref, NR_AL));
  924. list.concat(taicpu.op_none(A_CBW));
  925. list.concat(taicpu.op_none(A_CWD));
  926. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  927. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  928. ungetcpuregister(list, NR_AX);
  929. ungetcpuregister(list, NR_DX);
  930. end;
  931. OS_16:
  932. begin
  933. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  934. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg)));
  935. end;
  936. OS_S16:
  937. begin
  938. getcpuregister(list, NR_AX);
  939. getcpuregister(list, NR_DX);
  940. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, NR_AX));
  941. list.concat(taicpu.op_none(A_CWD));
  942. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg));
  943. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg)));
  944. ungetcpuregister(list, NR_AX);
  945. ungetcpuregister(list, NR_DX);
  946. end;
  947. OS_32,OS_S32:
  948. begin
  949. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, reg));
  950. inc(tmpref.offset, 2);
  951. list.concat(taicpu.op_ref_reg(A_MOV, S_W, tmpref, GetNextReg(reg)));
  952. end;
  953. else
  954. internalerror(2013030213);
  955. end;
  956. else
  957. internalerror(2013030211);
  958. end;
  959. end;
  960. procedure tcg8086.a_load_reg_reg(list : TAsmList;fromsize,tosize: tcgsize;reg1,reg2 : tregister);
  961. procedure add_mov(instr: Taicpu);
  962. begin
  963. { Notify the register allocator that we have written a move instruction so
  964. it can try to eliminate it. }
  965. if (instr.oper[0]^.reg<>current_procinfo.framepointer) and (instr.oper[0]^.reg<>NR_STACK_POINTER_REG) then
  966. add_move_instruction(instr);
  967. list.concat(instr);
  968. end;
  969. begin
  970. check_register_size(fromsize,reg1);
  971. check_register_size(tosize,reg2);
  972. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  973. begin
  974. if tosize in [OS_32, OS_S32] then
  975. internalerror(2013031801);
  976. reg1:=makeregsize(list,reg1,tosize);
  977. fromsize:=tosize;
  978. end;
  979. if (reg1<>reg2) then
  980. begin
  981. case tosize of
  982. OS_8,OS_S8:
  983. if fromsize in [OS_8,OS_S8] then
  984. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2))
  985. else
  986. internalerror(2013030210);
  987. OS_16,OS_S16:
  988. case fromsize of
  989. OS_8:
  990. begin
  991. reg2 := makeregsize(list, reg2, OS_8);
  992. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  993. setsubreg(reg2,R_SUBH);
  994. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  995. end;
  996. OS_S8:
  997. begin
  998. getcpuregister(list, NR_AX);
  999. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1000. list.concat(taicpu.op_none(A_CBW));
  1001. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1002. ungetcpuregister(list, NR_AX);
  1003. end;
  1004. OS_16,OS_S16:
  1005. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1006. else
  1007. internalerror(2013030212);
  1008. end;
  1009. OS_32,OS_S32:
  1010. case fromsize of
  1011. OS_8:
  1012. begin
  1013. list.concat(taicpu.op_const_reg(A_MOV, S_W, 0, GetNextReg(reg2)));
  1014. reg2 := makeregsize(list, reg2, OS_8);
  1015. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, reg2));
  1016. setsubreg(reg2,R_SUBH);
  1017. list.concat(taicpu.op_const_reg(A_MOV, S_B, 0, reg2));
  1018. end;
  1019. OS_S8:
  1020. begin
  1021. getcpuregister(list, NR_AX);
  1022. add_mov(taicpu.op_reg_reg(A_MOV, S_B, reg1, NR_AL));
  1023. getcpuregister(list, NR_DX);
  1024. list.concat(taicpu.op_none(A_CBW));
  1025. list.concat(taicpu.op_none(A_CWD));
  1026. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1027. ungetcpuregister(list, NR_AX);
  1028. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1029. ungetcpuregister(list, NR_DX);
  1030. end;
  1031. OS_16:
  1032. begin
  1033. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1034. list.concat(taicpu.op_const_reg(A_MOV,S_W,0,GetNextReg(reg2)));
  1035. end;
  1036. OS_S16:
  1037. begin
  1038. getcpuregister(list, NR_AX);
  1039. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, NR_AX));
  1040. getcpuregister(list, NR_DX);
  1041. list.concat(taicpu.op_none(A_CWD));
  1042. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_AX, reg2));
  1043. ungetcpuregister(list, NR_AX);
  1044. add_mov(taicpu.op_reg_reg(A_MOV, S_W, NR_DX, GetNextReg(reg2)));
  1045. ungetcpuregister(list, NR_DX);
  1046. end;
  1047. OS_32,OS_S32:
  1048. begin
  1049. add_mov(taicpu.op_reg_reg(A_MOV, S_W, reg1, reg2));
  1050. add_mov(taicpu.op_reg_reg(A_MOV, S_W, GetNextReg(reg1), GetNextReg(reg2)));
  1051. end;
  1052. else
  1053. internalerror(2013030213);
  1054. end;
  1055. else
  1056. internalerror(2013030211);
  1057. end;
  1058. end;
  1059. end;
  1060. procedure tcg8086.g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister);
  1061. var
  1062. ai : taicpu;
  1063. hreg, hreg16 : tregister;
  1064. hl_skip: TAsmLabel;
  1065. invf: TResFlags;
  1066. begin
  1067. hreg:=makeregsize(list,reg,OS_8);
  1068. invf := f;
  1069. inverse_flags(invf);
  1070. list.concat(Taicpu.op_const_reg(A_MOV, S_B, 0, hreg));
  1071. current_asmdata.getjumplabel(hl_skip);
  1072. ai:=Taicpu.Op_Sym(A_Jcc,S_NO,hl_skip);
  1073. ai.SetCondition(flags_to_cond(invf));
  1074. ai.is_jmp:=true;
  1075. list.concat(ai);
  1076. { 16-bit INC is shorter than 8-bit }
  1077. hreg16:=makeregsize(list,hreg,OS_16);
  1078. list.concat(Taicpu.op_reg(A_INC, S_W, hreg16));
  1079. a_label(list,hl_skip);
  1080. if reg<>hreg then
  1081. a_load_reg_reg(list,OS_8,size,hreg,reg);
  1082. end;
  1083. procedure tcg8086.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref: TReference);
  1084. var
  1085. tmpreg : tregister;
  1086. begin
  1087. tmpreg:=getintregister(list,size);
  1088. g_flags2reg(list,size,f,tmpreg);
  1089. a_load_reg_ref(list,size,size,tmpreg,ref);
  1090. end;
  1091. procedure tcg8086.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
  1092. var
  1093. stacksize : longint;
  1094. begin
  1095. { MMX needs to call EMMS }
  1096. if assigned(rg[R_MMXREGISTER]) and
  1097. (rg[R_MMXREGISTER].uses_registers) then
  1098. list.concat(Taicpu.op_none(A_EMMS,S_NO));
  1099. { remove stackframe }
  1100. if not nostackframe then
  1101. begin
  1102. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1103. begin
  1104. stacksize:=current_procinfo.calc_stackframe_size;
  1105. if (target_info.stackalign>4) and
  1106. ((stacksize <> 0) or
  1107. (pi_do_call in current_procinfo.flags) or
  1108. { can't detect if a call in this case -> use nostackframe }
  1109. { if you (think you) know what you are doing }
  1110. (po_assembler in current_procinfo.procdef.procoptions)) then
  1111. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1112. if (stacksize<>0) then
  1113. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
  1114. end
  1115. else
  1116. begin
  1117. if current_settings.cputype < cpu_186 then
  1118. begin
  1119. list.concat(Taicpu.op_reg_reg(A_MOV, S_W, NR_BP, NR_SP));
  1120. list.concat(Taicpu.op_reg(A_POP, S_W, NR_BP));
  1121. end
  1122. else
  1123. list.concat(Taicpu.op_none(A_LEAVE,S_NO));
  1124. end;
  1125. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1126. end;
  1127. { return from proc }
  1128. if (po_interrupt in current_procinfo.procdef.procoptions) and
  1129. { this messes up stack alignment }
  1130. (target_info.stackalign=4) then
  1131. begin
  1132. if assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
  1133. (current_procinfo.procdef.funcretloc[calleeside].location^.loc=LOC_REGISTER) then
  1134. begin
  1135. if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.register)=RS_EAX) then
  1136. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1137. else
  1138. internalerror(2010053001);
  1139. end
  1140. else
  1141. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EAX));
  1142. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EBX));
  1143. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ECX));
  1144. if (current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64]) and
  1145. assigned(current_procinfo.procdef.funcretloc[calleeside].location) and
  1146. assigned(current_procinfo.procdef.funcretloc[calleeside].location^.next) and
  1147. (current_procinfo.procdef.funcretloc[calleeside].location^.next^.loc=LOC_REGISTER) then
  1148. begin
  1149. if (getsupreg(current_procinfo.procdef.funcretloc[calleeside].location^.next^.register)=RS_EDX) then
  1150. list.concat(Taicpu.Op_const_reg(A_ADD,S_L,4,NR_ESP))
  1151. else
  1152. internalerror(2010053002);
  1153. end
  1154. else
  1155. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDX));
  1156. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_ESI));
  1157. list.concat(Taicpu.Op_reg(A_POP,S_L,NR_EDI));
  1158. { .... also the segment registers }
  1159. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_DS));
  1160. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_ES));
  1161. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_FS));
  1162. list.concat(Taicpu.Op_reg(A_POP,S_W,NR_GS));
  1163. { this restores the flags }
  1164. list.concat(Taicpu.Op_none(A_IRET,S_NO));
  1165. end
  1166. { Routines with the poclearstack flag set use only a ret }
  1167. else if (current_procinfo.procdef.proccalloption in clearstack_pocalls) and
  1168. (not paramanager.use_fixed_stack) then
  1169. begin
  1170. { complex return values are removed from stack in C code PM }
  1171. { but not on win32 }
  1172. { and not for safecall with hidden exceptions, because the result }
  1173. { wich contains the exception is passed in EAX }
  1174. if (target_info.system <> system_i386_win32) and
  1175. not ((current_procinfo.procdef.proccalloption = pocall_safecall) and
  1176. (tf_safecall_exceptions in target_info.flags)) and
  1177. paramanager.ret_in_param(current_procinfo.procdef.returndef,
  1178. current_procinfo.procdef) then
  1179. list.concat(Taicpu.Op_const(A_RET,S_W,sizeof(aint)))
  1180. else
  1181. list.concat(Taicpu.Op_none(A_RET,S_NO));
  1182. end
  1183. { ... also routines with parasize=0 }
  1184. else if (parasize=0) then
  1185. list.concat(Taicpu.Op_none(A_RET,S_NO))
  1186. else
  1187. begin
  1188. { parameters are limited to 65535 bytes because ret allows only imm16 }
  1189. if (parasize>65535) then
  1190. CGMessage(cg_e_parasize_too_big);
  1191. list.concat(Taicpu.Op_const(A_RET,S_W,parasize));
  1192. end;
  1193. end;
  1194. procedure tcg8086.g_copyvaluepara_openarray(list : TAsmList;const ref:treference;const lenloc:tlocation;elesize:tcgint;destreg:tregister);
  1195. var
  1196. power,len : longint;
  1197. opsize : topsize;
  1198. {$ifndef __NOWINPECOFF__}
  1199. again,ok : tasmlabel;
  1200. {$endif}
  1201. begin
  1202. { get stack space }
  1203. getcpuregister(list,NR_DI);
  1204. a_load_loc_reg(list,OS_INT,lenloc,NR_DI);
  1205. list.concat(Taicpu.op_reg(A_INC,S_W,NR_DI));
  1206. { Now DI contains (high+1). Copy it to CX for later use. }
  1207. getcpuregister(list,NR_CX);
  1208. list.concat(Taicpu.op_reg_reg(A_MOV,S_W,NR_DI,NR_CX));
  1209. if (elesize<>1) then
  1210. begin
  1211. if ispowerof2(elesize, power) then
  1212. list.concat(Taicpu.op_const_reg(A_SHL,S_W,power,NR_DI))
  1213. else
  1214. list.concat(Taicpu.op_const_reg(A_IMUL,S_W,elesize,NR_DI));
  1215. end;
  1216. {$ifndef __NOWINPECOFF__}
  1217. { windows guards only a few pages for stack growing, }
  1218. { so we have to access every page first }
  1219. if target_info.system=system_i386_win32 then
  1220. begin
  1221. current_asmdata.getjumplabel(again);
  1222. current_asmdata.getjumplabel(ok);
  1223. a_label(list,again);
  1224. list.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,NR_EDI));
  1225. a_jmp_cond(list,OC_B,ok);
  1226. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,NR_ESP));
  1227. list.concat(Taicpu.op_reg(A_PUSH,S_L,NR_EDI));
  1228. list.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,NR_EDI));
  1229. a_jmp_always(list,again);
  1230. a_label(list,ok);
  1231. end;
  1232. {$endif __NOWINPECOFF__}
  1233. { If we were probing pages, EDI=(size mod pagesize) and ESP is decremented
  1234. by (size div pagesize)*pagesize, otherwise EDI=size.
  1235. Either way, subtracting EDI from ESP will set ESP to desired final value. }
  1236. list.concat(Taicpu.op_reg_reg(A_SUB,S_W,NR_DI,NR_SP));
  1237. { align stack on 2 bytes }
  1238. list.concat(Taicpu.op_const_reg(A_AND,S_W,aint($fffe),NR_SP));
  1239. { load destination, don't use a_load_reg_reg, that will add a move instruction
  1240. that can confuse the reg allocator }
  1241. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1242. {$ifdef volatile_es}
  1243. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DS));
  1244. list.concat(taicpu.op_reg(A_POP,S_W,NR_ES));
  1245. {$endif volatile_es}
  1246. { Allocate SI and load it with source }
  1247. getcpuregister(list,NR_SI);
  1248. a_loadaddr_ref_reg(list,ref,NR_SI);
  1249. { calculate size }
  1250. len:=elesize;
  1251. opsize:=S_B;
  1252. { if (len and 3)=0 then
  1253. begin
  1254. opsize:=S_L;
  1255. len:=len shr 2;
  1256. end
  1257. else}
  1258. if (len and 1)=0 then
  1259. begin
  1260. opsize:=S_W;
  1261. len:=len shr 1;
  1262. end;
  1263. if len>1 then
  1264. begin
  1265. if ispowerof2(len, power) then
  1266. list.concat(Taicpu.op_const_reg(A_SHL,S_W,power,NR_CX))
  1267. else
  1268. list.concat(Taicpu.op_const_reg(A_IMUL,S_W,len,NR_CX));
  1269. end;
  1270. list.concat(Taicpu.op_none(A_REP,S_NO));
  1271. case opsize of
  1272. S_B : list.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1273. S_W : list.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1274. // S_L : list.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1275. end;
  1276. ungetcpuregister(list,NR_DI);
  1277. ungetcpuregister(list,NR_CX);
  1278. ungetcpuregister(list,NR_SI);
  1279. { patch the new address, but don't use a_load_reg_reg, that will add a move instruction
  1280. that can confuse the reg allocator }
  1281. list.concat(Taicpu.Op_reg_reg(A_MOV,S_W,NR_SP,destreg));
  1282. end;
  1283. procedure tcg8086.g_releasevaluepara_openarray(list : TAsmList;const l:tlocation);
  1284. begin
  1285. { Nothing to release }
  1286. end;
  1287. procedure tcg8086.g_exception_reason_save(list : TAsmList; const href : treference);
  1288. begin
  1289. if not paramanager.use_fixed_stack then
  1290. list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1291. else
  1292. inherited g_exception_reason_save(list,href);
  1293. end;
  1294. procedure tcg8086.g_exception_reason_save_const(list : TAsmList;const href : treference; a: tcgint);
  1295. begin
  1296. if not paramanager.use_fixed_stack then
  1297. push_const(list,OS_INT,a)
  1298. else
  1299. inherited g_exception_reason_save_const(list,href,a);
  1300. end;
  1301. procedure tcg8086.g_exception_reason_load(list : TAsmList; const href : treference);
  1302. begin
  1303. if not paramanager.use_fixed_stack then
  1304. begin
  1305. cg.a_reg_alloc(list,NR_FUNCTION_RESULT_REG);
  1306. list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_INT],NR_FUNCTION_RESULT_REG))
  1307. end
  1308. else
  1309. inherited g_exception_reason_load(list,href);
  1310. end;
  1311. procedure tcg8086.get_32bit_ops(op: TOpCG; out op1, op2: TAsmOp);
  1312. begin
  1313. case op of
  1314. OP_ADD :
  1315. begin
  1316. op1:=A_ADD;
  1317. op2:=A_ADC;
  1318. end;
  1319. OP_SUB :
  1320. begin
  1321. op1:=A_SUB;
  1322. op2:=A_SBB;
  1323. end;
  1324. OP_XOR :
  1325. begin
  1326. op1:=A_XOR;
  1327. op2:=A_XOR;
  1328. end;
  1329. OP_OR :
  1330. begin
  1331. op1:=A_OR;
  1332. op2:=A_OR;
  1333. end;
  1334. OP_AND :
  1335. begin
  1336. op1:=A_AND;
  1337. op2:=A_AND;
  1338. end;
  1339. else
  1340. internalerror(200203241);
  1341. end;
  1342. end;
  1343. procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  1344. var
  1345. hsym : tsym;
  1346. href : treference;
  1347. paraloc : Pcgparalocation;
  1348. begin
  1349. { calculate the parameter info for the procdef }
  1350. procdef.init_paraloc_info(callerside);
  1351. hsym:=tsym(procdef.parast.Find('self'));
  1352. if not(assigned(hsym) and
  1353. (hsym.typ=paravarsym)) then
  1354. internalerror(200305251);
  1355. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1356. while paraloc<>nil do
  1357. with paraloc^ do
  1358. begin
  1359. case loc of
  1360. LOC_REGISTER:
  1361. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  1362. LOC_REFERENCE:
  1363. begin
  1364. { offset in the wrapper needs to be adjusted for the stored
  1365. return address }
  1366. if (reference.index<>NR_BP) and (reference.index<>NR_BX) and (reference.index<>NR_DI)
  1367. and (reference.index<>NR_SI) then
  1368. begin
  1369. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1370. list.concat(taicpu.op_reg_reg(A_MOV,S_W,reference.index,NR_DI));
  1371. if reference.index=NR_SP then
  1372. reference_reset_base(href,NR_DI,reference.offset+sizeof(pint)+2,sizeof(pint))
  1373. else
  1374. reference_reset_base(href,NR_DI,reference.offset+sizeof(pint),sizeof(pint));
  1375. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1376. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1377. end
  1378. else
  1379. begin
  1380. reference_reset_base(href,reference.index,reference.offset+sizeof(pint),sizeof(pint));
  1381. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  1382. end;
  1383. end
  1384. else
  1385. internalerror(200309189);
  1386. end;
  1387. paraloc:=next;
  1388. end;
  1389. end;
  1390. procedure tcg8086.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1391. {
  1392. possible calling conventions:
  1393. default stdcall cdecl pascal register
  1394. default(0): OK OK OK OK OK
  1395. virtual(1): OK OK OK OK OK(2)
  1396. (0):
  1397. set self parameter to correct value
  1398. jmp mangledname
  1399. (1): The wrapper code use %eax to reach the virtual method address
  1400. set self to correct value
  1401. move self,%bx
  1402. mov 0(%bx),%bx ; load vmt
  1403. jmp vmtoffs(%bx) ; method offs
  1404. (2): Virtual use values pushed on stack to reach the method address
  1405. so the following code be generated:
  1406. set self to correct value
  1407. push %bx ; allocate space for function address
  1408. push %bx
  1409. push %di
  1410. mov self,%bx
  1411. mov 0(%bx),%bx ; load vmt
  1412. mov vmtoffs(%bx),bx ; method offs
  1413. mov %sp,%di
  1414. mov %bx,4(%di)
  1415. pop %di
  1416. pop %bx
  1417. ret 0; jmp the address
  1418. }
  1419. procedure getselftobx(offs: longint);
  1420. var
  1421. href : treference;
  1422. selfoffsetfromsp : longint;
  1423. begin
  1424. { "mov offset(%sp),%bx" }
  1425. if (procdef.proccalloption<>pocall_register) then
  1426. begin
  1427. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1428. { framepointer is pushed for nested procs }
  1429. if procdef.parast.symtablelevel>normal_function_level then
  1430. selfoffsetfromsp:=2*sizeof(aint)
  1431. else
  1432. selfoffsetfromsp:=sizeof(aint);
  1433. list.concat(taicpu.op_reg_reg(A_mov,S_W,NR_SP,NR_DI));
  1434. reference_reset_base(href,NR_DI,selfoffsetfromsp+offs+2,2);
  1435. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1436. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1437. end
  1438. else
  1439. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_BX,NR_BX);
  1440. end;
  1441. procedure loadvmttobx;
  1442. var
  1443. href : treference;
  1444. begin
  1445. { mov 0(%bx),%bx ; load vmt}
  1446. reference_reset_base(href,NR_BX,0,2);
  1447. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1448. end;
  1449. procedure loadmethodoffstobx;
  1450. var
  1451. href : treference;
  1452. begin
  1453. if (procdef.extnumber=$ffff) then
  1454. Internalerror(200006139);
  1455. { mov vmtoffs(%bx),%bx ; method offs }
  1456. reference_reset_base(href,NR_BX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),2);
  1457. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_BX);
  1458. end;
  1459. var
  1460. lab : tasmsymbol;
  1461. make_global : boolean;
  1462. href : treference;
  1463. begin
  1464. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1465. Internalerror(200006137);
  1466. if not assigned(procdef.struct) or
  1467. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1468. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1469. Internalerror(200006138);
  1470. if procdef.owner.symtabletype<>ObjectSymtable then
  1471. Internalerror(200109191);
  1472. make_global:=false;
  1473. if (not current_module.is_unit) or
  1474. create_smartlink or
  1475. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1476. make_global:=true;
  1477. if make_global then
  1478. List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1479. else
  1480. List.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1481. { set param1 interface to self }
  1482. g_adjust_self_value(list,procdef,ioffset);
  1483. if (po_virtualmethod in procdef.procoptions) and
  1484. not is_objectpascal_helper(procdef.struct) then
  1485. begin
  1486. { case 1 & case 2 }
  1487. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX)); { allocate space for address}
  1488. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_BX));
  1489. list.concat(taicpu.op_reg(A_PUSH,S_W,NR_DI));
  1490. getselftobx(8);
  1491. loadvmttobx;
  1492. loadmethodoffstobx;
  1493. { set target address
  1494. "mov %bx,4(%sp)" }
  1495. reference_reset_base(href,NR_DI,4,2);
  1496. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_SP,NR_DI));
  1497. list.concat(taicpu.op_reg_ref(A_MOV,S_W,NR_BX,href));
  1498. { load ax? }
  1499. if procdef.proccalloption=pocall_register then
  1500. list.concat(taicpu.op_reg_reg(A_MOV,S_W,NR_BX,NR_AX));
  1501. { restore register
  1502. pop %di,bx }
  1503. list.concat(taicpu.op_reg(A_POP,S_W,NR_DI));
  1504. list.concat(taicpu.op_reg(A_POP,S_W,NR_BX));
  1505. { ret ; jump to the address }
  1506. list.concat(taicpu.op_none(A_RET,S_W));
  1507. end
  1508. { case 0 }
  1509. else
  1510. begin
  1511. lab:=current_asmdata.RefAsmSymbol(procdef.mangledname);
  1512. list.concat(taicpu.op_sym(A_JMP,S_NO,lab))
  1513. end;
  1514. List.concat(Tai_symbol_end.Createname(labelname));
  1515. end;
  1516. { ************* 64bit operations ************ }
  1517. procedure tcg64f8086.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp);
  1518. begin
  1519. case op of
  1520. OP_ADD :
  1521. begin
  1522. op1:=A_ADD;
  1523. op2:=A_ADC;
  1524. end;
  1525. OP_SUB :
  1526. begin
  1527. op1:=A_SUB;
  1528. op2:=A_SBB;
  1529. end;
  1530. OP_XOR :
  1531. begin
  1532. op1:=A_XOR;
  1533. op2:=A_XOR;
  1534. end;
  1535. OP_OR :
  1536. begin
  1537. op1:=A_OR;
  1538. op2:=A_OR;
  1539. end;
  1540. OP_AND :
  1541. begin
  1542. op1:=A_AND;
  1543. op2:=A_AND;
  1544. end;
  1545. else
  1546. internalerror(200203241);
  1547. end;
  1548. end;
  1549. (* procedure tcg64f8086.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);
  1550. var
  1551. op1,op2 : TAsmOp;
  1552. tempref : treference;
  1553. begin
  1554. if not(op in [OP_NEG,OP_NOT]) then
  1555. begin
  1556. get_64bit_ops(op,op1,op2);
  1557. tempref:=ref;
  1558. tcgx86(cg).make_simple_ref(list,tempref);
  1559. list.concat(taicpu.op_ref_reg(op1,S_L,tempref,reg.reglo));
  1560. inc(tempref.offset,4);
  1561. list.concat(taicpu.op_ref_reg(op2,S_L,tempref,reg.reghi));
  1562. end
  1563. else
  1564. begin
  1565. a_load64_ref_reg(list,ref,reg);
  1566. a_op64_reg_reg(list,op,size,reg,reg);
  1567. end;
  1568. end;*)
  1569. procedure tcg64f8086.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1570. var
  1571. op1,op2 : TAsmOp;
  1572. begin
  1573. case op of
  1574. OP_NEG :
  1575. begin
  1576. if (regsrc.reglo<>regdst.reglo) then
  1577. a_load64_reg_reg(list,regsrc,regdst);
  1578. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1579. cg.a_op_reg_reg(list,OP_NEG,OS_32,regdst.reglo,regdst.reglo);
  1580. { there's no OP_SBB, so do it directly }
  1581. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,regdst.reghi));
  1582. list.concat(taicpu.op_const_reg(A_SBB,S_W,-1,GetNextReg(regdst.reghi)));
  1583. exit;
  1584. end;
  1585. OP_NOT :
  1586. begin
  1587. if (regsrc.reglo<>regdst.reglo) then
  1588. a_load64_reg_reg(list,regsrc,regdst);
  1589. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reglo,regdst.reglo);
  1590. cg.a_op_reg_reg(list,OP_NOT,OS_32,regdst.reghi,regdst.reghi);
  1591. exit;
  1592. end;
  1593. end;
  1594. get_64bit_ops(op,op1,op2);
  1595. list.concat(taicpu.op_reg_reg(op1,S_W,regsrc.reglo,regdst.reglo));
  1596. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reglo),GetNextReg(regdst.reglo)));
  1597. list.concat(taicpu.op_reg_reg(op2,S_W,regsrc.reghi,regdst.reghi));
  1598. list.concat(taicpu.op_reg_reg(op2,S_W,GetNextReg(regsrc.reghi),GetNextReg(regdst.reghi)));
  1599. end;
  1600. procedure tcg64f8086.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1601. var
  1602. op1,op2 : TAsmOp;
  1603. begin
  1604. case op of
  1605. OP_AND,OP_OR,OP_XOR:
  1606. begin
  1607. cg.a_op_const_reg(list,op,OS_32,tcgint(lo(value)),reg.reglo);
  1608. cg.a_op_const_reg(list,op,OS_32,tcgint(hi(value)),reg.reghi);
  1609. end;
  1610. OP_ADD, OP_SUB:
  1611. begin
  1612. // can't use a_op_const_ref because this may use dec/inc
  1613. get_64bit_ops(op,op1,op2);
  1614. list.concat(taicpu.op_const_reg(op1,S_W,aint(value and $ffff),reg.reglo));
  1615. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 16) and $ffff),GetNextReg(reg.reglo)));
  1616. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 32) and $ffff),reg.reghi));
  1617. list.concat(taicpu.op_const_reg(op2,S_W,aint((value shr 48) and $ffff),GetNextReg(reg.reghi)));
  1618. end;
  1619. else
  1620. internalerror(200204021);
  1621. end;
  1622. end;
  1623. (* procedure tcg64f8086.a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);
  1624. var
  1625. op1,op2 : TAsmOp;
  1626. tempref : treference;
  1627. begin
  1628. tempref:=ref;
  1629. tcgx86(cg).make_simple_ref(list,tempref);
  1630. case op of
  1631. OP_AND,OP_OR,OP_XOR:
  1632. begin
  1633. cg.a_op_const_ref(list,op,OS_32,tcgint(lo(value)),tempref);
  1634. inc(tempref.offset,4);
  1635. cg.a_op_const_ref(list,op,OS_32,tcgint(hi(value)),tempref);
  1636. end;
  1637. OP_ADD, OP_SUB:
  1638. begin
  1639. get_64bit_ops(op,op1,op2);
  1640. // can't use a_op_const_ref because this may use dec/inc
  1641. list.concat(taicpu.op_const_ref(op1,S_L,aint(lo(value)),tempref));
  1642. inc(tempref.offset,4);
  1643. list.concat(taicpu.op_const_ref(op2,S_L,aint(hi(value)),tempref));
  1644. end;
  1645. else
  1646. internalerror(200204022);
  1647. end;
  1648. end;*)
  1649. procedure create_codegen;
  1650. begin
  1651. cg := tcg8086.create;
  1652. cg64 := tcg64f8086.create;
  1653. end;
  1654. end.