cgcpu.pas 70 KB

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