nppccnv.pas 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate PowerPC assembler for type converting nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nppccnv;
  18. {$I fpcdefs.inc}
  19. interface
  20. uses
  21. node, ncnv, ncgcnv, ngppccnv;
  22. type
  23. tppctypeconvnode = class(tgenppctypeconvnode)
  24. protected
  25. { procedure second_int_to_int;override; }
  26. { procedure second_string_to_string;override; }
  27. { procedure second_cstring_to_pchar;override; }
  28. { procedure second_string_to_chararray;override; }
  29. { procedure second_array_to_pointer;override; }
  30. function first_int_to_real: tnode; 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. end;
  46. implementation
  47. uses
  48. verbose, globtype, globals, systems,
  49. symconst, symdef, aasmbase, aasmtai,aasmdata,
  50. defutil, symcpu,
  51. cgbase, cgutils, pass_1, pass_2,
  52. ncon, ncal,procinfo,
  53. ncgutil,
  54. cpubase, aasmcpu,
  55. rgobj, tgobj, cgobj, hlcgobj;
  56. {*****************************************************************************
  57. FirstTypeConv
  58. *****************************************************************************}
  59. function tppctypeconvnode.first_int_to_real: tnode;
  60. begin
  61. if (is_currency(left.resultdef)) then begin
  62. // hack to avoid double division by 10000, as it's
  63. // already done by typecheckpass.resultdef_int_to_real
  64. left.resultdef := s64inttype;
  65. end else begin
  66. // everything that is less than 64 bits is converted to a 64 bit signed
  67. // integer - because the int_to_real conversion is faster for 64 bit
  68. // signed ints compared to 64 bit unsigned ints.
  69. if (not (torddef(left.resultdef).ordtype in [s64bit, u64bit, scurrency])) then begin
  70. inserttypeconv(left, s64inttype);
  71. end;
  72. end;
  73. firstpass(left);
  74. result := nil;
  75. expectloc := LOC_FPUREGISTER;
  76. end;
  77. {*****************************************************************************
  78. SecondTypeConv
  79. *****************************************************************************}
  80. procedure tppctypeconvnode.second_int_to_real;
  81. const
  82. convconst : double = $100000000;
  83. var
  84. tempconst : tnode;
  85. disp, disp2: treference;
  86. // temp registers for converting signed ints
  87. valuereg, leftreg,
  88. // additional temp registers for converting unsigned 64 bit ints
  89. tmpintreg1, tmpintreg2, tmpfpureg, tmpfpuconst : tregister;
  90. size: tcgsize;
  91. signed: boolean;
  92. begin
  93. location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
  94. reference_reset(disp2,0,[]);
  95. tempconst:=nil;
  96. { the code here comes from the PowerPC Compiler Writer's Guide }
  97. { * longint to double (works for all rounding modes) }
  98. { std R3,disp(R1) # store doubleword }
  99. { lfd FR1,disp(R1) # load float double }
  100. { fcfid FR1,FR1 # convert to floating-point integer }
  101. { * unsigned 64 bit int to fp value (works for all rounding modes) }
  102. { rldicl rT1,rS,32,32 # isolate high half }
  103. { rldicl rT2,rS,0,32 # isolate low half }
  104. { std rT1,disp(R1) # store high half }
  105. { std rT2,disp+8(R1) # store low half }
  106. { lfd frT1,disp(R1) # load high half }
  107. { lfd frD,disp+8(R1) # load low half }
  108. { fcfid frT1,frT1 # convert each half to floating }
  109. { fcfid frD,frD # point integer (no round) }
  110. { fmadd frD,frC,frT1,frD # (2^32)*high + low }
  111. { # (only add can round) }
  112. tg.Gettemp(current_asmdata.CurrAsmList, 8, 8, tt_normal, disp);
  113. { do the signed case for everything but 64 bit unsigned integers }
  114. signed := (left.location.size <> OS_64);
  115. { we need a certain constant for the conversion of unsigned 64 bit integers,
  116. so create them here. Additonally another temporary location is neeted }
  117. if (not signed) then begin
  118. // allocate temp for constant value used for unsigned 64 bit ints
  119. tempconst :=
  120. crealconstnode.create(convconst, pbestrealtype^);
  121. typecheckpass(tempconst);
  122. firstpass(tempconst);
  123. secondpass(tempconst);
  124. if (tempconst.location.loc <> LOC_CREFERENCE) then
  125. internalerror(200110011);
  126. // allocate second temp memory
  127. tg.Gettemp(current_asmdata.CurrAsmList, 8, 8, tt_normal, disp2);
  128. end;
  129. if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE]) then
  130. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
  131. case left.location.loc of
  132. // the conversion algorithm does not modify the input register, so it can
  133. // be used for both LOC_REGISTER and LOC_CREGISTER
  134. LOC_REGISTER, LOC_CREGISTER:
  135. begin
  136. leftreg := left.location.register;
  137. valuereg := leftreg;
  138. end;
  139. LOC_REFERENCE, LOC_CREFERENCE:
  140. begin
  141. leftreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  142. valuereg := leftreg;
  143. if signed then
  144. size := OS_S64
  145. else
  146. size := OS_64;
  147. cg.a_load_ref_reg(current_asmdata.CurrAsmList, def_cgsize(left.resultdef),
  148. size, left.location.reference, leftreg);
  149. end
  150. else
  151. internalerror(200110012);
  152. end;
  153. if (signed) then begin
  154. // std rS, disp(r1)
  155. cg.a_load_reg_ref(current_asmdata.CurrAsmList, OS_S64, OS_S64, valuereg, disp);
  156. // lfd frD, disp(r1)
  157. location.register := cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64);
  158. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,OS_F64, OS_F64, disp, location.register);
  159. // fcfid frD, frD
  160. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCFID, location.register,
  161. location.register));
  162. end else begin
  163. { ts:todo use TOC for this constant or at least schedule better }
  164. // lfd frC, const
  165. tmpfpuconst := cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64);
  166. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,OS_F64,OS_F64,tempconst.location.reference,
  167. tmpfpuconst);
  168. tempconst.free;
  169. tmpintreg1 := cg.getintregister(current_asmdata.CurrAsmList, OS_64);
  170. // rldicl rT1, rS, 32, 32
  171. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const_const(A_RLDICL, tmpintreg1, valuereg, 32, 32));
  172. // rldicl rT2, rS, 0, 32
  173. tmpintreg2 := cg.getintregister(current_asmdata.CurrAsmList, OS_64);
  174. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const_const(A_RLDICL, tmpintreg2, valuereg, 0, 32));
  175. // std rT1, disp(r1)
  176. cg.a_load_reg_ref(current_asmdata.CurrAsmList, OS_S64, OS_S64, tmpintreg1, disp);
  177. // std rT2, disp2(r1)
  178. cg.a_load_reg_ref(current_asmdata.CurrAsmList, OS_S64, OS_S64, tmpintreg2, disp2);
  179. // lfd frT1, disp(R1)
  180. tmpfpureg := cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64);
  181. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,OS_F64, OS_F64, disp, tmpfpureg);
  182. // lfd frD, disp+8(R1)
  183. location.register := cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64);
  184. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,OS_F64, OS_F64, disp2, location.register);
  185. // fcfid frT1, frT1
  186. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCFID, tmpfpureg,
  187. tmpfpureg));
  188. // fcfid frD, frD
  189. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCFID, location.register,
  190. location.register));
  191. // fmadd frD,frC,frT1,frD # (2^32)*high + low }
  192. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_FMADD, location.register, tmpfpuconst,
  193. tmpfpureg, location.register));
  194. // free used temps
  195. tg.ungetiftemp(current_asmdata.CurrAsmList, disp2);
  196. end;
  197. // free reference
  198. tg.ungetiftemp(current_asmdata.CurrAsmList, disp);
  199. // make sure the precision is correct
  200. if (tfloatdef(resultdef).floattype = s32real) then
  201. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRSP,location.register,
  202. location.register));
  203. end;
  204. begin
  205. ctypeconvnode := tppctypeconvnode;
  206. end.