njvminl.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. {
  2. Copyright (c) 1998-2011 by Florian Klaempfl and Jonas Maebe
  3. Generate JVM inline 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 njvminl;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,
  22. node,ninl,ncginl;
  23. type
  24. tjvminlinenode = class(tcginlinenode)
  25. protected
  26. function typecheck_length(var handled: boolean): tnode;
  27. function typecheck_high(var handled: boolean): tnode;
  28. function typecheck_new(var handled: boolean): tnode;
  29. public
  30. { typecheck override to intercept handling }
  31. function pass_typecheck: tnode; override;
  32. { first pass override
  33. so that the code generator will actually generate
  34. these nodes.
  35. }
  36. (*
  37. function first_sqrt_real: tnode; override;
  38. *)
  39. function first_sqr_real: tnode; override;
  40. function first_trunc_real: tnode; override;
  41. (*
  42. function first_round_real: tnode; override;
  43. *)
  44. function first_new: tnode; override;
  45. function first_setlength: tnode; override;
  46. procedure second_length; override;
  47. (*
  48. procedure second_sqrt_real; override;
  49. procedure second_abs_real; override;
  50. *)
  51. procedure second_sqr_real; override;
  52. procedure second_trunc_real; override;
  53. (*
  54. procedure second_round_real; override;
  55. *)
  56. procedure second_new; override;
  57. protected
  58. procedure load_fpu_location;
  59. end;
  60. implementation
  61. uses
  62. cutils,globals,verbose,globtype,constexp,
  63. aasmbase,aasmtai,aasmdata,aasmcpu,
  64. symtype,symconst,symdef,symtable,jvmdef,
  65. defutil,
  66. nbas,ncon,ncnv,ncal,nld,
  67. cgbase,pass_1,pass_2,
  68. cpuinfo,ncgutil,
  69. cgutils,hlcgobj,hlcgcpu;
  70. {*****************************************************************************
  71. tjvminlinenode
  72. *****************************************************************************}
  73. function tjvminlinenode.typecheck_length(var handled: boolean): tnode;
  74. begin
  75. typecheckpass(left);
  76. if is_dynamic_array(left.resultdef) or
  77. is_open_array(left.resultdef) then
  78. begin
  79. resultdef:=s32inttype;
  80. result:=nil;
  81. handled:=true;
  82. end;
  83. end;
  84. function tjvminlinenode.typecheck_high(var handled: boolean): tnode;
  85. begin
  86. typecheckpass(left);
  87. if is_dynamic_array(left.resultdef) or
  88. is_open_array(left.resultdef) then
  89. begin
  90. { replace with pred(length(arr)) }
  91. result:=cinlinenode.create(in_pred_x,false,
  92. cinlinenode.create(in_length_x,false,left));
  93. left:=nil;
  94. handled:=true;
  95. end;
  96. end;
  97. function tjvminlinenode.typecheck_new(var handled: boolean): tnode;
  98. var
  99. para: tcallparanode;
  100. elemdef: tdef;
  101. begin
  102. { normally never exists; used by the JVM backend to create new
  103. arrays because it requires special opcodes }
  104. tcallparanode(left).get_paratype;
  105. if is_dynamic_array(left.resultdef) then
  106. begin
  107. para:=tcallparanode(left);
  108. { need at least one extra parameter in addition to the
  109. array }
  110. if not assigned(para.right) then
  111. internalerror(2011012206);
  112. elemdef:=tarraydef(left.resultdef).elementdef;
  113. while elemdef.typ=arraydef do
  114. begin
  115. { if we have less length specifiers than dimensions, make
  116. the last array an array of length 0 }
  117. if not assigned(para.right) then
  118. begin
  119. para.right:=ccallparanode.create(
  120. cordconstnode.create(0,s32inttype,false),nil);
  121. tcallparanode(para.right).get_paratype;
  122. break;
  123. end
  124. else
  125. begin
  126. inserttypeconv(tcallparanode(para.right).left,s32inttype);
  127. tcallparanode(para.right).get_paratype;
  128. end;
  129. para:=tcallparanode(para.right);
  130. elemdef:=tarraydef(elemdef).elementdef;
  131. end;
  132. result:=nil;
  133. resultdef:=left.resultdef;
  134. handled:=true;
  135. end;
  136. end;
  137. function tjvminlinenode.pass_typecheck: tnode;
  138. var
  139. handled: boolean;
  140. begin
  141. handled:=false;
  142. case inlinenumber of
  143. in_length_x:
  144. begin
  145. result:=typecheck_length(handled);
  146. end;
  147. in_high_x:
  148. begin
  149. result:=typecheck_high(handled);
  150. end;
  151. in_new_x:
  152. begin
  153. result:=typecheck_new(handled);
  154. end;
  155. end;
  156. if not handled then
  157. result:=inherited pass_typecheck;
  158. end;
  159. (*
  160. function tjvminlinenode.first_sqrt_real : tnode;
  161. begin
  162. if (current_settings.cputype >= cpu_PPC970) then
  163. begin
  164. expectloc:=LOC_FPUREGISTER;
  165. first_sqrt_real := nil;
  166. end
  167. else
  168. result:=inherited first_sqrt_real;
  169. end;
  170. *)
  171. function tjvminlinenode.first_sqr_real : tnode;
  172. begin
  173. expectloc:=LOC_FPUREGISTER;
  174. first_sqr_real:=nil;
  175. end;
  176. function tjvminlinenode.first_trunc_real : tnode;
  177. begin
  178. expectloc:=LOC_REGISTER;
  179. first_trunc_real:=nil;
  180. end;
  181. function tjvminlinenode.first_new: tnode;
  182. begin
  183. { skip the array; it's a type node }
  184. tcallparanode(tcallparanode(left).right).firstcallparan;
  185. expectloc:=LOC_REGISTER;
  186. result:=nil;
  187. end;
  188. function tjvminlinenode.first_setlength: tnode;
  189. var
  190. assignmenttarget,
  191. ppn,
  192. newparas: tnode;
  193. newnode: tnode;
  194. eledef,
  195. objarraydef: tdef;
  196. ndims: longint;
  197. finaltype: char;
  198. setlenroutine: string;
  199. lefttemp: ttempcreatenode;
  200. newblock: tblocknode;
  201. newstatement: tstatementnode;
  202. primitive: boolean;
  203. begin
  204. { reverse the parameter order so we can process them more easily }
  205. left:=reverseparameters(tcallparanode(left));
  206. { first parameter is the array, the rest are the dimensions }
  207. newparas:=tcallparanode(left).right;
  208. tcallparanode(left).right:=nil;
  209. { count the number of specified dimensions, and determine the type of
  210. the final one }
  211. ppn:=newparas;
  212. eledef:=tarraydef(left.resultdef).elementdef;
  213. { ppn already points to the first dimension }
  214. ndims:=1;
  215. while assigned(tcallparanode(ppn).right) do
  216. begin
  217. inc(ndims);
  218. eledef:=tarraydef(eledef).elementdef;
  219. ppn:=tcallparanode(ppn).right;
  220. end;
  221. { in case it's a dynamic array of static arrays, we must also allocate
  222. the static arrays! }
  223. while (eledef.typ=arraydef) and
  224. not is_dynamic_array(eledef) do
  225. begin
  226. inc(ndims);
  227. tcallparanode(ppn).right:=
  228. ccallparanode.create(
  229. genintconstnode(tarraydef(eledef).elecount),nil);
  230. ppn:=tcallparanode(ppn).right;
  231. eledef:=tarraydef(eledef).elementdef;
  232. end;
  233. { prepend type parameter for the array }
  234. newparas:=ccallparanode.create(ctypenode.create(left.resultdef),newparas);
  235. ttypenode(tcallparanode(newparas).left).allowed:=true;
  236. { node to create the new array }
  237. newnode:=cinlinenode.create(in_new_x,false,newparas);
  238. { Common parameters for setlength helper }
  239. { start with org (save assignmenttarget itself to assign the result back to) }
  240. { store left into a temp in case it may contain a function call
  241. (which must not be evaluated twice) }
  242. lefttemp:=maybereplacewithtempref(tcallparanode(left).left,tcallparanode(left).left.resultdef.size,false);
  243. if assigned(lefttemp) then
  244. begin
  245. newblock:=internalstatements(newstatement);
  246. addstatement(newstatement,lefttemp);
  247. assignmenttarget:=ctemprefnode.create(lefttemp);
  248. typecheckpass(tnode(assignmenttarget));
  249. end
  250. else
  251. assignmenttarget:=tcallparanode(left).left.getcopy;
  252. newparas:=left;
  253. left:=nil;
  254. { if more than 1 dimension, or if 1 dimention of a non-primitive type,
  255. typecast to generic array of tobject }
  256. setlenroutine:=jvmarrtype(eledef,primitive);
  257. if (ndims>1) or
  258. not primitive then
  259. begin
  260. objarraydef:=search_system_type('TJOBJECTARRAY').typedef;
  261. tcallparanode(newparas).left:=ctypeconvnode.create_explicit(tcallparanode(newparas).left,objarraydef);
  262. newnode:=ctypeconvnode.create_explicit(newnode,objarraydef);
  263. end;
  264. { prepend new }
  265. newparas:=ccallparanode.create(newnode,newparas);
  266. { prepend deepcopy }
  267. newparas:=ccallparanode.create(cordconstnode.create(0,pasbool8type,false),newparas);
  268. { call the right setlenght helper }
  269. if ndims>1 then
  270. begin
  271. finaltype:=jvmarrtype_setlength(eledef);
  272. setlenroutine:='FPC_SETLENGTH_DYNARR_MULTIDIM';
  273. { create proper parameters, from right to left:
  274. eletype=finaltype, ndim=ndims, deepcopy=false, new=newnode,
  275. assignmenttarget=tcallparanode(left).left }
  276. { prepend ndim }
  277. newparas:=ccallparanode.create(cordconstnode.create(ndims,s32inttype,false),newparas);
  278. { prepend eletype }
  279. newparas:=ccallparanode.create(cordconstnode.create(ord(finaltype),cwidechartype,false),newparas);
  280. end
  281. else
  282. begin
  283. if not primitive then
  284. setlenroutine:='OBJECT'
  285. else
  286. uppervar(setlenroutine);
  287. setlenroutine:='FPC_SETLENGTH_DYNARR_J'+setlenroutine;
  288. { create proper parameters, from right to left:
  289. deepcopy=false, new=newnode, assignmenttarget=tcallparnode(left).left
  290. -> already done in common part above }
  291. end;
  292. result:=ccallnode.createintern(setlenroutine,newparas);
  293. { assign result back to org (no call-by-reference for Java) }
  294. result:=cassignmentnode.create(assignmenttarget,
  295. ctypeconvnode.create_explicit(result,assignmenttarget.resultdef));
  296. if assigned(lefttemp) then
  297. begin
  298. addstatement(newstatement,result);
  299. addstatement(newstatement,ctempdeletenode.create(lefttemp));
  300. result:=newblock;
  301. end;
  302. end;
  303. procedure tjvminlinenode.second_length;
  304. begin
  305. if is_dynamic_array(left.resultdef) or
  306. is_open_array(left.resultdef) then
  307. begin
  308. location_reset(location,LOC_REGISTER,OS_S32);
  309. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s32inttype);
  310. secondpass(left);
  311. thlcgjvm(hlcg).g_getarraylen(current_asmdata.CurrAsmList,left.location);
  312. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  313. end
  314. else
  315. internalerror(2011012004);
  316. end;
  317. (*
  318. function tjvminlinenode.first_round_real : tnode;
  319. begin
  320. if (current_settings.cputype >= cpu_PPC970) then
  321. begin
  322. expectloc:=LOC_REFERENCE;
  323. first_round_real := nil;
  324. end
  325. else
  326. result:=inherited first_round_real;
  327. end;
  328. *)
  329. { load the FPU value on the evaluation stack }
  330. procedure tjvminlinenode.load_fpu_location;
  331. begin
  332. secondpass(left);
  333. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  334. end;
  335. (*
  336. procedure tjvminlinenode.second_sqrt_real;
  337. begin
  338. if (current_settings.cputype < cpu_PPC970) then
  339. internalerror(2007020910);
  340. location.loc:=LOC_FPUREGISTER;
  341. load_fpu_location;
  342. case left.location.size of
  343. OS_F32:
  344. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRTS,location.register,
  345. left.location.register));
  346. OS_F64:
  347. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT,location.register,
  348. left.location.register));
  349. else
  350. inherited;
  351. end;
  352. end;
  353. *)
  354. procedure tjvminlinenode.second_sqr_real;
  355. begin
  356. load_fpu_location;
  357. location_reset(location,LOC_FPUREGISTER,location.size);
  358. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  359. case left.location.size of
  360. OS_F32:
  361. begin
  362. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  363. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  364. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_fmul));
  365. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  366. end;
  367. OS_F64:
  368. begin
  369. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup2));
  370. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  371. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dmul));
  372. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  373. end;
  374. else
  375. internalerror(2011010804);
  376. end;
  377. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  378. end;
  379. procedure tjvminlinenode.second_trunc_real;
  380. begin
  381. load_fpu_location;
  382. location_reset(location,LOC_REGISTER,left.location.size);
  383. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  384. case left.location.size of
  385. OS_F32:
  386. begin
  387. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_f2l));
  388. { 32 bit float -> 64 bit int: +1 stack slot }
  389. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  390. end;
  391. OS_F64:
  392. begin
  393. { 64 bit float -> 64 bit int: same number of stack slots }
  394. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_d2l));
  395. end;
  396. else
  397. internalerror(2011010805);
  398. end;
  399. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  400. end;
  401. procedure tjvminlinenode.second_new;
  402. var
  403. arr: tnode;
  404. hp: tcallparanode;
  405. paracount: longint;
  406. begin
  407. hp:=tcallparanode(left);
  408. { we don't second pass this one, it's only a type node }
  409. arr:=hp.left;
  410. if not is_dynamic_array(arr.resultdef) then
  411. internalerror(2011012204);
  412. hp:=tcallparanode(hp.right);
  413. if not assigned(hp) then
  414. internalerror(2011012205);
  415. paracount:=0;
  416. { put all the dimensions on the stack }
  417. repeat
  418. inc(paracount);
  419. secondpass(hp.left);
  420. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,hp.left.resultdef,hp.left.location);
  421. hp:=tcallparanode(hp.right);
  422. until not assigned(hp);
  423. { create the array }
  424. thlcgjvm(hlcg).g_newarray(current_asmdata.CurrAsmList,arr.resultdef,paracount);
  425. location_reset(location,LOC_REGISTER,OS_ADDR);
  426. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  427. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,arr.resultdef,location.register);
  428. end;
  429. begin
  430. cinlinenode:=tjvminlinenode;
  431. end.