cgcpu.pas 58 KB

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