ncgcnv.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Generate assembler for nodes that handle type conversions which are
  5. the same for all (most) processors
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ncgcnv;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. node,ncnv,defbase;
  24. type
  25. tcgtypeconvnode = class(ttypeconvnode)
  26. procedure second_int_to_int;override;
  27. procedure second_cstring_to_pchar;override;
  28. procedure second_string_to_chararray;override;
  29. procedure second_array_to_pointer;override;
  30. procedure second_pointer_to_array;override;
  31. procedure second_char_to_string;override;
  32. procedure second_real_to_real;override;
  33. procedure second_cord_to_pointer;override;
  34. procedure second_proc_to_procvar;override;
  35. procedure second_bool_to_int;override;
  36. procedure second_bool_to_bool;override;
  37. procedure second_ansistring_to_pchar;override;
  38. procedure second_class_to_intf;override;
  39. procedure second_char_to_char;override;
  40. procedure second_nothing;override;
  41. {$ifdef TESTOBJEXT2}
  42. procedure checkobject;virtual;
  43. {$endif TESTOBJEXT2}
  44. procedure second_call_helper(c : tconverttype);virtual;abstract;
  45. procedure pass_2;override;
  46. end;
  47. tcgasnode = class(tasnode)
  48. procedure pass_2;override;
  49. end;
  50. implementation
  51. uses
  52. cutils,verbose,
  53. aasmbase,aasmtai,aasmcpu,symconst,symdef,paramgr,
  54. ncon,ncal,
  55. cpubase,cpuinfo,cpupara,systems,
  56. pass_2,
  57. cginfo,cgbase,
  58. cgobj,cgcpu,
  59. ncgutil,
  60. tgobj,rgobj
  61. ;
  62. procedure tcgtypeconvnode.second_int_to_int;
  63. var
  64. newsize : tcgsize;
  65. ressize, leftsize: cardinal;
  66. begin
  67. newsize:=def_cgsize(resulttype.def);
  68. { insert range check if not explicit conversion }
  69. if not(nf_explizit in flags) then
  70. cg.g_rangecheck(exprasmlist,left,resulttype.def);
  71. { is the result size smaller ? }
  72. ressize := resulttype.def.size;
  73. leftsize := left.resulttype.def.size;
  74. if ressize<>leftsize then
  75. begin
  76. location_copy(location,left.location);
  77. { reuse a loc_reference when the newsize is smaller than
  78. than the original, else load it to a register }
  79. if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  80. (ressize<leftsize) then
  81. begin
  82. location.size:=newsize;
  83. if (target_info.endian = ENDIAN_BIG) then
  84. inc(location.reference.offset,leftsize-ressize);
  85. end
  86. else
  87. location_force_reg(exprasmlist,location,newsize,false);
  88. end
  89. else
  90. begin
  91. { no special loading is required, reuse current location }
  92. location_copy(location,left.location);
  93. location.size:=newsize;
  94. end;
  95. end;
  96. procedure tcgtypeconvnode.second_cstring_to_pchar;
  97. var
  98. hr : treference;
  99. begin
  100. location_release(exprasmlist,left.location);
  101. location_reset(location,LOC_REGISTER,OS_ADDR);
  102. case tstringdef(left.resulttype.def).string_typ of
  103. st_shortstring :
  104. begin
  105. inc(left.location.reference.offset);
  106. location.register:=rg.getaddressregister(exprasmlist);
  107. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,location.register);
  108. end;
  109. st_ansistring :
  110. begin
  111. if (left.nodetype=stringconstn) and
  112. (str_length(left)=0) then
  113. begin
  114. reference_reset(hr);
  115. hr.symbol:=objectlibrary.newasmsymbol('FPC_EMPTYCHAR');
  116. location.register:=rg.getaddressregister(exprasmlist);
  117. cg.a_loadaddr_ref_reg(exprasmlist,hr,location.register);
  118. end
  119. else
  120. begin
  121. location.register:=rg.getaddressregister(exprasmlist);
  122. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.register);
  123. end;
  124. end;
  125. st_longstring:
  126. begin
  127. {!!!!!!!}
  128. internalerror(8888);
  129. end;
  130. st_widestring:
  131. begin
  132. if (left.nodetype=stringconstn) and
  133. (str_length(left)=0) then
  134. begin
  135. reference_reset(hr);
  136. hr.symbol:=objectlibrary.newasmsymbol('FPC_EMPTYCHAR');
  137. location.register:=rg.getaddressregister(exprasmlist);
  138. cg.a_loadaddr_ref_reg(exprasmlist,hr,location.register);
  139. end
  140. else
  141. begin
  142. location.register:=rg.getregisterint(exprasmlist);
  143. {$ifdef fpc}
  144. {$warning Todo: convert widestrings to ascii when typecasting them to pchars}
  145. {$endif}
  146. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,
  147. location.register);
  148. end;
  149. end;
  150. end;
  151. end;
  152. procedure tcgtypeconvnode.second_string_to_chararray;
  153. var
  154. arrsize: longint;
  155. begin
  156. with tarraydef(resulttype.def) do
  157. arrsize := highrange-lowrange+1;
  158. if (left.nodetype = stringconstn) and
  159. { left.length+1 since there's always a terminating #0 character (JM) }
  160. (tstringconstnode(left).len+1 >= arrsize) and
  161. (tstringdef(left.resulttype.def).string_typ=st_shortstring) then
  162. begin
  163. location_copy(location,left.location);
  164. inc(location.reference.offset);
  165. exit;
  166. end
  167. else
  168. { should be handled already in resulttype pass (JM) }
  169. internalerror(200108292);
  170. end;
  171. procedure tcgtypeconvnode.second_array_to_pointer;
  172. begin
  173. location_release(exprasmlist,left.location);
  174. location_reset(location,LOC_REGISTER,OS_ADDR);
  175. location.register:=rg.getaddressregister(exprasmlist);
  176. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,location.register);
  177. end;
  178. procedure tcgtypeconvnode.second_pointer_to_array;
  179. begin
  180. location_reset(location,LOC_REFERENCE,OS_NO);
  181. case left.location.loc of
  182. LOC_REGISTER :
  183. begin
  184. if not rg.isaddressregister(left.location.register) then
  185. begin
  186. location_release(exprasmlist,left.location);
  187. location.reference.base:=rg.getaddressregister(exprasmlist);
  188. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,
  189. left.location.register,location.reference.base);
  190. end
  191. else
  192. location.reference.base := left.location.register;
  193. end;
  194. LOC_CREGISTER :
  195. begin
  196. location.reference.base:=rg.getaddressregister(exprasmlist);
  197. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.register,
  198. location.reference.base);
  199. end;
  200. LOC_REFERENCE,
  201. LOC_CREFERENCE :
  202. begin
  203. location_release(exprasmlist,left.location);
  204. location.reference.base:=rg.getaddressregister(exprasmlist);
  205. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,
  206. location.reference.base);
  207. location_freetemp(exprasmlist,left.location);
  208. end;
  209. else
  210. internalerror(2002032216);
  211. end;
  212. end;
  213. procedure tcgtypeconvnode.second_char_to_string;
  214. begin
  215. location_reset(location,LOC_REFERENCE,OS_NO);
  216. case tstringdef(resulttype.def).string_typ of
  217. st_shortstring :
  218. begin
  219. tg.GetTemp(exprasmlist,256,tt_normal,location.reference);
  220. cg.a_load_loc_ref(exprasmlist,left.location,
  221. location.reference);
  222. location_release(exprasmlist,left.location);
  223. location_freetemp(exprasmlist,left.location);
  224. end;
  225. { the rest is removed in the resulttype pass and converted to compilerprocs }
  226. else
  227. internalerror(4179);
  228. end;
  229. end;
  230. procedure tcgtypeconvnode.second_real_to_real;
  231. begin
  232. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  233. case left.location.loc of
  234. LOC_FPUREGISTER,
  235. LOC_CFPUREGISTER:
  236. begin
  237. location_copy(location,left.location);
  238. location.size:=def_cgsize(resulttype.def);
  239. exit;
  240. end;
  241. LOC_CREFERENCE,
  242. LOC_REFERENCE:
  243. begin
  244. location_release(exprasmlist,left.location);
  245. location.register:=rg.getregisterfpu(exprasmlist);
  246. cg.a_loadfpu_loc_reg(exprasmlist,left.location,location.register);
  247. location_freetemp(exprasmlist,left.location);
  248. end;
  249. else
  250. internalerror(2002032215);
  251. end;
  252. end;
  253. procedure tcgtypeconvnode.second_cord_to_pointer;
  254. begin
  255. { this can't happen because constants are already processed in
  256. pass 1 }
  257. internalerror(47423985);
  258. end;
  259. procedure tcgtypeconvnode.second_proc_to_procvar;
  260. begin
  261. { method pointer ? }
  262. if assigned(tunarynode(left).left) then
  263. begin
  264. location_copy(location,left.location);
  265. end
  266. else
  267. begin
  268. location_release(exprasmlist,left.location);
  269. location_reset(location,LOC_REGISTER,OS_ADDR);
  270. location.register:=rg.getaddressregister(exprasmlist);
  271. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,location.register);
  272. end;
  273. end;
  274. procedure tcgtypeconvnode.second_bool_to_int;
  275. var
  276. oldtruelabel,oldfalselabel : tasmlabel;
  277. begin
  278. oldtruelabel:=truelabel;
  279. oldfalselabel:=falselabel;
  280. objectlibrary.getlabel(truelabel);
  281. objectlibrary.getlabel(falselabel);
  282. secondpass(left);
  283. location_copy(location,left.location);
  284. { byte(boolean) or word(wordbool) or longint(longbool) must }
  285. { be accepted for var parameters }
  286. if not((nf_explizit in flags) and
  287. (left.resulttype.def.size=resulttype.def.size) and
  288. (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER])) then
  289. location_force_reg(exprasmlist,location,def_cgsize(resulttype.def),false);
  290. truelabel:=oldtruelabel;
  291. falselabel:=oldfalselabel;
  292. end;
  293. procedure tcgtypeconvnode.second_bool_to_bool;
  294. begin
  295. { we can reuse the conversion already available
  296. in bool_to_int to resize the value. But when the
  297. size of the new boolean is smaller we need to calculate
  298. the value as is done in int_to_bool. This is needed because
  299. the bits that define the true status can be outside the limits
  300. of the new size and truncating the register can result in a 0
  301. value }
  302. if resulttype.def.size<left.resulttype.def.size then
  303. second_int_to_bool
  304. else
  305. second_bool_to_int;
  306. end;
  307. procedure tcgtypeconvnode.second_ansistring_to_pchar;
  308. var
  309. l1 : tasmlabel;
  310. hr : treference;
  311. begin
  312. location_reset(location,LOC_REGISTER,OS_ADDR);
  313. objectlibrary.getlabel(l1);
  314. case left.location.loc of
  315. LOC_CREGISTER,LOC_REGISTER:
  316. begin
  317. if not rg.isaddressregister(left.location.register) then
  318. begin
  319. location_release(exprasmlist,left.location);
  320. location.register:=rg.getaddressregister(exprasmlist);
  321. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,
  322. left.location.register,location.register);
  323. end
  324. else
  325. location.register := left.location.register;
  326. end;
  327. LOC_CREFERENCE,LOC_REFERENCE:
  328. begin
  329. location_release(exprasmlist,left.location);
  330. location.register:=rg.getaddressregister(exprasmlist);
  331. cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,location.register);
  332. location_freetemp(exprasmlist,left.location);
  333. end;
  334. else
  335. internalerror(2002032214);
  336. end;
  337. cg.a_cmp_const_reg_label(exprasmlist,OS_32,OC_NE,0,location.register,l1);
  338. reference_reset(hr);
  339. hr.symbol:=objectlibrary.newasmsymbol('FPC_EMPTYCHAR');
  340. cg.a_loadaddr_ref_reg(exprasmlist,hr,location.register);
  341. cg.a_label(exprasmlist,l1);
  342. end;
  343. procedure tcgtypeconvnode.second_class_to_intf;
  344. var
  345. l1 : tasmlabel;
  346. hd : tobjectdef;
  347. begin
  348. location_reset(location,LOC_REGISTER,OS_ADDR);
  349. case left.location.loc of
  350. LOC_CREFERENCE,
  351. LOC_REFERENCE:
  352. begin
  353. location_release(exprasmlist,left.location);
  354. location.register:=rg.getaddressregister(exprasmlist);
  355. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.register);
  356. location_freetemp(exprasmlist,left.location);
  357. end;
  358. LOC_CREGISTER:
  359. begin
  360. location.register:=rg.getaddressregister(exprasmlist);
  361. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.register,location.register);
  362. end;
  363. LOC_REGISTER:
  364. location.register:=left.location.register;
  365. else
  366. internalerror(121120001);
  367. end;
  368. objectlibrary.getlabel(l1);
  369. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,location.register,l1);
  370. hd:=tobjectdef(left.resulttype.def);
  371. while assigned(hd) do
  372. begin
  373. if hd.implementedinterfaces.searchintf(resulttype.def)<>-1 then
  374. begin
  375. cg.a_op_const_reg(exprasmlist,OP_ADD,aword(
  376. hd.implementedinterfaces.ioffsets(
  377. hd.implementedinterfaces.searchintf(
  378. resulttype.def))^),location.register);
  379. break;
  380. end;
  381. hd:=hd.childof;
  382. end;
  383. if hd=nil then
  384. internalerror(2002081301);
  385. cg.a_label(exprasmlist,l1);
  386. end;
  387. procedure tcgtypeconvnode.second_char_to_char;
  388. begin
  389. {$ifdef fpc}
  390. {$warning todo: add RTL routine for widechar-char conversion }
  391. {$endif}
  392. { Quick hack to atleast generate 'working' code (PFV) }
  393. second_int_to_int;
  394. end;
  395. procedure tcgtypeconvnode.second_nothing;
  396. begin
  397. { we reuse the old value }
  398. location_copy(location,left.location);
  399. { Floats should never be returned as LOC_CONSTANT, do the
  400. moving to memory before the new size is set }
  401. if (resulttype.def.deftype=floatdef) and
  402. (location.loc=LOC_CONSTANT) then
  403. location_force_mem(exprasmlist,location);
  404. { but use the new size, but we don't know the size of all arrays }
  405. location.size:=def_cgsize(resulttype.def);
  406. end;
  407. {$ifdef TESTOBJEXT2}
  408. procedure tcgtypeconvnode.checkobject;
  409. begin
  410. { no checking by default }
  411. end;
  412. {$endif TESTOBJEXT2}
  413. procedure tcgtypeconvnode.pass_2;
  414. begin
  415. { the boolean routines can be called with LOC_JUMP and
  416. call secondpass themselves in the helper }
  417. if not(convtype in [tc_bool_2_int,tc_bool_2_bool,tc_int_2_bool]) then
  418. begin
  419. secondpass(left);
  420. if codegenerror then
  421. exit;
  422. end;
  423. second_call_helper(convtype);
  424. {$ifdef TESTOBJEXT2}
  425. { Check explicit conversions to objects pointers !! }
  426. if p^.explizit and
  427. (p^.resulttype.def.deftype=pointerdef) and
  428. (tpointerdef(p^.resulttype.def).definition.deftype=objectdef) and not
  429. (tobjectdef(tpointerdef(p^.resulttype.def).definition).isclass) and
  430. ((tobjectdef(tpointerdef(p^.resulttype.def).definition).options and oo_hasvmt)<>0) and
  431. (cs_check_range in aktlocalswitches) then
  432. checkobject;
  433. {$endif TESTOBJEXT2}
  434. end;
  435. procedure tcgasnode.pass_2;
  436. begin
  437. secondpass(call);
  438. location_copy(location,call.location);
  439. end;
  440. begin
  441. ctypeconvnode := tcgtypeconvnode;
  442. casnode := tcgasnode;
  443. end.
  444. {
  445. $Log$
  446. Revision 1.33 2002-10-05 12:43:25 carl
  447. * fixes for Delphi 6 compilation
  448. (warning : Some features do not work under Delphi)
  449. Revision 1.32 2002/09/17 18:54:02 jonas
  450. * a_load_reg_reg() now has two size parameters: source and dest. This
  451. allows some optimizations on architectures that don't encode the
  452. register size in the register name.
  453. Revision 1.31 2002/09/16 13:08:44 jonas
  454. * big endian fix for second_int_to_int
  455. Revision 1.30 2002/09/07 15:25:02 peter
  456. * old logs removed and tabs fixed
  457. Revision 1.29 2002/09/02 18:46:00 peter
  458. * reuse a reference when resizing ordinal values to smaller sizes,
  459. this is required for constructions like byte(w):=1 that are
  460. allowed in tp mode only
  461. Revision 1.28 2002/08/25 09:06:58 peter
  462. * add calls to release temps
  463. Revision 1.27 2002/08/23 16:14:48 peter
  464. * tempgen cleanup
  465. * tt_noreuse temp type added that will be used in genentrycode
  466. Revision 1.26 2002/08/20 18:23:32 jonas
  467. * the as node again uses a compilerproc
  468. + (untested) support for interface "as" statements
  469. Revision 1.25 2002/08/13 18:01:52 carl
  470. * rename swatoperands to swapoperands
  471. + m68k first compilable version (still needs a lot of testing):
  472. assembler generator, system information , inline
  473. assembler reader.
  474. Revision 1.24 2002/08/12 20:39:17 florian
  475. * casting of classes to interface fixed when the interface was
  476. implemented by a parent class
  477. Revision 1.23 2002/08/11 14:32:26 peter
  478. * renamed current_library to objectlibrary
  479. Revision 1.22 2002/08/11 13:24:11 peter
  480. * saving of asmsymbols in ppu supported
  481. * asmsymbollist global is removed and moved into a new class
  482. tasmlibrarydata that will hold the info of a .a file which
  483. corresponds with a single module. Added librarydata to tmodule
  484. to keep the library info stored for the module. In the future the
  485. objectfiles will also be stored to the tasmlibrarydata class
  486. * all getlabel/newasmsymbol and friends are moved to the new class
  487. Revision 1.21 2002/07/20 11:57:53 florian
  488. * types.pas renamed to defbase.pas because D6 contains a types
  489. unit so this would conflicts if D6 programms are compiled
  490. + Willamette/SSE2 instructions to assembler added
  491. Revision 1.20 2002/07/11 14:41:28 florian
  492. * start of the new generic parameter handling
  493. Revision 1.19 2002/07/07 09:52:32 florian
  494. * powerpc target fixed, very simple units can be compiled
  495. * some basic stuff for better callparanode handling, far from being finished
  496. Revision 1.18 2002/07/04 20:43:01 florian
  497. * first x86-64 patches
  498. Revision 1.17 2002/07/01 18:46:22 peter
  499. * internal linker
  500. * reorganized aasm layer
  501. Revision 1.16 2002/07/01 16:23:53 peter
  502. * cg64 patch
  503. * basics for currency
  504. * asnode updates for class and interface (not finished)
  505. Revision 1.15 2002/05/18 13:34:09 peter
  506. * readded missing revisions
  507. Revision 1.14 2002/05/16 19:46:37 carl
  508. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  509. + try to fix temp allocation (still in ifdef)
  510. + generic constructor calls
  511. + start of tassembler / tmodulebase class cleanup
  512. Revision 1.12 2002/05/12 16:53:07 peter
  513. * moved entry and exitcode to ncgutil and cgobj
  514. * foreach gets extra argument for passing local data to the
  515. iterator function
  516. * -CR checks also class typecasts at runtime by changing them
  517. into as
  518. * fixed compiler to cycle with the -CR option
  519. * fixed stabs with elf writer, finally the global variables can
  520. be watched
  521. * removed a lot of routines from cga unit and replaced them by
  522. calls to cgobj
  523. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  524. u32bit then the other is typecasted also to u32bit without giving
  525. a rangecheck warning/error.
  526. * fixed pascal calling method with reversing also the high tree in
  527. the parast, detected by tcalcst3 test
  528. Revision 1.11 2002/04/21 19:02:03 peter
  529. * removed newn and disposen nodes, the code is now directly
  530. inlined from pexpr
  531. * -an option that will write the secondpass nodes to the .s file, this
  532. requires EXTDEBUG define to actually write the info
  533. * fixed various internal errors and crashes due recent code changes
  534. Revision 1.10 2002/04/19 15:39:34 peter
  535. * removed some more routines from cga
  536. * moved location_force_reg/mem to ncgutil
  537. * moved arrayconstructnode secondpass to ncgld
  538. Revision 1.9 2002/04/15 19:44:19 peter
  539. * fixed stackcheck that would be called recursively when a stack
  540. error was found
  541. * generic changeregsize(reg,size) for i386 register resizing
  542. * removed some more routines from cga unit
  543. * fixed returnvalue handling
  544. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  545. }