njvminl.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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. function first_setlength_array: tnode;
  30. public
  31. { typecheck override to intercept handling }
  32. function pass_typecheck: tnode; override;
  33. { first pass override
  34. so that the code generator will actually generate
  35. these nodes.
  36. }
  37. (*
  38. function first_sqrt_real: tnode; override;
  39. *)
  40. function first_sqr_real: tnode; override;
  41. function first_trunc_real: tnode; override;
  42. (*
  43. function first_round_real: tnode; override;
  44. *)
  45. function first_new: tnode; override;
  46. function first_setlength: tnode; override;
  47. procedure second_length; override;
  48. (*
  49. procedure second_sqrt_real; override;
  50. procedure second_abs_real; override;
  51. *)
  52. procedure second_sqr_real; override;
  53. procedure second_trunc_real; override;
  54. (*
  55. procedure second_round_real; override;
  56. *)
  57. procedure second_new; override;
  58. procedure second_setlength; override;
  59. protected
  60. procedure load_fpu_location;
  61. end;
  62. implementation
  63. uses
  64. cutils,globals,verbose,globtype,constexp,
  65. aasmbase,aasmtai,aasmdata,aasmcpu,
  66. symtype,symconst,symdef,symsym,symtable,jvmdef,
  67. defutil,
  68. nbas,ncon,ncnv,ncal,nld,nflw,nutils,
  69. cgbase,pass_1,pass_2,
  70. cpuinfo,ncgutil,
  71. cgutils,hlcgobj,hlcgcpu;
  72. {*****************************************************************************
  73. tjvminlinenode
  74. *****************************************************************************}
  75. function tjvminlinenode.typecheck_length(var handled: boolean): tnode;
  76. begin
  77. typecheckpass(left);
  78. if is_dynamic_array(left.resultdef) or
  79. is_open_array(left.resultdef) then
  80. begin
  81. resultdef:=s32inttype;
  82. result:=nil;
  83. handled:=true;
  84. end;
  85. end;
  86. function tjvminlinenode.typecheck_high(var handled: boolean): tnode;
  87. begin
  88. typecheckpass(left);
  89. if is_dynamic_array(left.resultdef) or
  90. is_open_array(left.resultdef) then
  91. begin
  92. { replace with pred(length(arr)) }
  93. result:=cinlinenode.create(in_pred_x,false,
  94. cinlinenode.create(in_length_x,false,left));
  95. left:=nil;
  96. handled:=true;
  97. end;
  98. end;
  99. function tjvminlinenode.typecheck_new(var handled: boolean): tnode;
  100. var
  101. para: tcallparanode;
  102. elemdef: tdef;
  103. begin
  104. { normally never exists; used by the JVM backend to create new
  105. arrays because it requires special opcodes }
  106. tcallparanode(left).get_paratype;
  107. if is_dynamic_array(left.resultdef) then
  108. begin
  109. para:=tcallparanode(left);
  110. { need at least one extra parameter in addition to the
  111. array }
  112. if not assigned(para.right) then
  113. internalerror(2011012206);
  114. elemdef:=tarraydef(left.resultdef).elementdef;
  115. while elemdef.typ=arraydef do
  116. begin
  117. { if we have less length specifiers than dimensions, make
  118. the last array an array of length 0 }
  119. if not assigned(para.right) then
  120. begin
  121. para.right:=ccallparanode.create(
  122. cordconstnode.create(0,s32inttype,false),nil);
  123. tcallparanode(para.right).get_paratype;
  124. break;
  125. end
  126. else
  127. begin
  128. inserttypeconv(tcallparanode(para.right).left,s32inttype);
  129. tcallparanode(para.right).get_paratype;
  130. end;
  131. para:=tcallparanode(para.right);
  132. elemdef:=tarraydef(elemdef).elementdef;
  133. end;
  134. result:=nil;
  135. resultdef:=left.resultdef;
  136. handled:=true;
  137. end;
  138. end;
  139. function tjvminlinenode.pass_typecheck: tnode;
  140. var
  141. handled: boolean;
  142. begin
  143. handled:=false;
  144. case inlinenumber of
  145. in_length_x:
  146. begin
  147. result:=typecheck_length(handled);
  148. end;
  149. in_high_x:
  150. begin
  151. result:=typecheck_high(handled);
  152. end;
  153. in_new_x:
  154. begin
  155. result:=typecheck_new(handled);
  156. end;
  157. end;
  158. if not handled then
  159. result:=inherited pass_typecheck;
  160. end;
  161. (*
  162. function tjvminlinenode.first_sqrt_real : tnode;
  163. begin
  164. if (current_settings.cputype >= cpu_PPC970) then
  165. begin
  166. expectloc:=LOC_FPUREGISTER;
  167. first_sqrt_real := nil;
  168. end
  169. else
  170. result:=inherited first_sqrt_real;
  171. end;
  172. *)
  173. function tjvminlinenode.first_sqr_real : tnode;
  174. begin
  175. expectloc:=LOC_FPUREGISTER;
  176. first_sqr_real:=nil;
  177. end;
  178. function tjvminlinenode.first_trunc_real : tnode;
  179. begin
  180. expectloc:=LOC_REGISTER;
  181. first_trunc_real:=nil;
  182. end;
  183. function tjvminlinenode.first_new: tnode;
  184. begin
  185. { skip the array; it's a type node }
  186. tcallparanode(tcallparanode(left).right).firstcallparan;
  187. expectloc:=LOC_REGISTER;
  188. result:=nil;
  189. end;
  190. function tjvminlinenode.first_setlength_array: tnode;
  191. var
  192. assignmenttarget,
  193. ppn,
  194. newparas: tnode;
  195. newnode: tnode;
  196. eledef,
  197. objarraydef: tdef;
  198. ndims: longint;
  199. finaltype: char;
  200. setlenroutine: string;
  201. lefttemp: ttempcreatenode;
  202. newblock: tblocknode;
  203. newstatement: tstatementnode;
  204. primitive: boolean;
  205. begin
  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. function tjvminlinenode.first_setlength: tnode;
  304. begin
  305. { reverse the parameter order so we can process them more easily }
  306. left:=reverseparameters(tcallparanode(left));
  307. { treat setlength(x,0) specially: used to init uninitialised locations }
  308. if not assigned(tcallparanode(tcallparanode(left).right).right) and
  309. is_constintnode(tcallparanode(tcallparanode(left).right).left) and
  310. (tordconstnode(tcallparanode(tcallparanode(left).right).left).value=0) then
  311. begin
  312. result:=nil;
  313. expectloc:=LOC_VOID;
  314. exit;
  315. end;
  316. case left.resultdef.typ of
  317. arraydef:
  318. result:=first_setlength_array;
  319. else
  320. internalerror(2011031204);
  321. end;
  322. end;
  323. procedure tjvminlinenode.second_length;
  324. begin
  325. if is_dynamic_array(left.resultdef) or
  326. is_open_array(left.resultdef) then
  327. begin
  328. location_reset(location,LOC_REGISTER,OS_S32);
  329. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s32inttype);
  330. secondpass(left);
  331. thlcgjvm(hlcg).g_getarraylen(current_asmdata.CurrAsmList,left.location);
  332. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  333. end
  334. else
  335. internalerror(2011012004);
  336. end;
  337. (*
  338. function tjvminlinenode.first_round_real : tnode;
  339. begin
  340. if (current_settings.cputype >= cpu_PPC970) then
  341. begin
  342. expectloc:=LOC_REFERENCE;
  343. first_round_real := nil;
  344. end
  345. else
  346. result:=inherited first_round_real;
  347. end;
  348. *)
  349. { load the FPU value on the evaluation stack }
  350. procedure tjvminlinenode.load_fpu_location;
  351. begin
  352. secondpass(left);
  353. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  354. end;
  355. (*
  356. procedure tjvminlinenode.second_sqrt_real;
  357. begin
  358. if (current_settings.cputype < cpu_PPC970) then
  359. internalerror(2007020910);
  360. location.loc:=LOC_FPUREGISTER;
  361. load_fpu_location;
  362. case left.location.size of
  363. OS_F32:
  364. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRTS,location.register,
  365. left.location.register));
  366. OS_F64:
  367. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT,location.register,
  368. left.location.register));
  369. else
  370. inherited;
  371. end;
  372. end;
  373. *)
  374. procedure tjvminlinenode.second_sqr_real;
  375. begin
  376. load_fpu_location;
  377. location_reset(location,LOC_FPUREGISTER,location.size);
  378. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  379. case left.location.size of
  380. OS_F32:
  381. begin
  382. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  383. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  384. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_fmul));
  385. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  386. end;
  387. OS_F64:
  388. begin
  389. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup2));
  390. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  391. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dmul));
  392. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  393. end;
  394. else
  395. internalerror(2011010804);
  396. end;
  397. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  398. end;
  399. procedure tjvminlinenode.second_trunc_real;
  400. begin
  401. load_fpu_location;
  402. location_reset(location,LOC_REGISTER,left.location.size);
  403. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  404. case left.location.size of
  405. OS_F32:
  406. begin
  407. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_f2l));
  408. { 32 bit float -> 64 bit int: +1 stack slot }
  409. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  410. end;
  411. OS_F64:
  412. begin
  413. { 64 bit float -> 64 bit int: same number of stack slots }
  414. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_d2l));
  415. end;
  416. else
  417. internalerror(2011010805);
  418. end;
  419. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  420. end;
  421. procedure tjvminlinenode.second_new;
  422. var
  423. arr: tnode;
  424. hp: tcallparanode;
  425. paracount: longint;
  426. begin
  427. hp:=tcallparanode(left);
  428. { we don't second pass this one, it's only a type node }
  429. arr:=hp.left;
  430. if not is_dynamic_array(arr.resultdef) then
  431. internalerror(2011012204);
  432. hp:=tcallparanode(hp.right);
  433. if not assigned(hp) then
  434. internalerror(2011012205);
  435. paracount:=0;
  436. { put all the dimensions on the stack }
  437. repeat
  438. inc(paracount);
  439. secondpass(hp.left);
  440. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,hp.left.resultdef,hp.left.location);
  441. hp:=tcallparanode(hp.right);
  442. until not assigned(hp);
  443. { create the array }
  444. thlcgjvm(hlcg).g_newarray(current_asmdata.CurrAsmList,arr.resultdef,paracount);
  445. location_reset(location,LOC_REGISTER,OS_ADDR);
  446. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  447. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,arr.resultdef,location.register);
  448. end;
  449. procedure tjvminlinenode.second_setlength;
  450. var
  451. target: tnode;
  452. lenpara: tnode;
  453. begin
  454. target:=tcallparanode(left).left;
  455. lenpara:=tcallparanode(tcallparanode(left).right).left;
  456. if assigned(tcallparanode(tcallparanode(left).right).right) or
  457. not is_constintnode(lenpara) or
  458. (tordconstnode(lenpara).value<>0) then
  459. internalerror(2011031801);
  460. secondpass(target);
  461. if is_dynamic_array(target.resultdef) then
  462. begin
  463. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,0,R_INTREGISTER);
  464. thlcgjvm(hlcg).g_newarray(current_asmdata.CurrAsmList,target.resultdef,1);
  465. end
  466. else
  467. internalerror(2011031401);
  468. thlcgjvm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,target.resultdef,target.location);
  469. end;
  470. begin
  471. cinlinenode:=tjvminlinenode;
  472. end.