cgcpu.pas 59 KB

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