nppcmem.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Jonas Maebe
  4. Generate PowerPC assembler for in memory related 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 nppcmem;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nmem,ncgmem;
  23. type
  24. tppcvecnode = class(tcgvecnode)
  25. procedure pass_2;override;
  26. end;
  27. implementation
  28. uses
  29. {$ifdef delphi}
  30. sysutils,
  31. {$endif}
  32. globtype,systems,
  33. cutils,verbose,globals,
  34. symconst,symtype,symdef,symsym,symtable,defbase,paramgr,
  35. aasmbase,aasmtai,aasmcpu,
  36. cginfo,cgbase,pass_2,
  37. pass_1,nld,ncon,nadd,
  38. cpubase,
  39. cgobj,tgobj,rgobj,ncgutil;
  40. {*****************************************************************************
  41. TPPCVECNODE
  42. *****************************************************************************}
  43. procedure tppcvecnode.pass_2;
  44. var
  45. extraoffset : longint;
  46. { rl stores the resulttype.def of the left node, this is necessary }
  47. { to detect if it is an ansistring }
  48. { because in constant nodes which constant index }
  49. { the left tree is removed }
  50. t : tnode;
  51. href : treference;
  52. srsym : tsym;
  53. pushed : tpushedsaved;
  54. hightree : tnode;
  55. isjump : boolean;
  56. otl,ofl : tasmlabel;
  57. newsize : tcgsize;
  58. pushedregs : tmaybesave;
  59. begin
  60. newsize:=def_cgsize(resulttype.def);
  61. location_reset(location,LOC_REFERENCE,newsize);
  62. secondpass(left);
  63. { we load the array reference to location }
  64. { an ansistring needs to be dereferenced }
  65. if is_ansistring(left.resulttype.def) or
  66. is_widestring(left.resulttype.def) then
  67. begin
  68. if nf_callunique in flags then
  69. begin
  70. if left.location.loc<>LOC_REFERENCE then
  71. begin
  72. CGMessage(cg_e_illegal_expression);
  73. exit;
  74. end;
  75. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  76. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(1));
  77. rg.saveregvars(exprasmlist,all_registers);
  78. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_UNIQUE');
  79. cg.g_maybe_loadself(exprasmlist);
  80. rg.restoreusedregisters(exprasmlist,pushed);
  81. end;
  82. case left.location.loc of
  83. LOC_REGISTER,
  84. LOC_CREGISTER :
  85. location.reference.base:=left.location.register;
  86. LOC_CREFERENCE,
  87. LOC_REFERENCE :
  88. begin
  89. location_release(exprasmlist,left.location);
  90. location.reference.base:=rg.getregisterint(exprasmlist);
  91. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.reference.base);
  92. end;
  93. else
  94. internalerror(2002032218);
  95. end;
  96. { check for a zero length string,
  97. we can use the ansistring routine here }
  98. if (cs_check_range in aktlocalswitches) then
  99. begin
  100. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  101. cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,paramanager.getintparaloc(1));
  102. rg.saveregvars(exprasmlist,all_registers);
  103. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO');
  104. cg.g_maybe_loadself(exprasmlist);
  105. rg.restoreusedregisters(exprasmlist,pushed);
  106. end;
  107. { in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
  108. if is_ansistring(left.resulttype.def) then
  109. dec(location.reference.offset)
  110. else
  111. dec(location.reference.offset,2);
  112. { we've also to keep left up-to-date, because it is used }
  113. { if a constant array index occurs, subject to change (FK) }
  114. location_copy(left.location,location);
  115. end
  116. else if is_dynamic_array(left.resulttype.def) then
  117. { ... also a dynamic string }
  118. begin
  119. case left.location.loc of
  120. LOC_REGISTER,
  121. LOC_CREGISTER :
  122. location.reference.base:=left.location.register;
  123. LOC_REFERENCE,
  124. LOC_CREFERENCE :
  125. begin
  126. location_release(exprasmlist,left.location);
  127. location.reference.base:=rg.getaddressregister(exprasmlist);
  128. cg.a_load_ref_reg(exprasmlist,OS_ADDR,
  129. left.location.reference,location.reference.base);
  130. end;
  131. else
  132. internalerror(2002032219);
  133. end;
  134. {$warning FIXME}
  135. { check for a zero length string,
  136. we can use the ansistring routine here }
  137. if (cs_check_range in aktlocalswitches) then
  138. begin
  139. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  140. cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,paramanager.getintparaloc(1));
  141. rg.saveregvars(exprasmlist,all_registers);
  142. cg.a_call_name(exprasmlist,'FPC_ANSISTR_CHECKZERO');
  143. cg.g_maybe_loadself(exprasmlist);
  144. rg.restoreusedregisters(exprasmlist,pushed);
  145. end;
  146. { we've also to keep left up-to-date, because it is used }
  147. { if a constant array index occurs, subject to change (FK) }
  148. location_copy(left.location,location);
  149. end
  150. else
  151. location_copy(location,left.location);
  152. { offset can only differ from 0 if arraydef }
  153. if (left.resulttype.def.deftype=arraydef) and
  154. not(is_dynamic_array(left.resulttype.def)) then
  155. dec(location.reference.offset,
  156. get_mul_size*tarraydef(left.resulttype.def).lowrange);
  157. if right.nodetype=ordconstn then
  158. begin
  159. { offset can only differ from 0 if arraydef }
  160. if (left.resulttype.def.deftype=arraydef) then
  161. begin
  162. if not(is_open_array(left.resulttype.def)) and
  163. not(is_array_of_const(left.resulttype.def)) and
  164. not(is_dynamic_array(left.resulttype.def)) then
  165. begin
  166. if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or
  167. (tordconstnode(right).value<tarraydef(left.resulttype.def).lowrange) then
  168. begin
  169. { this should be caught in the resulttypepass! (JM) }
  170. if (cs_check_range in aktlocalswitches) then
  171. CGMessage(parser_e_range_check_error)
  172. else
  173. CGMessage(parser_w_range_check_error);
  174. end;
  175. dec(left.location.reference.offset,
  176. get_mul_size*tarraydef(left.resulttype.def).lowrange);
  177. end
  178. else
  179. begin
  180. { range checking for open and dynamic arrays !!!! }
  181. {$warning FIXME}
  182. {!!!!!!!!!!!!!!!!!}
  183. end;
  184. end
  185. else if (left.resulttype.def.deftype=stringdef) then
  186. begin
  187. if (tordconstnode(right).value=0) and
  188. not(is_shortstring(left.resulttype.def)) then
  189. { this should be caught in the resulttypepass! (JM) }
  190. CGMessage(cg_e_can_access_element_zero);
  191. if (cs_check_range in aktlocalswitches) then
  192. begin
  193. case tstringdef(left.resulttype.def).string_typ of
  194. { it's the same for ansi- and wide strings }
  195. st_widestring,
  196. st_ansistring:
  197. begin
  198. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  199. cg.a_param_const(exprasmlist,OS_INT,tordconstnode(right).value,paramanager.getintparaloc(2));
  200. href:=location.reference;
  201. dec(href.offset,7);
  202. cg.a_param_ref(exprasmlist,OS_INT,href,paramanager.getintparaloc(1));
  203. rg.saveregvars(exprasmlist,all_registers);
  204. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  205. rg.restoreusedregisters(exprasmlist,pushed);
  206. cg.g_maybe_loadself(exprasmlist);
  207. end;
  208. st_shortstring:
  209. begin
  210. {!!!!!!!!!!!!!!!!!}
  211. end;
  212. st_longstring:
  213. begin
  214. {!!!!!!!!!!!!!!!!!}
  215. end;
  216. end;
  217. end;
  218. end;
  219. inc(left.location.reference.offset,
  220. get_mul_size*tordconstnode(right).value);
  221. location_copy(location,left.location);
  222. end
  223. else
  224. { not nodetype=ordconstn }
  225. begin
  226. if (cs_regalloc in aktglobalswitches) and
  227. { if we do range checking, we don't }
  228. { need that fancy code (it would be }
  229. { buggy) }
  230. not(cs_check_range in aktlocalswitches) and
  231. (left.resulttype.def.deftype=arraydef) then
  232. begin
  233. extraoffset:=0;
  234. if (right.nodetype=addn) then
  235. begin
  236. if taddnode(right).right.nodetype=ordconstn then
  237. begin
  238. extraoffset:=tordconstnode(taddnode(right).right).value;
  239. t:=taddnode(right).left;
  240. { First pass processed this with the assumption }
  241. { that there was an add node which may require an }
  242. { extra register. Fake it or die with IE10 (JM) }
  243. t.registers32 := taddnode(right).registers32;
  244. taddnode(right).left:=nil;
  245. right.free;
  246. right:=t;
  247. end
  248. else if taddnode(right).left.nodetype=ordconstn then
  249. begin
  250. extraoffset:=tordconstnode(taddnode(right).left).value;
  251. t:=taddnode(right).right;
  252. t.registers32 := right.registers32;
  253. taddnode(right).right:=nil;
  254. right.free;
  255. right:=t;
  256. end;
  257. end
  258. else if (right.nodetype=subn) then
  259. begin
  260. if taddnode(right).right.nodetype=ordconstn then
  261. begin
  262. { this was "extraoffset:=right.right.value;" Looks a bit like
  263. copy-paste bug :) (JM) }
  264. extraoffset:=-tordconstnode(taddnode(right).right).value;
  265. t:=taddnode(right).left;
  266. t.registers32 := right.registers32;
  267. taddnode(right).left:=nil;
  268. right.free;
  269. right:=t;
  270. end
  271. { You also have to negate right.right in this case! I can't add an
  272. unaryminusn without causing a crash, so I've disabled it (JM)
  273. else if right.left.nodetype=ordconstn then
  274. begin
  275. extraoffset:=right.left.value;
  276. t:=right.right;
  277. t^.registers32 := right.registers32;
  278. putnode(right);
  279. putnode(right.left);
  280. right:=t;
  281. end;}
  282. end;
  283. inc(location.reference.offset,
  284. get_mul_size*extraoffset);
  285. end;
  286. { calculate from left to right }
  287. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  288. { should be internalerror! (JM) }
  289. CGMessage(cg_e_illegal_expression);
  290. isjump:=(right.location.loc=LOC_JUMP);
  291. if isjump then
  292. begin
  293. otl:=truelabel;
  294. getlabel(truelabel);
  295. ofl:=falselabel;
  296. getlabel(falselabel);
  297. end;
  298. maybe_save(exprasmlist,right.registers32,location,pushedregs);
  299. secondpass(right);
  300. maybe_restore(exprasmlist,location,pushedregs);
  301. { here we change the location of right
  302. and the update was forgotten so it
  303. led to wrong code in emitrangecheck later PM
  304. so make range check before }
  305. if cs_check_range in aktlocalswitches then
  306. begin
  307. if left.resulttype.def.deftype=arraydef then
  308. begin
  309. if is_open_array(left.resulttype.def) or
  310. is_array_of_const(left.resulttype.def) then
  311. begin
  312. tarraydef(left.resulttype.def).genrangecheck;
  313. srsym:=searchsymonlyin(tloadnode(left).symtable,
  314. 'high'+tvarsym(tloadnode(left).symtableentry).name);
  315. hightree:=cloadnode.create(tvarsym(srsym),tloadnode(left).symtable);
  316. firstpass(hightree);
  317. secondpass(hightree);
  318. location_release(exprasmlist,hightree.location);
  319. reference_reset_symbol(href,newasmsymbol(tarraydef(left.resulttype.def).getrangecheckstring),4);
  320. cg.a_load_loc_ref(exprasmlist,hightree.location,href);
  321. hightree.free;
  322. hightree:=nil;
  323. end;
  324. cg.g_rangecheck(exprasmlist,right,left.resulttype.def);
  325. end;
  326. end;
  327. location_force_reg(exprasmlist,right.location,OS_32,false);
  328. if isjump then
  329. begin
  330. truelabel:=otl;
  331. falselabel:=ofl;
  332. end;
  333. { produce possible range check code: }
  334. if cs_check_range in aktlocalswitches then
  335. begin
  336. if left.resulttype.def.deftype=arraydef then
  337. begin
  338. { done defore (PM) }
  339. end
  340. else if (left.resulttype.def.deftype=stringdef) then
  341. begin
  342. case tstringdef(left.resulttype.def).string_typ of
  343. { it's the same for ansi- and wide strings }
  344. st_widestring,
  345. st_ansistring:
  346. begin
  347. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  348. cg.a_param_reg(exprasmlist,OS_INT,right.location.register,paramanager.getintparaloc(1));
  349. href:=location.reference;
  350. dec(href.offset,7);
  351. cg.a_param_ref(exprasmlist,OS_INT,href,paramanager.getintparaloc(1));
  352. rg.saveregvars(exprasmlist,all_registers);
  353. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  354. rg.restoreusedregisters(exprasmlist,pushed);
  355. cg.g_maybe_loadself(exprasmlist);
  356. end;
  357. st_shortstring:
  358. begin
  359. {!!!!!!!!!!!!!!!!!}
  360. end;
  361. st_longstring:
  362. begin
  363. {!!!!!!!!!!!!!!!!!}
  364. end;
  365. end;
  366. end;
  367. end;
  368. if location.reference.index=R_NO then
  369. begin
  370. location.reference.index:=right.location.register;
  371. cg.a_op_const_reg(exprasmlist,OP_IMUL,get_mul_size,
  372. right.location.register);
  373. end
  374. else
  375. begin
  376. if location.reference.base=R_NO then
  377. { this wouldn't make sense for the ppc since there are }
  378. { no scalefactors (JM) }
  379. internalerror(2002072901)
  380. else
  381. begin
  382. cg.a_loadaddr_ref_reg(exprasmlist,location.reference,
  383. location.reference.base);
  384. rg.ungetregisterint(exprasmlist,location.reference.index);
  385. { the symbol offset is loaded, }
  386. { so release the symbol name and set symbol }
  387. { to nil }
  388. location.reference.symbol:=nil;
  389. location.reference.offset:=0;
  390. cg.a_op_const_reg(exprasmlist,OP_IMUL,
  391. get_mul_size,right.location.register);
  392. location.reference.index:=right.location.register;
  393. end;
  394. end;
  395. end;
  396. location.size:=newsize;
  397. end;
  398. begin
  399. cvecnode:=tppcvecnode;
  400. end.
  401. {
  402. $Log$
  403. Revision 1.1 2002-07-29 09:21:30 jonas
  404. + tppcvecnode, almost straight copy of the i386 code, can most likely
  405. be made generic if all treference type allow a base, index and offset
  406. }