n386cnv.pas 20 KB

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