nppccnv.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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,defcmp;
  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. end;
  47. implementation
  48. uses
  49. verbose,globtype,globals,systems,
  50. symconst,symdef,aasmbase,aasmtai,
  51. defutil,
  52. cgbase,cgutils,pass_1,pass_2,
  53. ncon,ncal,
  54. ncgutil,
  55. cpubase,aasmcpu,
  56. rgobj,tgobj,cgobj;
  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) or
  66. is_currency(left.resulttype.def) then
  67. begin
  68. { hack to avoid double division by 10000, as it's }
  69. { already done by resulttypepass.resulttype_int_to_real }
  70. if is_currency(left.resulttype.def) then
  71. left.resulttype := s64inttype;
  72. if is_signed(left.resulttype.def) then
  73. fname := 'fpc_int64_to_double'
  74. else
  75. fname := 'fpc_qword_to_double';
  76. result := ccallnode.createintern(fname,ccallparanode.create(
  77. left,nil));
  78. left:=nil;
  79. firstpass(result);
  80. exit;
  81. end
  82. else
  83. { other integers are supposed to be 32 bit }
  84. begin
  85. if is_signed(left.resulttype.def) then
  86. inserttypeconv(left,s32inttype)
  87. else
  88. inserttypeconv(left,u32inttype);
  89. firstpass(left);
  90. end;
  91. result := nil;
  92. if registersfpu<1 then
  93. registersfpu:=1;
  94. expectloc:=LOC_FPUREGISTER;
  95. end;
  96. {*****************************************************************************
  97. SecondTypeConv
  98. *****************************************************************************}
  99. procedure tppctypeconvnode.second_int_to_real;
  100. type
  101. tdummyarray = packed array[0..7] of byte;
  102. {$ifdef VER1_0}
  103. var
  104. dummy1, dummy2: int64;
  105. {$else VER1_0}
  106. const
  107. dummy1: int64 = $4330000080000000;
  108. dummy2: int64 = $4330000000000000;
  109. {$endif VER1_0}
  110. var
  111. tempconst: trealconstnode;
  112. ref: treference;
  113. valuereg, tempreg, leftreg, tmpfpureg: tregister;
  114. size: tcgsize;
  115. signed : boolean;
  116. begin
  117. {$ifdef VER1_0}
  118. dummy1 := (int64(1) shl 31) or (int64($43300000) shl 32);
  119. dummy2 := int64($43300000) shl 32;
  120. {$endif VER1_0}
  121. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  122. { the code here comes from the PowerPC Compiler Writer's Guide }
  123. { * longint to double }
  124. { addis R0,R0,0x4330 # R0 = 0x43300000 }
  125. { stw R0,disp(R1) # store upper half }
  126. { xoris R3,R3,0x8000 # flip sign bit }
  127. { stw R3,disp+4(R1) # store lower half }
  128. { lfd FR1,disp(R1) # float load double of value }
  129. { fsub FR1,FR1,FR2 # subtract 0x4330000080000000 }
  130. { * cardinal to double }
  131. { addis R0,R0,0x4330 # R0 = 0x43300000 }
  132. { stw R0,disp(R1) # store upper half }
  133. { stw R3,disp+4(R1) # store lower half }
  134. { lfd FR1,disp(R1) # float load double of value }
  135. { fsub FR1,FR1,FR2 # subtract 0x4330000000000000 }
  136. tg.Gettemp(exprasmlist,8,tt_normal,ref);
  137. signed := is_signed(left.resulttype.def);
  138. { we need a certain constant for the conversion, so create it here }
  139. if signed then
  140. tempconst :=
  141. crealconstnode.create(double(tdummyarray(dummy1)),
  142. pbestrealtype^)
  143. else
  144. tempconst :=
  145. crealconstnode.create(double(tdummyarray(dummy2)),
  146. pbestrealtype^);
  147. resulttypepass(tempconst);
  148. firstpass(tempconst);
  149. secondpass(tempconst);
  150. if (tempconst.location.loc <> LOC_CREFERENCE) or
  151. { has to be handled by a helper }
  152. is_64bitint(left.resulttype.def) then
  153. internalerror(200110011);
  154. case left.location.loc of
  155. LOC_REGISTER:
  156. begin
  157. leftreg := left.location.register;
  158. valuereg := leftreg;
  159. end;
  160. LOC_CREGISTER:
  161. begin
  162. leftreg := left.location.register;
  163. if signed then
  164. valuereg := cg.getintregister(exprasmlist,OS_INT)
  165. else
  166. valuereg := leftreg;
  167. end;
  168. LOC_REFERENCE,LOC_CREFERENCE:
  169. begin
  170. leftreg := cg.getintregister(exprasmlist,OS_INT);
  171. valuereg := leftreg;
  172. if signed then
  173. size := OS_S32
  174. else
  175. size := OS_32;
  176. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),
  177. size,left.location.reference,leftreg);
  178. end
  179. else
  180. internalerror(200110012);
  181. end;
  182. tempreg := cg.getintregister(exprasmlist,OS_INT);
  183. exprasmlist.concat(taicpu.op_reg_const(A_LIS,tempreg,$4330));
  184. cg.a_load_reg_ref(exprasmlist,OS_32,OS_32,tempreg,ref);
  185. if signed then
  186. exprasmlist.concat(taicpu.op_reg_reg_const(A_XORIS,valuereg,
  187. { xoris expects a unsigned 16 bit int (FK) }
  188. leftreg,$8000));
  189. inc(ref.offset,4);
  190. cg.a_load_reg_ref(exprasmlist,OS_32,OS_32,valuereg,ref);
  191. dec(ref.offset,4);
  192. tmpfpureg := cg.getfpuregister(exprasmlist,OS_F64);
  193. cg.a_loadfpu_ref_reg(exprasmlist,OS_F64,tempconst.location.reference,
  194. tmpfpureg);
  195. tempconst.free;
  196. location.register := cg.getfpuregister(exprasmlist,OS_F64);
  197. cg.a_loadfpu_ref_reg(exprasmlist,OS_F64,ref,location.register);
  198. tg.ungetiftemp(exprasmlist,ref);
  199. exprasmlist.concat(taicpu.op_reg_reg_reg(A_FSUB,location.register,
  200. location.register,tmpfpureg));
  201. { work around bug in some PowerPC processors }
  202. if (tfloatdef(resulttype.def).typ = s32real) then
  203. exprasmlist.concat(taicpu.op_reg_reg(A_FRSP,location.register,
  204. location.register));
  205. end;
  206. procedure tppctypeconvnode.second_real_to_real;
  207. begin
  208. inherited second_real_to_real;
  209. { work around bug in some powerpc processors where doubles aren't }
  210. { properly converted to singles }
  211. if (tfloatdef(left.resulttype.def).typ = s64real) and
  212. (tfloatdef(resulttype.def).typ = s32real) then
  213. exprasmlist.concat(taicpu.op_reg_reg(A_FRSP,location.register,
  214. location.register));
  215. end;
  216. procedure tppctypeconvnode.second_int_to_bool;
  217. var
  218. hreg1,
  219. hreg2 : tregister;
  220. href : treference;
  221. resflags : tresflags;
  222. opsize : tcgsize;
  223. hlabel, oldtruelabel, oldfalselabel : tasmlabel;
  224. begin
  225. oldtruelabel:=truelabel;
  226. oldfalselabel:=falselabel;
  227. objectlibrary.getlabel(truelabel);
  228. objectlibrary.getlabel(falselabel);
  229. secondpass(left);
  230. if codegenerror then
  231. exit;
  232. { byte(boolean) or word(wordbool) or longint(longbool) must }
  233. { be accepted for var parameters }
  234. if (nf_explicit in flags) and
  235. (left.resulttype.def.size=resulttype.def.size) and
  236. (left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
  237. begin
  238. truelabel:=oldtruelabel;
  239. falselabel:=oldfalselabel;
  240. location_copy(location,left.location);
  241. exit;
  242. end;
  243. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def));
  244. opsize := def_cgsize(left.resulttype.def);
  245. case left.location.loc of
  246. LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER :
  247. begin
  248. if left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  249. begin
  250. hreg1:=cg.getintregister(exprasmlist,OS_INT);
  251. if left.location.size in [OS_64,OS_S64] then
  252. begin
  253. cg.a_load_ref_reg(exprasmlist,OS_INT,OS_INT,left.location.reference,hreg1);
  254. hreg2:=cg.getintregister(exprasmlist,OS_INT);
  255. href:=left.location.reference;
  256. inc(href.offset,4);
  257. cg.a_load_ref_reg(exprasmlist,OS_INT,OS_INT,href,hreg2);
  258. cg.a_op_reg_reg_reg(exprasmlist,OP_OR,OS_32,hreg1,hreg2,hreg1);
  259. end
  260. else
  261. cg.a_load_ref_reg(exprasmlist,opsize,opsize,left.location.reference,hreg1);
  262. end
  263. else
  264. begin
  265. if left.location.size in [OS_64,OS_S64] then
  266. begin
  267. hreg1:=cg.getintregister(exprasmlist,OS_32);
  268. cg.a_op_reg_reg_reg(exprasmlist,OP_OR,OS_32,left.location.register64.reghi,left.location.register64.reglo,hreg1);
  269. end
  270. else
  271. hreg1 := left.location.register;
  272. end;
  273. hreg2 := cg.getintregister(exprasmlist,OS_INT);
  274. exprasmlist.concat(taicpu.op_reg_reg_const(A_SUBIC,hreg2,hreg1,1));
  275. exprasmlist.concat(taicpu.op_reg_reg_reg(A_SUBFE,hreg1,hreg2,hreg1));
  276. end;
  277. LOC_FLAGS :
  278. begin
  279. hreg1:=cg.getintregister(exprasmlist,OS_INT);
  280. resflags:=left.location.resflags;
  281. cg.g_flags2reg(exprasmlist,location.size,resflags,hreg1);
  282. end;
  283. LOC_JUMP :
  284. begin
  285. hreg1:=cg.getintregister(exprasmlist,OS_INT);
  286. objectlibrary.getlabel(hlabel);
  287. cg.a_label(exprasmlist,truelabel);
  288. cg.a_load_const_reg(exprasmlist,OS_INT,1,hreg1);
  289. cg.a_jmp_always(exprasmlist,hlabel);
  290. cg.a_label(exprasmlist,falselabel);
  291. cg.a_load_const_reg(exprasmlist,OS_INT,0,hreg1);
  292. cg.a_label(exprasmlist,hlabel);
  293. end;
  294. else
  295. internalerror(10062);
  296. end;
  297. location.register := hreg1;
  298. truelabel:=oldtruelabel;
  299. falselabel:=oldfalselabel;
  300. end;
  301. begin
  302. ctypeconvnode:=tppctypeconvnode;
  303. end.
  304. {
  305. $Log$
  306. Revision 1.55 2004-10-31 21:45:03 peter
  307. * generic tlocation
  308. * move tlocation to cgutils
  309. Revision 1.54 2004/09/25 14:23:55 peter
  310. * ungetregister is now only used for cpuregisters, renamed to
  311. ungetcpuregister
  312. * renamed (get|unget)explicitregister(s) to ..cpuregister
  313. * removed location-release/reference_release
  314. Revision 1.53 2004/06/20 08:55:32 florian
  315. * logs truncated
  316. Revision 1.52 2004/05/19 22:26:46 jonas
  317. * fixed web bug 3103: the fpu conversion code couldn't deal with offsets
  318. outside the smallint range
  319. Revision 1.51 2004/03/17 20:06:56 jonas
  320. * fixed missing restoring of true/falselabels in case of explicit
  321. integer to same-sized boolean conversions
  322. Revision 1.50 2004/02/03 22:32:54 peter
  323. * renamed xNNbittype to xNNinttype
  324. * renamed registers32 to registersint
  325. * replace some s32bit,u32bit with torddef([su]inttype).def.typ
  326. }