n386cnv.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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,defbase;
  23. type
  24. ti386typeconvnode = class(tcgtypeconvnode)
  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. procedure second_int_to_real;override;
  35. { procedure second_real_to_real;override; }
  36. { procedure second_cord_to_pointer;override; }
  37. { procedure second_proc_to_procvar;override; }
  38. { procedure second_bool_to_int;override; }
  39. procedure second_int_to_bool;override;
  40. { procedure second_load_smallset;override; }
  41. { procedure second_ansistring_to_pchar;override; }
  42. { procedure second_pchar_to_string;override; }
  43. { procedure second_class_to_intf;override; }
  44. { procedure second_char_to_char;override; }
  45. {$ifdef TESTOBJEXT2}
  46. procedure checkobject;override;
  47. {$endif TESTOBJEXT2}
  48. procedure second_call_helper(c : tconverttype);override;
  49. end;
  50. implementation
  51. uses
  52. verbose,systems,
  53. symconst,symdef,aasmbase,aasmtai,aasmcpu,
  54. cginfo,cgbase,pass_2,
  55. ncon,ncal,ncnv,
  56. cpubase,
  57. cgobj,cga,tgobj,rgobj,rgcpu,ncgutil;
  58. {*****************************************************************************
  59. SecondTypeConv
  60. *****************************************************************************}
  61. procedure ti386typeconvnode.second_int_to_real;
  62. var
  63. href : treference;
  64. hregister : tregister;
  65. l1,l2 : tasmlabel;
  66. freereg : boolean;
  67. begin
  68. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  69. hregister:=R_NO;
  70. freereg:=false;
  71. { for u32bit a solution is to push $0 and to load a comp }
  72. { does this first, it destroys maybe EDI }
  73. if torddef(left.resulttype.def).typ=u32bit then
  74. exprasmlist.concat(taicpu.op_const(A_PUSH,S_L,0));
  75. case left.location.loc of
  76. LOC_REGISTER,
  77. LOC_CREGISTER :
  78. begin
  79. case left.location.size of
  80. OS_64,OS_S64 :
  81. begin
  82. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,left.location.registerhigh));
  83. hregister:=left.location.registerlow;
  84. end;
  85. OS_32,OS_S32 :
  86. hregister:=left.location.register;
  87. else
  88. begin
  89. hregister:=cg.get_scratch_reg_int(exprasmlist);
  90. freereg:=true;
  91. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,hregister);
  92. end;
  93. end;
  94. end;
  95. LOC_REFERENCE,
  96. LOC_CREFERENCE :
  97. begin
  98. hregister:=cg.get_scratch_reg_int(exprasmlist);
  99. freereg:=true;
  100. if left.location.size in [OS_64,OS_S64] then
  101. begin
  102. href:=left.location.reference;
  103. inc(href.offset,4);
  104. cg.a_load_ref_reg(exprasmlist,OS_32,href,hregister);
  105. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,hregister));
  106. cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,hregister);
  107. end
  108. else
  109. cg.a_load_ref_reg(exprasmlist,left.location.size,left.location.reference,hregister);
  110. end;
  111. else
  112. internalerror(2002032218);
  113. end;
  114. location_release(exprasmlist,left.location);
  115. location_freetemp(exprasmlist,left.location);
  116. { for 64 bit integers, the high dword is already pushed }
  117. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,hregister));
  118. if freereg then
  119. cg.free_scratch_reg(exprasmlist,hregister);
  120. reference_reset_base(href,R_ESP,0);
  121. case torddef(left.resulttype.def).typ of
  122. u32bit:
  123. begin
  124. emit_ref(A_FILD,S_IQ,href);
  125. emit_const_reg(A_ADD,S_L,8,R_ESP);
  126. end;
  127. s64bit:
  128. begin
  129. emit_ref(A_FILD,S_IQ,href);
  130. emit_const_reg(A_ADD,S_L,8,R_ESP);
  131. end;
  132. u64bit:
  133. begin
  134. { unsigned 64 bit ints are harder to handle: }
  135. { we load bits 0..62 and then check bit 63: }
  136. { if it is 1 then we add $80000000 000000000 }
  137. { as double }
  138. inc(href.offset,4);
  139. rg.getexplicitregisterint(exprasmlist,R_EDI);
  140. emit_ref_reg(A_MOV,S_L,href,R_EDI);
  141. reference_reset_base(href,R_ESP,4);
  142. emit_const_ref(A_AND,S_L,$7fffffff,href);
  143. emit_const_reg(A_TEST,S_L,longint($80000000),R_EDI);
  144. rg.ungetregisterint(exprasmlist,R_EDI);
  145. reference_reset_base(href,R_ESP,0);
  146. emit_ref(A_FILD,S_IQ,href);
  147. objectlibrary.getdatalabel(l1);
  148. objectlibrary.getlabel(l2);
  149. emitjmp(C_Z,l2);
  150. Consts.concat(Tai_label.Create(l1));
  151. { I got this constant from a test progtram (FK) }
  152. Consts.concat(Tai_const.Create_32bit(0));
  153. Consts.concat(Tai_const.Create_32bit(1138753536));
  154. reference_reset_symbol(href,l1,0);
  155. emit_ref(A_FADD,S_FL,href);
  156. cg.a_label(exprasmlist,l2);
  157. emit_const_reg(A_ADD,S_L,8,R_ESP);
  158. end
  159. else
  160. begin
  161. emit_ref(A_FILD,S_IL,href);
  162. rg.getexplicitregisterint(exprasmlist,R_EDI);
  163. emit_reg(A_POP,S_L,R_EDI);
  164. rg.ungetregisterint(exprasmlist,R_EDI);
  165. end;
  166. end;
  167. inc(trgcpu(rg).fpuvaroffset);
  168. location.register:=R_ST;
  169. end;
  170. procedure ti386typeconvnode.second_int_to_bool;
  171. var
  172. hregister : tregister;
  173. pref : treference;
  174. resflags : tresflags;
  175. hlabel,oldtruelabel,oldfalselabel : tasmlabel;
  176. begin
  177. oldtruelabel:=truelabel;
  178. oldfalselabel:=falselabel;
  179. objectlibrary.getlabel(truelabel);
  180. objectlibrary.getlabel(falselabel);
  181. secondpass(left);
  182. if codegenerror then
  183. exit;
  184. { byte(boolean) or word(wordbool) or longint(longbool) must }
  185. { be accepted for var parameters }
  186. if (nf_explizit in flags) and
  187. (left.resulttype.def.size=resulttype.def.size) and
  188. (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
  189. begin
  190. location_copy(location,left.location);
  191. truelabel:=oldtruelabel;
  192. falselabel:=oldfalselabel;
  193. exit;
  194. end;
  195. { Load left node into flag F_NE/F_E }
  196. resflags:=F_NE;
  197. location_release(exprasmlist,left.location);
  198. case left.location.loc of
  199. LOC_CREFERENCE,
  200. LOC_REFERENCE :
  201. begin
  202. if left.location.size in [OS_64,OS_S64] then
  203. begin
  204. hregister:=rg.getregisterint(exprasmlist);
  205. emit_ref_reg(A_MOV,S_L,left.location.reference,hregister);
  206. pref:=left.location.reference;
  207. inc(pref.offset,4);
  208. emit_ref_reg(A_OR,S_L,pref,hregister);
  209. end
  210. else
  211. begin
  212. location_force_reg(exprasmlist,left.location,left.location.size,true);
  213. cg.a_op_reg_reg(exprasmlist,OP_OR,left.location.size,left.location.register,left.location.register);
  214. end;
  215. end;
  216. LOC_FLAGS :
  217. begin
  218. resflags:=left.location.resflags;
  219. end;
  220. LOC_REGISTER,LOC_CREGISTER :
  221. begin
  222. if left.location.size in [OS_64,OS_S64] then
  223. begin
  224. hregister:=cg.get_scratch_reg_int(exprasmlist);
  225. cg.a_load_reg_reg(exprasmlist,OS_32,left.location.registerlow,hregister);
  226. cg.a_op_reg_reg(exprasmlist,OP_OR,OS_32,left.location.registerhigh,hregister);
  227. cg.free_scratch_reg(exprasmlist,hregister);
  228. end
  229. else
  230. cg.a_op_reg_reg(exprasmlist,OP_OR,left.location.size,left.location.register,left.location.register);
  231. end;
  232. LOC_JUMP :
  233. begin
  234. hregister:=rg.getregisterint(exprasmlist);
  235. objectlibrary.getlabel(hlabel);
  236. cg.a_label(exprasmlist,truelabel);
  237. cg.a_load_const_reg(exprasmlist,OS_INT,1,hregister);
  238. cg.a_jmp_always(exprasmlist,hlabel);
  239. cg.a_label(exprasmlist,falselabel);
  240. cg.a_load_const_reg(exprasmlist,OS_INT,0,hregister);
  241. cg.a_label(exprasmlist,hlabel);
  242. cg.a_op_reg_reg(exprasmlist,OP_OR,OS_INT,hregister,hregister);
  243. end;
  244. else
  245. internalerror(10062);
  246. end;
  247. { load flags to register }
  248. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def));
  249. location.register:=def_getreg(resulttype.def);
  250. cg.g_flags2reg(exprasmlist,location.size,resflags,location.register);
  251. truelabel:=oldtruelabel;
  252. falselabel:=oldfalselabel;
  253. end;
  254. {$ifdef TESTOBJEXT2}
  255. procedure ti386typeconvnode.checkobject;
  256. var
  257. r : preference;
  258. nillabel : plabel;
  259. begin
  260. new(r);
  261. reset_reference(r^);
  262. if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  263. r^.base:=p^.location.register
  264. else
  265. begin
  266. rg.getexplicitregisterint(exprasmlist,R_EDI);
  267. emit_mov_loc_reg(p^.location,R_EDI);
  268. r^.base:=R_EDI;
  269. end;
  270. { NIL must be accepted !! }
  271. emit_reg_reg(A_OR,S_L,r^.base,r^.base);
  272. rg.ungetregisterint(exprasmlist,R_EDI);
  273. objectlibrary.getlabel(nillabel);
  274. emitjmp(C_E,nillabel);
  275. { this is one point where we need vmt_offset (PM) }
  276. r^.offset:= tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_offset;
  277. rg.getexplicitregisterint(exprasmlist,R_EDI);
  278. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  279. emit_sym(A_PUSH,S_L,
  280. objectlibrary.newasmsymbol(tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_mangledname));
  281. emit_reg(A_PUSH,S_L,R_EDI);
  282. rg.ungetregister32(exprasmlist,R_EDI);
  283. emitcall('FPC_CHECK_OBJECT_EXT');
  284. emitlab(nillabel);
  285. end;
  286. {$endif TESTOBJEXT2}
  287. procedure ti386typeconvnode.second_call_helper(c : tconverttype);
  288. const
  289. secondconvert : array[tconverttype] of pointer = (
  290. @second_nothing, {equal}
  291. @second_nothing, {not_possible}
  292. @second_nothing, {second_string_to_string, handled in resulttype pass }
  293. @second_char_to_string,
  294. @second_nothing, {char_to_charray}
  295. @second_nothing, { pchar_to_string, handled in resulttype pass }
  296. @second_nothing, {cchar_to_pchar}
  297. @second_cstring_to_pchar,
  298. @second_ansistring_to_pchar,
  299. @second_string_to_chararray,
  300. @second_nothing, { chararray_to_string, handled in resulttype pass }
  301. @second_array_to_pointer,
  302. @second_pointer_to_array,
  303. @second_int_to_int,
  304. @second_int_to_bool,
  305. @second_bool_to_bool,
  306. @second_bool_to_int,
  307. @second_real_to_real,
  308. @second_int_to_real,
  309. @second_proc_to_procvar,
  310. @second_nothing, { arrayconstructor_to_set }
  311. @second_nothing, { second_load_smallset, handled in first pass }
  312. @second_cord_to_pointer,
  313. @second_nothing, { interface 2 string }
  314. @second_nothing, { interface 2 guid }
  315. @second_class_to_intf,
  316. @second_char_to_char,
  317. @second_nothing, { normal_2_smallset }
  318. @second_nothing { dynarray_2_openarray }
  319. );
  320. type
  321. tprocedureofobject = procedure of object;
  322. var
  323. r : packed record
  324. proc : pointer;
  325. obj : pointer;
  326. end;
  327. begin
  328. { this is a little bit dirty but it works }
  329. { and should be quite portable too }
  330. r.proc:=secondconvert[c];
  331. r.obj:=self;
  332. tprocedureofobject(r){$ifdef FPC}();{$endif FPC}
  333. end;
  334. begin
  335. ctypeconvnode:=ti386typeconvnode;
  336. end.
  337. {
  338. $Log$
  339. Revision 1.47 2002-08-11 14:32:30 peter
  340. * renamed current_library to objectlibrary
  341. Revision 1.46 2002/08/11 13:24:16 peter
  342. * saving of asmsymbols in ppu supported
  343. * asmsymbollist global is removed and moved into a new class
  344. tasmlibrarydata that will hold the info of a .a file which
  345. corresponds with a single module. Added librarydata to tmodule
  346. to keep the library info stored for the module. In the future the
  347. objectfiles will also be stored to the tasmlibrarydata class
  348. * all getlabel/newasmsymbol and friends are moved to the new class
  349. Revision 1.45 2002/07/27 19:53:51 jonas
  350. + generic implementation of tcg.g_flags2ref()
  351. * tcg.flags2xxx() now also needs a size parameter
  352. Revision 1.44 2002/07/20 11:58:01 florian
  353. * types.pas renamed to defbase.pas because D6 contains a types
  354. unit so this would conflicts if D6 programms are compiled
  355. + Willamette/SSE2 instructions to assembler added
  356. Revision 1.43 2002/07/01 18:46:31 peter
  357. * internal linker
  358. * reorganized aasm layer
  359. Revision 1.42 2002/05/20 13:30:40 carl
  360. * bugfix of hdisponen (base must be set, not index)
  361. * more portability fixes
  362. Revision 1.41 2002/05/18 13:34:24 peter
  363. * readded missing revisions
  364. Revision 1.40 2002/05/16 19:46:51 carl
  365. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  366. + try to fix temp allocation (still in ifdef)
  367. + generic constructor calls
  368. + start of tassembler / tmodulebase class cleanup
  369. Revision 1.38 2002/05/12 16:53:17 peter
  370. * moved entry and exitcode to ncgutil and cgobj
  371. * foreach gets extra argument for passing local data to the
  372. iterator function
  373. * -CR checks also class typecasts at runtime by changing them
  374. into as
  375. * fixed compiler to cycle with the -CR option
  376. * fixed stabs with elf writer, finally the global variables can
  377. be watched
  378. * removed a lot of routines from cga unit and replaced them by
  379. calls to cgobj
  380. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  381. u32bit then the other is typecasted also to u32bit without giving
  382. a rangecheck warning/error.
  383. * fixed pascal calling method with reversing also the high tree in
  384. the parast, detected by tcalcst3 test
  385. Revision 1.37 2002/04/21 19:02:07 peter
  386. * removed newn and disposen nodes, the code is now directly
  387. inlined from pexpr
  388. * -an option that will write the secondpass nodes to the .s file, this
  389. requires EXTDEBUG define to actually write the info
  390. * fixed various internal errors and crashes due recent code changes
  391. Revision 1.36 2002/04/21 15:35:23 carl
  392. * changeregsize -> rg.makeregsize
  393. Revision 1.35 2002/04/19 15:39:35 peter
  394. * removed some more routines from cga
  395. * moved location_force_reg/mem to ncgutil
  396. * moved arrayconstructnode secondpass to ncgld
  397. Revision 1.34 2002/04/15 19:44:21 peter
  398. * fixed stackcheck that would be called recursively when a stack
  399. error was found
  400. * generic changeregsize(reg,size) for i386 register resizing
  401. * removed some more routines from cga unit
  402. * fixed returnvalue handling
  403. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  404. Revision 1.33 2002/04/04 19:06:10 peter
  405. * removed unused units
  406. * use tlocation.size in cg.a_*loc*() routines
  407. Revision 1.32 2002/04/02 17:11:36 peter
  408. * tlocation,treference update
  409. * LOC_CONSTANT added for better constant handling
  410. * secondadd splitted in multiple routines
  411. * location_force_reg added for loading a location to a register
  412. of a specified size
  413. * secondassignment parses now first the right and then the left node
  414. (this is compatible with Kylix). This saves a lot of push/pop especially
  415. with string operations
  416. * adapted some routines to use the new cg methods
  417. Revision 1.31 2002/03/31 20:26:38 jonas
  418. + a_loadfpu_* and a_loadmm_* methods in tcg
  419. * register allocation is now handled by a class and is mostly processor
  420. independent (+rgobj.pas and i386/rgcpu.pas)
  421. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  422. * some small improvements and fixes to the optimizer
  423. * some register allocation fixes
  424. * some fpuvaroffset fixes in the unary minus node
  425. * push/popusedregisters is now called rg.save/restoreusedregisters and
  426. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  427. also better optimizable)
  428. * fixed and optimized register saving/restoring for new/dispose nodes
  429. * LOC_FPU locations now also require their "register" field to be set to
  430. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  431. - list field removed of the tnode class because it's not used currently
  432. and can cause hard-to-find bugs
  433. Revision 1.30 2002/03/04 19:10:13 peter
  434. * removed compiler warnings
  435. }