cgcpu.pas 60 KB

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