n386cnv.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 assembler for type converting 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 n386cnv;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,ncgcnv,defutil,defcmp,nx86cnv;
  23. type
  24. ti386typeconvnode = class(tx86typeconvnode)
  25. protected
  26. { procedure second_int_to_int;override; }
  27. { procedure second_string_to_string;override; }
  28. { procedure second_cstring_to_pchar;override; }
  29. { procedure second_string_to_chararray;override; }
  30. { procedure second_array_to_pointer;override; }
  31. { procedure second_pointer_to_array;override; }
  32. { procedure second_chararray_to_string;override; }
  33. { procedure second_char_to_string;override; }
  34. function first_int_to_real: tnode; override;
  35. procedure second_int_to_real;override;
  36. { procedure second_real_to_real;override; }
  37. { procedure second_cord_to_pointer;override; }
  38. { procedure second_proc_to_procvar;override; }
  39. { procedure second_bool_to_int;override; }
  40. { procedure second_int_to_bool;override; }
  41. { procedure second_load_smallset;override; }
  42. { procedure second_ansistring_to_pchar;override; }
  43. { procedure second_pchar_to_string;override; }
  44. { procedure second_class_to_intf;override; }
  45. { procedure second_char_to_char;override; }
  46. {$ifdef TESTOBJEXT2}
  47. procedure checkobject;override;
  48. {$endif TESTOBJEXT2}
  49. procedure second_call_helper(c : tconverttype);override;
  50. end;
  51. implementation
  52. uses
  53. verbose,systems,
  54. symconst,symdef,aasmbase,aasmtai,aasmcpu,
  55. cgbase,
  56. ncon,ncal,ncnv,
  57. cpubase,
  58. cgobj,cga,cgx86;
  59. function ti386typeconvnode.first_int_to_real : tnode;
  60. begin
  61. first_int_to_real:=nil;
  62. if registersfpu<1 then
  63. registersfpu:=1;
  64. expectloc:=LOC_FPUREGISTER;
  65. end;
  66. procedure ti386typeconvnode.second_int_to_real;
  67. var
  68. href : treference;
  69. hregister : tregister;
  70. l1,l2 : tasmlabel;
  71. freereg : boolean;
  72. begin
  73. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  74. hregister:=NR_NO;
  75. freereg:=false;
  76. { for u32bit a solution is to push $0 and to load a comp }
  77. { does this first, it destroys maybe EDI }
  78. if torddef(left.resulttype.def).typ=u32bit then
  79. exprasmlist.concat(taicpu.op_const(A_PUSH,S_L,0));
  80. case left.location.loc of
  81. LOC_REGISTER,
  82. LOC_CREGISTER :
  83. begin
  84. case left.location.size of
  85. OS_64,OS_S64 :
  86. begin
  87. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,left.location.registerhigh));
  88. hregister:=left.location.registerlow;
  89. end;
  90. OS_32,OS_S32 :
  91. hregister:=left.location.register;
  92. else
  93. begin
  94. hregister:=cg.getintregister(exprasmlist,OS_32);
  95. freereg:=true;
  96. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_32,left.location.register,hregister);
  97. end;
  98. end;
  99. end;
  100. LOC_REFERENCE,
  101. LOC_CREFERENCE :
  102. begin
  103. hregister:=cg.getintregister(exprasmlist,OS_INT);
  104. freereg:=true;
  105. if left.location.size in [OS_64,OS_S64] then
  106. begin
  107. href:=left.location.reference;
  108. inc(href.offset,4);
  109. cg.a_load_ref_reg(exprasmlist,OS_32,OS_32,href,hregister);
  110. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,hregister));
  111. cg.a_load_ref_reg(exprasmlist,OS_32,OS_32,left.location.reference,hregister);
  112. end
  113. else
  114. cg.a_load_ref_reg(exprasmlist,left.location.size,OS_INT,left.location.reference,hregister);
  115. end;
  116. else
  117. internalerror(2002032218);
  118. end;
  119. location_release(exprasmlist,left.location);
  120. location_freetemp(exprasmlist,left.location);
  121. { for 64 bit integers, the high dword is already pushed }
  122. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,hregister));
  123. if freereg then
  124. cg.ungetregister(exprasmlist,hregister);
  125. reference_reset_base(href,NR_ESP,0);
  126. case torddef(left.resulttype.def).typ of
  127. u32bit:
  128. begin
  129. emit_ref(A_FILD,S_IQ,href);
  130. emit_const_reg(A_ADD,S_L,8,NR_ESP);
  131. end;
  132. scurrency,
  133. s64bit:
  134. begin
  135. emit_ref(A_FILD,S_IQ,href);
  136. emit_const_reg(A_ADD,S_L,8,NR_ESP);
  137. end;
  138. u64bit:
  139. begin
  140. { unsigned 64 bit ints are harder to handle: }
  141. { we load bits 0..62 and then check bit 63: }
  142. { if it is 1 then we add $80000000 000000000 }
  143. { as double }
  144. inc(href.offset,4);
  145. hregister:=cg.getintregister(exprasmlist,OS_32);
  146. cg.a_load_ref_reg(exprasmlist,OS_INT,OS_INT,href,hregister);
  147. reference_reset_base(href,NR_ESP,4);
  148. emit_const_ref(A_AND,S_L,$7fffffff,href);
  149. emit_const_reg(A_TEST,S_L,longint($80000000),hregister);
  150. cg.ungetregister(exprasmlist,hregister);
  151. reference_reset_base(href,NR_ESP,0);
  152. emit_ref(A_FILD,S_IQ,href);
  153. objectlibrary.getdatalabel(l1);
  154. objectlibrary.getlabel(l2);
  155. cg.a_jmp_flags(exprasmlist,F_E,l2);
  156. Consts.concat(Tai_label.Create(l1));
  157. { I got this constant from a test progtram (FK) }
  158. Consts.concat(Tai_const.Create_32bit(0));
  159. Consts.concat(Tai_const.Create_32bit(1138753536));
  160. reference_reset_symbol(href,l1,0);
  161. emit_ref(A_FADD,S_FL,href);
  162. cg.a_label(exprasmlist,l2);
  163. emit_const_reg(A_ADD,S_L,8,NR_ESP);
  164. end
  165. else
  166. begin
  167. emit_ref(A_FILD,S_IL,href);
  168. hregister:=cg.getintregister(exprasmlist,OS_32);
  169. emit_reg(A_POP,S_L,hregister);
  170. cg.ungetregister(exprasmlist,hregister);
  171. end;
  172. end;
  173. tcgx86(cg).inc_fpu_stack;
  174. location.register:=NR_ST;
  175. end;
  176. {$ifdef TESTOBJEXT2}
  177. procedure ti386typeconvnode.checkobject;
  178. var
  179. r : preference;
  180. nillabel : plabel;
  181. begin
  182. new(r);
  183. reset_reference(r^);
  184. if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  185. r^.base:=p^.location.register
  186. else
  187. begin
  188. cg.getexplicitregister(exprasmlist,R_EDI);
  189. emit_mov_loc_reg(p^.location,R_EDI);
  190. r^.base:=R_EDI;
  191. end;
  192. { NIL must be accepted !! }
  193. emit_reg_reg(A_OR,S_L,r^.base,r^.base);
  194. rg.ungetregisterint(exprasmlist,R_EDI);
  195. objectlibrary.getlabel(nillabel);
  196. cg.a_jmp_flags(exprasmlist,F_E,nillabel);
  197. { this is one point where we need vmt_offset (PM) }
  198. r^.offset:= tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_offset;
  199. rg.getexplicitregisterint(exprasmlist,R_EDI);
  200. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  201. emit_sym(A_PUSH,S_L,
  202. objectlibrary.newasmsymbol(tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_mangledname));
  203. emit_reg(A_PUSH,S_L,R_EDI);
  204. rg.ungetregister32(exprasmlist,R_EDI);
  205. emitcall('FPC_CHECK_OBJECT_EXT');
  206. emitlab(nillabel);
  207. end;
  208. {$endif TESTOBJEXT2}
  209. procedure ti386typeconvnode.second_call_helper(c : tconverttype);
  210. {$ifdef fpc}
  211. const
  212. secondconvert : array[tconverttype] of pointer = (
  213. @second_nothing, {equal}
  214. @second_nothing, {not_possible}
  215. @second_nothing, {second_string_to_string, handled in resulttype pass }
  216. @second_char_to_string,
  217. @second_nothing, {char_to_charray}
  218. @second_nothing, { pchar_to_string, handled in resulttype pass }
  219. @second_nothing, {cchar_to_pchar}
  220. @second_cstring_to_pchar,
  221. @second_ansistring_to_pchar,
  222. @second_string_to_chararray,
  223. @second_nothing, { chararray_to_string, handled in resulttype pass }
  224. @second_array_to_pointer,
  225. @second_pointer_to_array,
  226. @second_int_to_int,
  227. @second_int_to_bool,
  228. @second_bool_to_bool,
  229. @second_bool_to_int,
  230. @second_real_to_real,
  231. @second_int_to_real,
  232. @second_nothing, { real_to_currency, handled in resulttype pass }
  233. @second_proc_to_procvar,
  234. @second_nothing, { arrayconstructor_to_set }
  235. @second_nothing, { second_load_smallset, handled in first pass }
  236. @second_cord_to_pointer,
  237. @second_nothing, { interface 2 string }
  238. @second_nothing, { interface 2 guid }
  239. @second_class_to_intf,
  240. @second_char_to_char,
  241. @second_nothing, { normal_2_smallset }
  242. @second_nothing, { dynarray_2_openarray }
  243. @second_nothing, { pwchar_2_string }
  244. @second_nothing, { variant_2_dynarray }
  245. @second_nothing { dynarray_2_variant}
  246. );
  247. type
  248. tprocedureofobject = procedure of object;
  249. var
  250. r : packed record
  251. proc : pointer;
  252. obj : pointer;
  253. end;
  254. begin
  255. { this is a little bit dirty but it works }
  256. { and should be quite portable too }
  257. r.proc:=secondconvert[c];
  258. r.obj:=self;
  259. tprocedureofobject(r)();
  260. end;
  261. {$else fpc}
  262. begin
  263. case c of
  264. tc_equal,
  265. tc_not_possible,
  266. tc_string_2_string : second_nothing;
  267. tc_char_2_string : second_char_to_string;
  268. tc_char_2_chararray : second_nothing;
  269. tc_pchar_2_string : second_nothing;
  270. tc_cchar_2_pchar : second_nothing;
  271. tc_cstring_2_pchar : second_cstring_to_pchar;
  272. tc_ansistring_2_pchar : second_ansistring_to_pchar;
  273. tc_string_2_chararray : second_string_to_chararray;
  274. tc_chararray_2_string : second_nothing;
  275. tc_array_2_pointer : second_array_to_pointer;
  276. tc_pointer_2_array : second_pointer_to_array;
  277. tc_int_2_int : second_int_to_int;
  278. tc_int_2_bool : second_int_to_bool;
  279. tc_bool_2_bool : second_bool_to_bool;
  280. tc_bool_2_int : second_bool_to_int;
  281. tc_real_2_real : second_real_to_real;
  282. tc_int_2_real : second_int_to_real;
  283. tc_real_2_currency : second_nothing;
  284. tc_proc_2_procvar : second_proc_to_procvar;
  285. tc_arrayconstructor_2_set : second_nothing;
  286. tc_load_smallset : second_nothing;
  287. tc_cord_2_pointer : second_cord_to_pointer;
  288. tc_intf_2_string : second_nothing;
  289. tc_intf_2_guid : second_nothing;
  290. tc_class_2_intf : second_class_to_intf;
  291. tc_char_2_char : second_char_to_char;
  292. tc_normal_2_smallset : second_nothing;
  293. tc_dynarray_2_openarray : second_nothing;
  294. tc_pwchar_2_string : second_nothing;
  295. tc_variant_2_dynarray : second_nothing;
  296. tc_dynarray_2_variant : second_nothing;
  297. else internalerror(2002101101);
  298. end;
  299. end;
  300. {$endif fpc}
  301. begin
  302. ctypeconvnode:=ti386typeconvnode;
  303. end.
  304. {
  305. $Log$
  306. Revision 1.67 2003-10-10 17:48:14 peter
  307. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  308. * tregisteralloctor renamed to trgobj
  309. * removed rgobj from a lot of units
  310. * moved location_* and reference_* to cgobj
  311. * first things for mmx register allocation
  312. Revision 1.66 2003/10/09 21:31:37 daniel
  313. * Register allocator splitted, ans abstract now
  314. Revision 1.65 2003/10/01 20:34:49 peter
  315. * procinfo unit contains tprocinfo
  316. * cginfo renamed to cgbase
  317. * moved cgmessage to verbose
  318. * fixed ppc and sparc compiles
  319. Revision 1.64 2003/09/28 21:48:20 peter
  320. * fix register leaks
  321. Revision 1.63 2003/09/03 15:55:01 peter
  322. * NEWRA branch merged
  323. Revision 1.62.2.2 2003/08/31 15:46:26 peter
  324. * more updates for tregister
  325. Revision 1.62.2.1 2003/08/31 13:58:46 daniel
  326. * Some more work to make things compile
  327. Revision 1.62 2003/06/03 21:11:09 peter
  328. * cg.a_load_* get a from and to size specifier
  329. * makeregsize only accepts newregister
  330. * i386 uses generic tcgnotnode,tcgunaryminus
  331. Revision 1.61 2003/04/30 20:53:32 florian
  332. * error when address of an abstract method is taken
  333. * fixed some x86-64 problems
  334. * merged some more x86-64 and i386 code
  335. Revision 1.60 2003/04/23 20:16:04 peter
  336. + added currency support based on int64
  337. + is_64bit for use in cg units instead of is_64bitint
  338. * removed cgmessage from n386add, replace with internalerrors
  339. Revision 1.59 2003/04/22 23:50:23 peter
  340. * firstpass uses expectloc
  341. * checks if there are differences between the expectloc and
  342. location.loc from secondpass in EXTDEBUG
  343. Revision 1.58 2003/04/22 10:09:35 daniel
  344. + Implemented the actual register allocator
  345. + Scratch registers unavailable when new register allocator used
  346. + maybe_save/maybe_restore unavailable when new register allocator used
  347. Revision 1.57 2003/03/13 19:52:23 jonas
  348. * and more new register allocator fixes (in the i386 code generator this
  349. time). At least now the ppc cross compiler can compile the linux
  350. system unit again, but I haven't tested it.
  351. Revision 1.56 2003/02/19 22:00:15 daniel
  352. * Code generator converted to new register notation
  353. - Horribily outdated todo.txt removed
  354. Revision 1.55 2003/01/13 18:37:44 daniel
  355. * Work on register conversion
  356. Revision 1.54 2003/01/08 18:43:57 daniel
  357. * Tregister changed into a record
  358. Revision 1.53 2002/12/05 14:27:42 florian
  359. * some variant <-> dyn. array stuff
  360. Revision 1.52 2002/11/25 17:43:26 peter
  361. * splitted defbase in defutil,symutil,defcmp
  362. * merged isconvertable and is_equal into compare_defs(_ext)
  363. * made operator search faster by walking the list only once
  364. Revision 1.51 2002/10/10 16:14:54 florian
  365. * fixed to reflect last tconvtype change
  366. Revision 1.50 2002/10/05 12:43:29 carl
  367. * fixes for Delphi 6 compilation
  368. (warning : Some features do not work under Delphi)
  369. Revision 1.49 2002/09/17 18:54:03 jonas
  370. * a_load_reg_reg() now has two size parameters: source and dest. This
  371. allows some optimizations on architectures that don't encode the
  372. register size in the register name.
  373. Revision 1.48 2002/08/14 19:19:14 carl
  374. * first_int_to_real moved to i386 (other one is generic)
  375. Revision 1.47 2002/08/11 14:32:30 peter
  376. * renamed current_library to objectlibrary
  377. Revision 1.46 2002/08/11 13:24:16 peter
  378. * saving of asmsymbols in ppu supported
  379. * asmsymbollist global is removed and moved into a new class
  380. tasmlibrarydata that will hold the info of a .a file which
  381. corresponds with a single module. Added librarydata to tmodule
  382. to keep the library info stored for the module. In the future the
  383. objectfiles will also be stored to the tasmlibrarydata class
  384. * all getlabel/newasmsymbol and friends are moved to the new class
  385. Revision 1.45 2002/07/27 19:53:51 jonas
  386. + generic implementation of tcg.g_flags2ref()
  387. * tcg.flags2xxx() now also needs a size parameter
  388. Revision 1.44 2002/07/20 11:58:01 florian
  389. * types.pas renamed to defbase.pas because D6 contains a types
  390. unit so this would conflicts if D6 programms are compiled
  391. + Willamette/SSE2 instructions to assembler added
  392. Revision 1.43 2002/07/01 18:46:31 peter
  393. * internal linker
  394. * reorganized aasm layer
  395. Revision 1.42 2002/05/20 13:30:40 carl
  396. * bugfix of hdisponen (base must be set, not index)
  397. * more portability fixes
  398. Revision 1.41 2002/05/18 13:34:24 peter
  399. * readded missing revisions
  400. Revision 1.40 2002/05/16 19:46:51 carl
  401. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  402. + try to fix temp allocation (still in ifdef)
  403. + generic constructor calls
  404. + start of tassembler / tmodulebase class cleanup
  405. Revision 1.38 2002/05/12 16:53:17 peter
  406. * moved entry and exitcode to ncgutil and cgobj
  407. * foreach gets extra argument for passing local data to the
  408. iterator function
  409. * -CR checks also class typecasts at runtime by changing them
  410. into as
  411. * fixed compiler to cycle with the -CR option
  412. * fixed stabs with elf writer, finally the global variables can
  413. be watched
  414. * removed a lot of routines from cga unit and replaced them by
  415. calls to cgobj
  416. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  417. u32bit then the other is typecasted also to u32bit without giving
  418. a rangecheck warning/error.
  419. * fixed pascal calling method with reversing also the high tree in
  420. the parast, detected by tcalcst3 test
  421. Revision 1.37 2002/04/21 19:02:07 peter
  422. * removed newn and disposen nodes, the code is now directly
  423. inlined from pexpr
  424. * -an option that will write the secondpass nodes to the .s file, this
  425. requires EXTDEBUG define to actually write the info
  426. * fixed various internal errors and crashes due recent code changes
  427. Revision 1.36 2002/04/21 15:35:23 carl
  428. * changeregsize -> rg.makeregsize
  429. Revision 1.35 2002/04/19 15:39:35 peter
  430. * removed some more routines from cga
  431. * moved location_force_reg/mem to ncgutil
  432. * moved arrayconstructnode secondpass to ncgld
  433. Revision 1.34 2002/04/15 19:44:21 peter
  434. * fixed stackcheck that would be called recursively when a stack
  435. error was found
  436. * generic changeregsize(reg,size) for i386 register resizing
  437. * removed some more routines from cga unit
  438. * fixed returnvalue handling
  439. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  440. Revision 1.33 2002/04/04 19:06:10 peter
  441. * removed unused units
  442. * use tlocation.size in cg.a_*loc*() routines
  443. Revision 1.32 2002/04/02 17:11:36 peter
  444. * tlocation,treference update
  445. * LOC_CONSTANT added for better constant handling
  446. * secondadd splitted in multiple routines
  447. * location_force_reg added for loading a location to a register
  448. of a specified size
  449. * secondassignment parses now first the right and then the left node
  450. (this is compatible with Kylix). This saves a lot of push/pop especially
  451. with string operations
  452. * adapted some routines to use the new cg methods
  453. Revision 1.31 2002/03/31 20:26:38 jonas
  454. + a_loadfpu_* and a_loadmm_* methods in tcg
  455. * register allocation is now handled by a class and is mostly processor
  456. independent (+rgobj.pas and i386/rgcpu.pas)
  457. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  458. * some small improvements and fixes to the optimizer
  459. * some register allocation fixes
  460. * some fpuvaroffset fixes in the unary minus node
  461. * push/popusedregisters is now called rg.save/restoreusedregisters and
  462. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  463. also better optimizable)
  464. * fixed and optimized register saving/restoring for new/dispose nodes
  465. * LOC_FPU locations now also require their "register" field to be set to
  466. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  467. - list field removed of the tnode class because it's not used currently
  468. and can cause hard-to-find bugs
  469. Revision 1.30 2002/03/04 19:10:13 peter
  470. * removed compiler warnings
  471. }