n386inl.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 inline nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit n386inl;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,ninl;
  23. type
  24. ti386inlinenode = class(tinlinenode)
  25. procedure pass_2;override;
  26. end;
  27. implementation
  28. uses
  29. globtype,systems,
  30. cutils,verbose,globals,fmodule,
  31. symconst,symdef,defbase,
  32. aasmbase,aasmtai,aasmcpu,
  33. cginfo,cgbase,pass_1,pass_2,
  34. cpubase,paramgr,
  35. nbas,ncon,ncal,ncnv,nld,
  36. cga,tgobj,ncgutil,cgobj,cg64f32,rgobj,rgcpu;
  37. {*****************************************************************************
  38. TI386INLINENODE
  39. *****************************************************************************}
  40. procedure ti386inlinenode.pass_2;
  41. const
  42. {tfloattype = (s32real,s64real,s80real,s64bit,f16bit,f32bit);}
  43. { float_name: array[tfloattype] of string[8]=
  44. ('S32REAL','S64REAL','S80REAL','S64BIT','F16BIT','F32BIT'); }
  45. addsubop:array[in_inc_x..in_dec_x] of TOpCG=(OP_ADD,OP_SUB);
  46. var
  47. asmop : tasmop;
  48. {inc/dec}
  49. addconstant : boolean;
  50. addvalue : longint;
  51. href : treference;
  52. hp2 : tstringconstnode;
  53. l : longint;
  54. pushedregs : tmaybesave;
  55. hregisterhi,
  56. hregister : tregister;
  57. lengthlab,
  58. otlabel,oflabel{,l1} : tasmlabel;
  59. oldpushedparasize : longint;
  60. cgop : TOpCG;
  61. cgsize : TCGSize;
  62. begin
  63. { save & reset pushedparasize }
  64. oldpushedparasize:=pushedparasize;
  65. pushedparasize:=0;
  66. case inlinenumber of
  67. in_assert_x_y:
  68. begin
  69. { the node should be removed in the firstpass }
  70. if not (cs_do_assertion in aktlocalswitches) then
  71. internalerror(7123458);
  72. otlabel:=truelabel;
  73. oflabel:=falselabel;
  74. getlabel(truelabel);
  75. getlabel(falselabel);
  76. secondpass(tcallparanode(left).left);
  77. maketojumpbool(exprasmlist,tcallparanode(left).left,lr_load_regvars);
  78. cg.a_label(exprasmlist,falselabel);
  79. { erroraddr }
  80. cg.a_param_reg(exprasmlist,OS_ADDR,R_EBP,paramanager.getintparaloc(4));
  81. { lineno }
  82. cg.a_param_const(exprasmlist,OS_INT,aktfilepos.line,paramanager.getintparaloc(3));
  83. { filename string }
  84. hp2:=cstringconstnode.createstr(current_module.sourcefiles.get_file_name(aktfilepos.fileindex),st_shortstring);
  85. firstpass(hp2);
  86. secondpass(hp2);
  87. if codegenerror then
  88. exit;
  89. cg.a_paramaddr_ref(exprasmlist,hp2.location.reference,paramanager.getintparaloc(2));
  90. hp2.free;
  91. { push msg }
  92. secondpass(tcallparanode(tcallparanode(left).right).left);
  93. cg.a_paramaddr_ref(exprasmlist,tcallparanode(tcallparanode(left).right).left.location.reference,paramanager.getintparaloc(1));
  94. { call }
  95. cg.a_call_name(exprasmlist,'FPC_ASSERT');
  96. cg.a_label(exprasmlist,truelabel);
  97. truelabel:=otlabel;
  98. falselabel:=oflabel;
  99. end;
  100. in_sizeof_x,
  101. in_typeof_x :
  102. begin
  103. location_reset(location,LOC_REGISTER,OS_ADDR);
  104. { for both cases load vmt }
  105. if left.nodetype=typen then
  106. begin
  107. hregister:=rg.getaddressregister(exprasmlist);
  108. reference_reset_symbol(href,newasmsymbol(tobjectdef(left.resulttype.def).vmt_mangledname),0);
  109. cg.a_loadaddr_ref_reg(exprasmlist,href,hregister);
  110. end
  111. else
  112. begin
  113. secondpass(left);
  114. location_release(exprasmlist,left.location);
  115. hregister:=rg.getaddressregister(exprasmlist);
  116. { load VMT pointer }
  117. inc(left.location.reference.offset,tobjectdef(left.resulttype.def).vmt_offset);
  118. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,hregister);
  119. end;
  120. { in sizeof load size }
  121. if inlinenumber=in_sizeof_x then
  122. begin
  123. reference_reset_base(href,hregister,0);
  124. rg.ungetaddressregister(exprasmlist,hregister);
  125. hregister:=rg.getregisterint(exprasmlist);
  126. cg.a_load_ref_reg(exprasmlist,OS_INT,href,hregister);
  127. end;
  128. location.register:=hregister;
  129. end;
  130. in_length_x :
  131. begin
  132. secondpass(left);
  133. { length in ansi strings is at offset -8 }
  134. if is_ansistring(left.resulttype.def) or
  135. is_widestring(left.resulttype.def) then
  136. begin
  137. location_force_reg(exprasmlist,left.location,OS_ADDR,false);
  138. hregister:=left.location.register;
  139. getlabel(lengthlab);
  140. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,hregister,lengthlab);
  141. reference_reset_base(href,hregister,-8);
  142. cg.a_load_ref_reg(exprasmlist,OS_INT,href,hregister);
  143. cg.a_label(exprasmlist,lengthlab);
  144. location_reset(location,LOC_REGISTER,OS_INT);
  145. location.register:=hregister;
  146. end
  147. else
  148. begin
  149. location_copy(location,left.location);
  150. location.size:=OS_8;
  151. end;
  152. end;
  153. in_pred_x,
  154. in_succ_x:
  155. begin
  156. secondpass(left);
  157. if inlinenumber=in_pred_x then
  158. cgop:=OP_SUB
  159. else
  160. cgop:=OP_ADD;
  161. cgsize:=def_cgsize(resulttype.def);
  162. { we need a value in a register }
  163. location_copy(location,left.location);
  164. location_force_reg(exprasmlist,location,cgsize,false);
  165. if cgsize in [OS_64,OS_S64] then
  166. cg64.a_op64_const_reg(exprasmlist,cgop,1,
  167. location.register64)
  168. else
  169. cg.a_op_const_reg(exprasmlist,cgop,1,location.register);
  170. cg.g_overflowcheck(exprasmlist,self);
  171. cg.g_rangecheck(exprasmlist,self,resulttype.def);
  172. end;
  173. in_dec_x,
  174. in_inc_x :
  175. begin
  176. { set defaults }
  177. addconstant:=true;
  178. { load first parameter, must be a reference }
  179. secondpass(tcallparanode(left).left);
  180. cgsize:=def_cgsize(tcallparanode(left).left.resulttype.def);
  181. { get addvalue }
  182. case tcallparanode(left).left.resulttype.def.deftype of
  183. orddef,
  184. enumdef :
  185. addvalue:=1;
  186. pointerdef :
  187. begin
  188. if is_void(tpointerdef(tcallparanode(left).left.resulttype.def).pointertype.def) then
  189. addvalue:=1
  190. else
  191. addvalue:=tpointerdef(tcallparanode(left).left.resulttype.def).pointertype.def.size;
  192. end;
  193. else
  194. internalerror(10081);
  195. end;
  196. { second argument specified?, must be a s32bit in register }
  197. if assigned(tcallparanode(left).right) then
  198. begin
  199. maybe_save(exprasmlist,tcallparanode(tcallparanode(left).right).left.registers32,
  200. tcallparanode(left).left.location,pushedregs);
  201. secondpass(tcallparanode(tcallparanode(left).right).left);
  202. maybe_restore(exprasmlist,tcallparanode(left).left.location,pushedregs);
  203. { when constant, just multiply the addvalue }
  204. if is_constintnode(tcallparanode(tcallparanode(left).right).left) then
  205. addvalue:=addvalue*get_ordinal_value(tcallparanode(tcallparanode(left).right).left)
  206. else
  207. begin
  208. location_force_reg(exprasmlist,tcallparanode(tcallparanode(left).right).left.location,cgsize,false);
  209. hregister:=tcallparanode(tcallparanode(left).right).left.location.register;
  210. hregisterhi:=tcallparanode(tcallparanode(left).right).left.location.registerhigh;
  211. { insert multiply with addvalue if its >1 }
  212. if addvalue>1 then
  213. cg.a_op_const_reg(exprasmlist,OP_IMUL,addvalue,hregister);
  214. addconstant:=false;
  215. end;
  216. end;
  217. { write the add instruction }
  218. if addconstant then
  219. begin
  220. if cgsize in [OS_64,OS_S64] then
  221. cg64.a_op64_const_loc(exprasmlist,addsubop[inlinenumber],
  222. addvalue,tcallparanode(left).left.location)
  223. else
  224. cg.a_op_const_loc(exprasmlist,addsubop[inlinenumber],
  225. addvalue,tcallparanode(left).left.location);
  226. end
  227. else
  228. begin
  229. if cgsize in [OS_64,OS_S64] then
  230. cg64.a_op64_reg_loc(exprasmlist,addsubop[inlinenumber],
  231. joinreg64(hregister,hregisterhi),tcallparanode(left).left.location)
  232. else
  233. cg.a_op_reg_loc(exprasmlist,addsubop[inlinenumber],
  234. hregister,tcallparanode(left).left.location);
  235. location_release(exprasmlist,tcallparanode(tcallparanode(left).right).left.location);
  236. end;
  237. cg.g_overflowcheck(exprasmlist,tcallparanode(left).left);
  238. cg.g_rangecheck(exprasmlist,tcallparanode(left).left,tcallparanode(left).left.resulttype.def);
  239. end;
  240. in_typeinfo_x:
  241. begin
  242. location_reset(location,LOC_REGISTER,OS_ADDR);
  243. location.register:=rg.getregisterint(exprasmlist);
  244. reference_reset_symbol(href,tstoreddef(ttypenode(tcallparanode(left).left).resulttype.def).get_rtti_label(fullrtti),0);
  245. emit_ref_reg(A_LEA,S_L,href,location.register);
  246. end;
  247. in_assigned_x :
  248. begin
  249. secondpass(tcallparanode(left).left);
  250. location_release(exprasmlist,tcallparanode(left).left.location);
  251. if (tcallparanode(left).left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  252. begin
  253. emit_reg_reg(A_OR,S_L,
  254. tcallparanode(left).left.location.register,
  255. tcallparanode(left).left.location.register);
  256. end
  257. else
  258. begin
  259. emit_const_ref(A_CMP,S_L,0,tcallparanode(left).left.location.reference);
  260. end;
  261. location_reset(location,LOC_FLAGS,OS_NO);
  262. location.resflags:=F_NE;
  263. end;
  264. in_include_x_y,
  265. in_exclude_x_y:
  266. begin
  267. location_copy(location,left.location);
  268. secondpass(tcallparanode(left).left);
  269. if tcallparanode(tcallparanode(left).right).left.nodetype=ordconstn then
  270. begin
  271. { calculate bit position }
  272. l:=1 shl (tordconstnode(tcallparanode(tcallparanode(left).right).left).value mod 32);
  273. { determine operator }
  274. if inlinenumber=in_include_x_y then
  275. asmop:=A_OR
  276. else
  277. begin
  278. asmop:=A_AND;
  279. l:=not(l);
  280. end;
  281. if (tcallparanode(left).left.location.loc=LOC_REFERENCE) then
  282. begin
  283. inc(tcallparanode(left).left.location.reference.offset,
  284. (tordconstnode(tcallparanode(tcallparanode(left).right).left).value div 32)*4);
  285. emit_const_ref(asmop,S_L,l,tcallparanode(left).left.location.reference);
  286. location_release(exprasmlist,tcallparanode(left).left.location);
  287. end
  288. else
  289. { LOC_CREGISTER }
  290. begin
  291. secondpass(tcallparanode(left).left);
  292. emit_const_reg(asmop,S_L,
  293. l,tcallparanode(left).left.location.register);
  294. end;
  295. end
  296. else
  297. begin
  298. { generate code for the element to set }
  299. maybe_save(exprasmlist,tcallparanode(tcallparanode(left).right).left.registers32,
  300. tcallparanode(left).left.location,pushedregs);
  301. secondpass(tcallparanode(tcallparanode(left).right).left);
  302. maybe_restore(exprasmlist,tcallparanode(left).left.location,pushedregs);
  303. { determine asm operator }
  304. if inlinenumber=in_include_x_y then
  305. asmop:=A_BTS
  306. else
  307. asmop:=A_BTR;
  308. if tcallparanode(tcallparanode(left).right).left.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  309. { we don't need a mod 32 because this is done automatically }
  310. { by the bts instruction. For proper checking we would }
  311. { note: bts doesn't do any mod'ing, that's why we can also use }
  312. { it for normalsets! (JM) }
  313. { need a cmp and jmp, but this should be done by the }
  314. { type cast code which does range checking if necessary (FK) }
  315. begin
  316. hregister := rg.makeregsize(tcallparanode(tcallparanode(left).right).left.location.register,OS_INT);
  317. end
  318. else
  319. begin
  320. rg.getexplicitregisterint(exprasmlist,R_EDI);
  321. hregister:=R_EDI;
  322. end;
  323. cg.a_load_loc_reg(exprasmlist,tcallparanode(tcallparanode(left).right).left.location,hregister);
  324. if (tcallparanode(left).left.location.loc=LOC_REFERENCE) then
  325. emit_reg_ref(asmop,S_L,hregister,tcallparanode(left).left.location.reference)
  326. else
  327. emit_reg_reg(asmop,S_L,hregister,tcallparanode(left).left.location.register);
  328. if hregister = R_EDI then
  329. rg.ungetregisterint(exprasmlist,R_EDI);
  330. end;
  331. end;
  332. in_pi:
  333. begin
  334. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  335. emit_none(A_FLDPI,S_NO);
  336. inc(trgcpu(rg).fpuvaroffset);
  337. location.register:=R_ST;
  338. end;
  339. in_sin_extended,
  340. in_arctan_extended,
  341. in_abs_extended,
  342. in_sqr_extended,
  343. in_sqrt_extended,
  344. in_ln_extended,
  345. in_cos_extended:
  346. begin
  347. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  348. location.register:=R_ST;
  349. secondpass(left);
  350. case left.location.loc of
  351. LOC_FPUREGISTER:
  352. ;
  353. LOC_CFPUREGISTER:
  354. begin
  355. cg.a_loadfpu_reg_reg(exprasmlist,
  356. left.location.register,location.register);
  357. end;
  358. LOC_REFERENCE,LOC_CREFERENCE:
  359. begin
  360. cg.a_loadfpu_ref_reg(exprasmlist,
  361. def_cgsize(left.resulttype.def),
  362. left.location.reference,location.register);
  363. location_release(exprasmlist,left.location);
  364. end
  365. else
  366. internalerror(309991);
  367. end;
  368. case inlinenumber of
  369. in_sin_extended,
  370. in_cos_extended:
  371. begin
  372. if inlinenumber=in_sin_extended then
  373. emit_none(A_FSIN,S_NO)
  374. else
  375. emit_none(A_FCOS,S_NO);
  376. {
  377. getlabel(l1);
  378. emit_reg(A_FNSTSW,S_NO,R_AX);
  379. emit_none(A_SAHF,S_NO);
  380. emitjmp(C_NP,l1);
  381. emit_reg(A_FSTP,S_NO,R_ST0);
  382. emit_none(A_FLDZ,S_NO);
  383. cg.a_label(exprasmlist,l1);
  384. }
  385. end;
  386. in_arctan_extended:
  387. begin
  388. emit_none(A_FLD1,S_NO);
  389. emit_none(A_FPATAN,S_NO);
  390. end;
  391. in_abs_extended:
  392. emit_none(A_FABS,S_NO);
  393. in_sqr_extended:
  394. begin
  395. (* emit_reg(A_FLD,S_NO,R_ST0);
  396. { emit_none(A_FMULP,S_NO); nasm does not accept this PM }
  397. emit_reg_reg(A_FMULP,S_NO,R_ST0,R_ST1);
  398. can be shorten to *)
  399. emit_reg_reg(A_FMUL,S_NO,R_ST0,R_ST0);
  400. end;
  401. in_sqrt_extended:
  402. emit_none(A_FSQRT,S_NO);
  403. in_ln_extended:
  404. begin
  405. emit_none(A_FLDLN2,S_NO);
  406. emit_none(A_FXCH,S_NO);
  407. emit_none(A_FYL2X,S_NO);
  408. end;
  409. end;
  410. end;
  411. {$ifdef SUPPORT_MMX}
  412. in_mmx_pcmpeqb..in_mmx_pcmpgtw:
  413. begin
  414. location_reset(location,LOC_MMXREGISTER,OS_NO);
  415. if left.location.loc=LOC_REGISTER then
  416. begin
  417. {!!!!!!!}
  418. end
  419. else if tcallparanode(left).left.location.loc=LOC_REGISTER then
  420. begin
  421. {!!!!!!!}
  422. end
  423. else
  424. begin
  425. {!!!!!!!}
  426. end;
  427. end;
  428. {$endif SUPPORT_MMX}
  429. else internalerror(9);
  430. end;
  431. { reset pushedparasize }
  432. pushedparasize:=oldpushedparasize;
  433. end;
  434. begin
  435. cinlinenode:=ti386inlinenode;
  436. end.
  437. {
  438. $Log$
  439. Revision 1.49 2002-07-20 11:58:02 florian
  440. * types.pas renamed to defbase.pas because D6 contains a types
  441. unit so this would conflicts if D6 programms are compiled
  442. + Willamette/SSE2 instructions to assembler added
  443. Revision 1.48 2002/07/11 14:41:33 florian
  444. * start of the new generic parameter handling
  445. Revision 1.47 2002/07/07 09:52:34 florian
  446. * powerpc target fixed, very simple units can be compiled
  447. * some basic stuff for better callparanode handling, far from being finished
  448. Revision 1.46 2002/07/01 18:46:33 peter
  449. * internal linker
  450. * reorganized aasm layer
  451. Revision 1.45 2002/07/01 16:23:56 peter
  452. * cg64 patch
  453. * basics for currency
  454. * asnode updates for class and interface (not finished)
  455. Revision 1.44 2002/05/18 13:34:25 peter
  456. * readded missing revisions
  457. Revision 1.43 2002/05/16 19:46:51 carl
  458. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  459. + try to fix temp allocation (still in ifdef)
  460. + generic constructor calls
  461. + start of tassembler / tmodulebase class cleanup
  462. Revision 1.41 2002/05/13 19:54:38 peter
  463. * removed n386ld and n386util units
  464. * maybe_save/maybe_restore added instead of the old maybe_push
  465. Revision 1.40 2002/05/12 16:53:17 peter
  466. * moved entry and exitcode to ncgutil and cgobj
  467. * foreach gets extra argument for passing local data to the
  468. iterator function
  469. * -CR checks also class typecasts at runtime by changing them
  470. into as
  471. * fixed compiler to cycle with the -CR option
  472. * fixed stabs with elf writer, finally the global variables can
  473. be watched
  474. * removed a lot of routines from cga unit and replaced them by
  475. calls to cgobj
  476. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  477. u32bit then the other is typecasted also to u32bit without giving
  478. a rangecheck warning/error.
  479. * fixed pascal calling method with reversing also the high tree in
  480. the parast, detected by tcalcst3 test
  481. Revision 1.39 2002/04/23 19:16:35 peter
  482. * add pinline unit that inserts compiler supported functions using
  483. one or more statements
  484. * moved finalize and setlength from ninl to pinline
  485. Revision 1.38 2002/04/21 15:35:54 carl
  486. * changeregsize -> rg.makeregsize
  487. Revision 1.37 2002/04/19 15:39:35 peter
  488. * removed some more routines from cga
  489. * moved location_force_reg/mem to ncgutil
  490. * moved arrayconstructnode secondpass to ncgld
  491. Revision 1.36 2002/04/15 19:44:21 peter
  492. * fixed stackcheck that would be called recursively when a stack
  493. error was found
  494. * generic changeregsize(reg,size) for i386 register resizing
  495. * removed some more routines from cga unit
  496. * fixed returnvalue handling
  497. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  498. Revision 1.35 2002/04/04 19:06:11 peter
  499. * removed unused units
  500. * use tlocation.size in cg.a_*loc*() routines
  501. Revision 1.34 2002/04/02 17:11:36 peter
  502. * tlocation,treference update
  503. * LOC_CONSTANT added for better constant handling
  504. * secondadd splitted in multiple routines
  505. * location_force_reg added for loading a location to a register
  506. of a specified size
  507. * secondassignment parses now first the right and then the left node
  508. (this is compatible with Kylix). This saves a lot of push/pop especially
  509. with string operations
  510. * adapted some routines to use the new cg methods
  511. Revision 1.33 2002/03/31 20:26:39 jonas
  512. + a_loadfpu_* and a_loadmm_* methods in tcg
  513. * register allocation is now handled by a class and is mostly processor
  514. independent (+rgobj.pas and i386/rgcpu.pas)
  515. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  516. * some small improvements and fixes to the optimizer
  517. * some register allocation fixes
  518. * some fpuvaroffset fixes in the unary minus node
  519. * push/popusedregisters is now called rg.save/restoreusedregisters and
  520. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  521. also better optimizable)
  522. * fixed and optimized register saving/restoring for new/dispose nodes
  523. * LOC_FPU locations now also require their "register" field to be set to
  524. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  525. - list field removed of the tnode class because it's not used currently
  526. and can cause hard-to-find bugs
  527. Revision 1.32 2002/03/04 19:10:14 peter
  528. * removed compiler warnings
  529. }