nppccnv.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate PowerPC 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 nppccnv;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,ncnv,ncgcnv,defbase;
  23. type
  24. tppctypeconvnode = 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. function first_int_to_real: tnode; override;
  32. { procedure second_pointer_to_array;override; }
  33. { procedure second_chararray_to_string;override; }
  34. { procedure second_char_to_string;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. procedure pass_2;override;
  47. procedure second_call_helper(c : tconverttype); override;
  48. end;
  49. implementation
  50. uses
  51. verbose,globals,systems,
  52. symconst,symdef,aasmbase,aasmtai,
  53. cgbase,pass_1,pass_2,
  54. ncon,ncal,
  55. cpubase,aasmcpu,
  56. rgobj,tgobj,cgobj,cginfo;
  57. {*****************************************************************************
  58. FirstTypeConv
  59. *****************************************************************************}
  60. function tppctypeconvnode.first_int_to_real: tnode;
  61. var
  62. fname: string[19];
  63. begin
  64. { converting a 64bit integer to a float requires a helper }
  65. if is_64bitint(left.resulttype.def) then
  66. begin
  67. if is_signed(left.resulttype.def) then
  68. fname := 'fpc_int64_to_double'
  69. else
  70. fname := 'fpc_qword_to_double';
  71. result := ccallnode.createintern(fname,ccallparanode.create(
  72. left,nil));
  73. firstpass(result);
  74. exit;
  75. end
  76. else
  77. { other integers are supposed to be 32 bit }
  78. begin
  79. if is_signed(left.resulttype.def) then
  80. inserttypeconv(left,s32bittype)
  81. else
  82. inserttypeconv(left,u32bittype);
  83. firstpass(left);
  84. end;
  85. result := inherited first_int_to_real;
  86. end;
  87. {*****************************************************************************
  88. SecondTypeConv
  89. *****************************************************************************}
  90. procedure tppctypeconvnode.second_int_to_real;
  91. type
  92. tdummyarray = packed array[0..7] of byte;
  93. const
  94. dummyarray1 : tdummyarray = ($43,$30,$00,$00,$80,$00,$00,$00);
  95. dummyarray2 : tdummyarray = ($43,$30,$00,$00,$00,$00,$00,$00);
  96. var
  97. tempconst: trealconstnode;
  98. ref: treference;
  99. valuereg, tempreg, leftreg, tmpfpureg: tregister;
  100. signed, valuereg_is_scratch: boolean;
  101. begin
  102. valuereg_is_scratch := false;
  103. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  104. { the code here comes from the PowerPC Compiler Writer's Guide }
  105. { * longint to double }
  106. { addis R0,R0,0x4330 # R0 = 0x43300000 }
  107. { stw R0,disp(R1) # store upper half }
  108. { xoris R3,R3,0x8000 # flip sign bit }
  109. { stw R3,disp+4(R1) # store lower half }
  110. { lfd FR1,disp(R1) # float load double of value }
  111. { fsub FR1,FR1,FR2 # subtract 0x4330000080000000 }
  112. { * cardinal to double }
  113. { addis R0,R0,0x4330 # R0 = 0x43300000 }
  114. { stw R0,disp(R1) # store upper half }
  115. { stw R3,disp+4(R1) # store lower half }
  116. { lfd FR1,disp(R1) # float load double of value }
  117. { fsub FR1,FR1,FR2 # subtract 0x4330000000000000 }
  118. tg.gettempofsizereference(exprasmlist,8,ref);
  119. signed := is_signed(left.resulttype.def);
  120. { we need a certain constant for the conversion, so create it here }
  121. if signed then
  122. tempconst :=
  123. { the array of byte is necessary because 1. the 1.0.x compiler
  124. doesn't know 64 constants, 2. it won't work with big endian
  125. and little endian machines at the same time (FK)
  126. }
  127. crealconstnode.create(double(dummyarray1),
  128. pbestrealtype^)
  129. else
  130. tempconst :=
  131. crealconstnode.create(double(dummyarray2),
  132. pbestrealtype^);
  133. resulttypepass(tempconst);
  134. firstpass(tempconst);
  135. secondpass(tempconst);
  136. if (tempconst.location.loc <> LOC_CREFERENCE) or
  137. { has to be handled by a helper }
  138. is_64bitint(left.resulttype.def) then
  139. internalerror(200110011);
  140. case left.location.loc of
  141. LOC_REGISTER:
  142. begin
  143. leftreg := left.location.register;
  144. valuereg := leftreg;
  145. end;
  146. LOC_CREGISTER:
  147. begin
  148. leftreg := left.location.register;
  149. if signed then
  150. begin
  151. valuereg := cg.get_scratch_reg_int(exprasmlist);
  152. valuereg_is_scratch := true;
  153. end
  154. else
  155. valuereg := leftreg;
  156. end;
  157. LOC_REFERENCE,LOC_CREFERENCE:
  158. begin
  159. leftreg := cg.get_scratch_reg_int(exprasmlist);
  160. valuereg := leftreg;
  161. valuereg_is_scratch := true;
  162. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),
  163. left.location.reference,leftreg);
  164. end
  165. else
  166. internalerror(200110012);
  167. end;
  168. tempreg := cg.get_scratch_reg_int(exprasmlist);
  169. exprasmlist.concat(taicpu.op_reg_const(A_LIS,tempreg,$4330));
  170. cg.a_load_reg_ref(exprasmlist,OS_32,tempreg,ref);
  171. cg.free_scratch_reg(exprasmlist,tempreg);
  172. if signed then
  173. exprasmlist.concat(taicpu.op_reg_reg_const(A_XORIS,valuereg,
  174. leftreg,smallint($8000)));
  175. inc(ref.offset,4);
  176. cg.a_load_reg_ref(exprasmlist,OS_32,valuereg,ref);
  177. dec(ref.offset,4);
  178. if (valuereg_is_scratch) then
  179. cg.free_scratch_reg(exprasmlist,valuereg);
  180. if (left.location.loc = LOC_REGISTER) or
  181. ((left.location.loc = LOC_CREGISTER) and
  182. not signed) then
  183. rg.ungetregister(exprasmlist,leftreg)
  184. else
  185. cg.free_scratch_reg(exprasmlist,valuereg);
  186. tmpfpureg := rg.getregisterfpu(exprasmlist);
  187. exprasmlist.concat(taicpu.op_reg_ref(A_LFD,tmpfpureg,
  188. tempconst.location.reference));
  189. tempconst.free;
  190. location.register := rg.getregisterfpu(exprasmlist);
  191. exprasmlist.concat(taicpu.op_reg_ref(A_LFD,location.register,
  192. ref));
  193. tg.ungetiftemp(exprasmlist,ref);
  194. exprasmlist.concat(taicpu.op_reg_reg_reg(A_FSUB,location.register,
  195. location.register,tmpfpureg));
  196. rg.ungetregisterfpu(exprasmlist,tmpfpureg);
  197. { work around bug in some PowerPC processors }
  198. if (tfloatdef(resulttype.def).typ = s32real) then
  199. exprasmlist.concat(taicpu.op_reg_reg(A_FRSP,location.register,
  200. location.register));
  201. end;
  202. procedure tppctypeconvnode.second_real_to_real;
  203. begin
  204. inherited second_real_to_real;
  205. { work around bug in some powerpc processors where doubles aren't }
  206. { properly converted to singles }
  207. if (tfloatdef(left.resulttype.def).typ = s64real) and
  208. (tfloatdef(resulttype.def).typ = s32real) then
  209. exprasmlist.concat(taicpu.op_reg_reg(A_FRSP,location.register,
  210. location.register));
  211. end;
  212. procedure tppctypeconvnode.second_int_to_bool;
  213. var
  214. hreg1,
  215. hreg2 : tregister;
  216. resflags : tresflags;
  217. opsize : tcgsize;
  218. begin
  219. { byte(boolean) or word(wordbool) or longint(longbool) must }
  220. { be accepted for var parameters }
  221. if (nf_explizit in flags) and
  222. (left.resulttype.def.size=resulttype.def.size) and
  223. (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
  224. begin
  225. location_copy(location,left.location);
  226. exit;
  227. end;
  228. location_reset(location,LOC_REGISTER,def_cgsize(left.resulttype.def));
  229. opsize := def_cgsize(left.resulttype.def);
  230. case left.location.loc of
  231. LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER :
  232. begin
  233. if left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  234. begin
  235. reference_release(exprasmlist,left.location.reference);
  236. hreg2:=rg.getregisterint(exprasmlist);
  237. cg.a_load_ref_reg(exprasmlist,opsize,
  238. left.location.reference,hreg2);
  239. end
  240. else
  241. hreg2 := left.location.register;
  242. hreg1 := rg.getregisterint(exprasmlist);
  243. exprasmlist.concat(taicpu.op_reg_reg_const(A_SUBIC,hreg1,
  244. hreg2,1));
  245. exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBFE,hreg1,hreg1,
  246. hreg2));
  247. rg.ungetregister(exprasmlist,hreg2);
  248. end;
  249. LOC_FLAGS :
  250. begin
  251. hreg1:=rg.getregisterint(exprasmlist);
  252. resflags:=left.location.resflags;
  253. cg.g_flags2reg(exprasmlist,resflags,hreg1);
  254. end;
  255. else
  256. internalerror(10062);
  257. end;
  258. location.register := hreg1;
  259. end;
  260. procedure tppctypeconvnode.second_call_helper(c : tconverttype);
  261. const
  262. secondconvert : array[tconverttype] of pointer = (
  263. @second_nothing, {equal}
  264. @second_nothing, {not_possible}
  265. @second_nothing, {second_string_to_string, handled in resulttype pass }
  266. @second_char_to_string,
  267. @second_nothing, {char_to_charray}
  268. @second_nothing, { pchar_to_string, handled in resulttype pass }
  269. @second_nothing, {cchar_to_pchar}
  270. @second_cstring_to_pchar,
  271. @second_ansistring_to_pchar,
  272. @second_string_to_chararray,
  273. @second_nothing, { chararray_to_string, handled in resulttype pass }
  274. @second_array_to_pointer,
  275. @second_pointer_to_array,
  276. @second_int_to_int,
  277. @second_int_to_bool,
  278. @second_bool_to_int, { bool_to_bool }
  279. @second_bool_to_int,
  280. @second_real_to_real,
  281. @second_int_to_real,
  282. @second_proc_to_procvar,
  283. @second_nothing, { arrayconstructor_to_set }
  284. @second_nothing, { second_load_smallset, handled in first pass }
  285. @second_cord_to_pointer,
  286. @second_nothing, { interface 2 string }
  287. @second_nothing, { interface 2 guid }
  288. @second_class_to_intf,
  289. @second_char_to_char,
  290. @second_nothing, { normal_2_smallset }
  291. @second_nothing { dynarray_2_openarray }
  292. );
  293. type
  294. tprocedureofobject = procedure of object;
  295. var
  296. r : packed record
  297. proc : pointer;
  298. obj : pointer;
  299. end;
  300. begin
  301. { this is a little bit dirty but it works }
  302. { and should be quite portable too }
  303. r.proc:=secondconvert[c];
  304. r.obj:=self;
  305. tprocedureofobject(r){$ifdef FPC}();{$endif FPC}
  306. end;
  307. procedure tppctypeconvnode.pass_2;
  308. {$ifdef TESTOBJEXT2}
  309. var
  310. r : preference;
  311. nillabel : plabel;
  312. {$endif TESTOBJEXT2}
  313. begin
  314. { this isn't good coding, I think tc_bool_2_int, shouldn't be }
  315. { type conversion (FK) }
  316. if not(convtype in [tc_bool_2_int,tc_bool_2_bool]) then
  317. begin
  318. secondpass(left);
  319. location_copy(location,left.location);
  320. if codegenerror then
  321. exit;
  322. end;
  323. second_call_helper(convtype);
  324. end;
  325. begin
  326. ctypeconvnode:=tppctypeconvnode;
  327. end.
  328. {
  329. $Log$
  330. Revision 1.14 2002-07-20 11:58:05 florian
  331. * types.pas renamed to defbase.pas because D6 contains a types
  332. unit so this would conflicts if D6 programms are compiled
  333. + Willamette/SSE2 instructions to assembler added
  334. Revision 1.13 2002/07/13 06:49:39 jonas
  335. * fixed fpu constants in second_int_to_real (fpu values are also stored
  336. in big endian)
  337. Revision 1.12 2002/07/12 22:02:22 florian
  338. * fixed to compile with 1.1
  339. Revision 1.11 2002/07/11 14:41:34 florian
  340. * start of the new generic parameter handling
  341. Revision 1.10 2002/07/11 07:42:31 jonas
  342. * fixed nppccnv and enabled it
  343. - removed PPC specific second_int_to_int and use the generic one instead
  344. Revision 1.9 2002/05/20 13:30:42 carl
  345. * bugfix of hdisponen (base must be set, not index)
  346. * more portability fixes
  347. Revision 1.8 2002/05/18 13:34:26 peter
  348. * readded missing revisions
  349. Revision 1.7 2002/05/16 19:46:53 carl
  350. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  351. + try to fix temp allocation (still in ifdef)
  352. + generic constructor calls
  353. + start of tassembler / tmodulebase class cleanup
  354. Revision 1.5 2002/04/06 18:13:02 jonas
  355. * several powerpc-related additions and fixes
  356. }