ncgmem.pas 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for memory related nodes which are
  4. the same for all (most?) processors
  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 ncgmem;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,cgbase,cpuinfo,cpubase,
  23. node,nmem;
  24. type
  25. tcgloadvmtaddrnode = class(tloadvmtaddrnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgloadparentfpnode = class(tloadparentfpnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgaddrnode = class(taddrnode)
  32. procedure pass_2;override;
  33. end;
  34. tcgderefnode = class(tderefnode)
  35. procedure pass_2;override;
  36. end;
  37. tcgsubscriptnode = class(tsubscriptnode)
  38. procedure pass_2;override;
  39. end;
  40. tcgwithnode = class(twithnode)
  41. procedure pass_2;override;
  42. end;
  43. tcgvecnode = class(tvecnode)
  44. private
  45. procedure rangecheck_array;
  46. protected
  47. function get_mul_size : aint;
  48. {# This routine is used to calculate the address of the reference.
  49. On entry reg contains the index in the array,
  50. and l contains the size of each element in the array.
  51. This routine should update location.reference correctly,
  52. so it points to the correct address.
  53. }
  54. procedure update_reference_reg_mul(reg:tregister;l:aint);virtual;
  55. procedure update_reference_reg_packed(reg:tregister;l:aint);virtual;
  56. procedure second_wideansistring;virtual;
  57. procedure second_dynamicarray;virtual;
  58. public
  59. procedure pass_2;override;
  60. end;
  61. implementation
  62. uses
  63. systems,
  64. cutils,verbose,globals,
  65. symconst,symdef,symsym,symtable,defutil,paramgr,
  66. aasmbase,aasmtai,aasmdata,
  67. procinfo,pass_2,parabase,
  68. pass_1,nld,ncon,nadd,nutils,nset,
  69. cgutils,cgobj,
  70. tgobj,ncgutil
  71. ;
  72. {*****************************************************************************
  73. TCGLOADVMTADDRNODE
  74. *****************************************************************************}
  75. procedure tcgloadvmtaddrnode.pass_2;
  76. var
  77. href : treference;
  78. begin
  79. location_reset(location,LOC_REGISTER,OS_ADDR);
  80. if (left.nodetype=typen) then
  81. begin
  82. reference_reset_symbol(href,
  83. current_asmdata.RefAsmSymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname),0);
  84. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  85. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
  86. end
  87. else
  88. begin
  89. { left contains self, load vmt from self }
  90. secondpass(left);
  91. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(left.resulttype.def),left.location,location.register);
  92. end;
  93. end;
  94. {*****************************************************************************
  95. TCGLOADPARENTFPNODE
  96. *****************************************************************************}
  97. procedure tcgloadparentfpnode.pass_2;
  98. var
  99. currpi : tprocinfo;
  100. hsym : tparavarsym;
  101. href : treference;
  102. begin
  103. if (current_procinfo.procdef.parast.symtablelevel=parentpd.parast.symtablelevel) then
  104. begin
  105. location_reset(location,LOC_REGISTER,OS_ADDR);
  106. location.register:=current_procinfo.framepointer;
  107. end
  108. else
  109. begin
  110. currpi:=current_procinfo;
  111. location_reset(location,LOC_REGISTER,OS_ADDR);
  112. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  113. { load framepointer of current proc }
  114. hsym:=tparavarsym(currpi.procdef.parast.search('parentfp'));
  115. if not assigned(hsym) then
  116. internalerror(200309281);
  117. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,hsym.localloc,location.register);
  118. { walk parents }
  119. while (currpi.procdef.owner.symtablelevel>parentpd.parast.symtablelevel) do
  120. begin
  121. currpi:=currpi.parent;
  122. if not assigned(currpi) then
  123. internalerror(200311201);
  124. hsym:=tparavarsym(currpi.procdef.parast.search('parentfp'));
  125. if not assigned(hsym) then
  126. internalerror(200309282);
  127. if hsym.localloc.loc<>LOC_REFERENCE then
  128. internalerror(200309283);
  129. reference_reset_base(href,location.register,hsym.localloc.reference.offset);
  130. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,location.register);
  131. end;
  132. end;
  133. end;
  134. {*****************************************************************************
  135. TCGADDRNODE
  136. *****************************************************************************}
  137. procedure tcgaddrnode.pass_2;
  138. var
  139. tmpref: treference;
  140. begin
  141. secondpass(left);
  142. location_reset(location,LOC_REGISTER,OS_ADDR);
  143. location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
  144. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,location.register);
  145. end;
  146. {*****************************************************************************
  147. TCGDEREFNODE
  148. *****************************************************************************}
  149. procedure tcgderefnode.pass_2;
  150. var
  151. paraloc1 : tcgpara;
  152. begin
  153. secondpass(left);
  154. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  155. case left.location.loc of
  156. LOC_CREGISTER,
  157. LOC_REGISTER:
  158. begin
  159. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  160. {$ifdef cpu_uses_separate_address_registers}
  161. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  162. begin
  163. location.reference.base := cg.getaddressregister(current_asmdata.CurrAsmList);
  164. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.register,
  165. location.reference.base);
  166. end
  167. else
  168. {$endif}
  169. location.reference.base := left.location.register;
  170. end;
  171. LOC_CREFERENCE,
  172. LOC_REFERENCE:
  173. begin
  174. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  175. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference.base);
  176. end;
  177. LOC_CONSTANT:
  178. begin
  179. location.reference.offset:=left.location.value;
  180. end;
  181. else
  182. internalerror(200507031);
  183. end;
  184. if (cs_use_heaptrc in aktglobalswitches) and
  185. (cs_checkpointer in aktlocalswitches) and
  186. not(cs_compilesystem in aktmoduleswitches) and
  187. not(tpointerdef(left.resulttype.def).is_far) and
  188. not(nf_no_checkpointer in flags) then
  189. begin
  190. paraloc1.init;
  191. paramanager.getintparaloc(pocall_default,1,paraloc1);
  192. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  193. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  194. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  195. paraloc1.done;
  196. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  197. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER');
  198. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  199. end;
  200. end;
  201. {*****************************************************************************
  202. TCGSUBSCRIPTNODE
  203. *****************************************************************************}
  204. procedure tcgsubscriptnode.pass_2;
  205. var
  206. paraloc1 : tcgpara;
  207. sref: tsubsetreference;
  208. begin
  209. secondpass(left);
  210. if codegenerror then
  211. exit;
  212. paraloc1.init;
  213. { classes and interfaces must be dereferenced implicit }
  214. if is_class_or_interface(left.resulttype.def) then
  215. begin
  216. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  217. case left.location.loc of
  218. LOC_CREGISTER,
  219. LOC_REGISTER:
  220. begin
  221. {$ifdef cpu_uses_separate_address_registers}
  222. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  223. begin
  224. location.reference.base:=rg.getaddressregister(current_asmdata.CurrAsmList);
  225. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  226. left.location.register,location.reference.base);
  227. end
  228. else
  229. {$endif}
  230. location.reference.base := left.location.register;
  231. end;
  232. LOC_CREFERENCE,
  233. LOC_REFERENCE:
  234. begin
  235. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  236. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference.base);
  237. end;
  238. end;
  239. { implicit deferencing }
  240. if (cs_use_heaptrc in aktglobalswitches) and
  241. (cs_checkpointer in aktlocalswitches) and
  242. not(cs_compilesystem in aktmoduleswitches) then
  243. begin
  244. paramanager.getintparaloc(pocall_default,1,paraloc1);
  245. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  246. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  247. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  248. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  249. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER');
  250. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  251. end;
  252. end
  253. else if is_interfacecom(left.resulttype.def) then
  254. begin
  255. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  256. tg.GetTempTyped(current_asmdata.CurrAsmList,left.resulttype.def,tt_normal,location.reference);
  257. cg.a_load_loc_ref(current_asmdata.CurrAsmList,OS_ADDR,left.location,location.reference);
  258. { implicit deferencing also for interfaces }
  259. if (cs_use_heaptrc in aktglobalswitches) and
  260. (cs_checkpointer in aktlocalswitches) and
  261. not(cs_compilesystem in aktmoduleswitches) then
  262. begin
  263. paramanager.getintparaloc(pocall_default,1,paraloc1);
  264. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  265. cg.a_param_reg(current_asmdata.CurrAsmList, OS_ADDR,location.reference.base,paraloc1);
  266. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  267. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  268. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_CHECKPOINTER');
  269. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  270. end;
  271. end
  272. else
  273. begin
  274. location_copy(location,left.location);
  275. { some abi's require that functions return (some) records in }
  276. { registers }
  277. case location.loc of
  278. LOC_REFERENCE,
  279. LOC_CREFERENCE:
  280. ;
  281. LOC_REGISTER,
  282. LOC_CREGISTER:
  283. begin
  284. if (left.resulttype.def.size > sizeof(aint)) then
  285. location_force_mem(current_asmdata.CurrAsmList,location)
  286. else
  287. begin
  288. if (left.location.loc = LOC_REGISTER) then
  289. location.loc := LOC_SUBSETREG
  290. else
  291. location.loc := LOC_CSUBSETREG;
  292. location.size:=def_cgsize(resulttype.def);
  293. location.sreg.subsetreg := left.location.register;
  294. location.sreg.subsetregsize := left.location.size;
  295. if not is_packed_record_or_object(left.resulttype.def) then
  296. begin
  297. if (target_info.endian = ENDIAN_BIG) then
  298. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8
  299. else
  300. location.sreg.startbit := (vs.fieldoffset * 8);
  301. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  302. end
  303. else
  304. begin
  305. location.sreg.bitlen := resulttype.def.packedbitsize;
  306. if (target_info.endian = ENDIAN_BIG) then
  307. location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset
  308. else
  309. location.sreg.startbit := vs.fieldoffset;
  310. end;
  311. end;
  312. end;
  313. LOC_SUBSETREG,
  314. LOC_CSUBSETREG:
  315. begin
  316. location.size:=def_cgsize(resulttype.def);
  317. if (target_info.endian = ENDIAN_BIG) then
  318. inc(location.sreg.startbit, (left.resulttype.def.size - tcgsize2size[location.size] - vs.fieldoffset) * 8)
  319. else
  320. inc(location.sreg.startbit, vs.fieldoffset * 8);
  321. location.sreg.bitlen := tcgsize2size[location.size] * 8;
  322. end;
  323. else
  324. internalerror(2006031901);
  325. end;
  326. end;
  327. if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  328. begin
  329. if not is_packed_record_or_object(left.resulttype.def) then
  330. begin
  331. inc(location.reference.offset,vs.fieldoffset);
  332. {$ifdef SUPPORT_UNALIGNED}
  333. { packed? }
  334. if (vs.owner.defowner.deftype in [recorddef,objectdef]) and
  335. (tabstractrecordsymtable(vs.owner).usefieldalignment=1) then
  336. location.reference.alignment:=1;
  337. {$endif SUPPORT_UNALIGNED}
  338. end
  339. else if (vs.fieldoffset mod 8 = 0) and
  340. (resulttype.def.packedbitsize mod 8 = 0) and
  341. { is different in case of e.g. packenum 2 and an enum }
  342. { which fits in 8 bits }
  343. (resulttype.def.size*8 = resulttype.def.packedbitsize) then
  344. begin
  345. inc(location.reference.offset,vs.fieldoffset div 8);
  346. if (resulttype.def.size*8 <> resulttype.def.packedbitsize) then
  347. internalerror(2006082013);
  348. { packed records always have an alignment of 1 }
  349. location.reference.alignment:=1;
  350. end
  351. else
  352. begin
  353. sref.ref:=location.reference;
  354. sref.ref.alignment:=1;
  355. sref.bitindexreg:=NR_NO;
  356. inc(sref.ref.offset,vs.fieldoffset div 8);
  357. sref.startbit:=vs.fieldoffset mod 8;
  358. sref.bitlen:=resulttype.def.packedbitsize;
  359. if (left.location.loc=LOC_REFERENCE) then
  360. location.loc:=LOC_SUBSETREF
  361. else
  362. location.loc:=LOC_CSUBSETREF;
  363. location.sref:=sref;
  364. end;
  365. { also update the size of the location }
  366. location.size:=def_cgsize(resulttype.def);
  367. end;
  368. paraloc1.done;
  369. end;
  370. {*****************************************************************************
  371. TCGWITHNODE
  372. *****************************************************************************}
  373. procedure tcgwithnode.pass_2;
  374. begin
  375. location_reset(location,LOC_VOID,OS_NO);
  376. if assigned(left) then
  377. secondpass(left);
  378. end;
  379. {*****************************************************************************
  380. TCGVECNODE
  381. *****************************************************************************}
  382. function tcgvecnode.get_mul_size : aint;
  383. begin
  384. if nf_memindex in flags then
  385. get_mul_size:=1
  386. else
  387. begin
  388. if (left.resulttype.def.deftype=arraydef) then
  389. if not is_packed_array(left.resulttype.def) then
  390. get_mul_size:=tarraydef(left.resulttype.def).elesize
  391. else
  392. get_mul_size:=tarraydef(left.resulttype.def).elepackedbitsize
  393. else
  394. get_mul_size:=resulttype.def.size;
  395. end
  396. end;
  397. procedure tcgvecnode.update_reference_reg_mul(reg:tregister;l:aint);
  398. var
  399. hreg: tregister;
  400. begin
  401. if location.reference.base=NR_NO then
  402. begin
  403. if l<>1 then
  404. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,reg);
  405. location.reference.base:=reg;
  406. end
  407. else if location.reference.index=NR_NO then
  408. begin
  409. if l<>1 then
  410. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,reg);
  411. location.reference.index:=reg;
  412. end
  413. else
  414. begin
  415. hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  416. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
  417. reference_reset_base(location.reference,hreg,0);
  418. { insert new index register }
  419. if l<>1 then
  420. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,reg);
  421. location.reference.index:=reg;
  422. end;
  423. end;
  424. procedure tcgvecnode.update_reference_reg_packed(reg:tregister;l:aint);
  425. var
  426. sref: tsubsetreference;
  427. offsetreg: tregister;
  428. byteoffs, bitoffs, alignpower: aint;
  429. temp : longint;
  430. begin
  431. if ((l mod 8) = 0) and
  432. ispowerof2(l div 8,temp) then
  433. begin
  434. update_reference_reg_mul(reg,l div 8);
  435. exit;
  436. end;
  437. if (l > 8*sizeof(aint)) then
  438. internalerror(200608051);
  439. sref.ref := location.reference;
  440. offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
  441. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,tarraydef(left.resulttype.def).lowrange,reg);
  442. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,reg);
  443. { keep alignment for index }
  444. sref.ref.alignment := left.resulttype.def.alignment;
  445. if not ispowerof2(sref.ref.alignment,temp) then
  446. internalerror(2006081201);
  447. alignpower:=temp;
  448. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,reg,offsetreg);
  449. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
  450. if (sref.ref.base = NR_NO) then
  451. sref.ref.base := offsetreg
  452. else if (sref.ref.index = NR_NO) then
  453. sref.ref.index := offsetreg
  454. else
  455. begin
  456. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
  457. sref.ref.base := offsetreg;
  458. end;
  459. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,reg);
  460. sref.bitindexreg := reg;
  461. sref.startbit := 0;
  462. sref.bitlen := resulttype.def.packedbitsize;
  463. if (left.location.loc = LOC_REFERENCE) then
  464. location.loc := LOC_SUBSETREF
  465. else
  466. location.loc := LOC_CSUBSETREF;
  467. location.sref := sref;
  468. end;
  469. procedure tcgvecnode.second_wideansistring;
  470. begin
  471. end;
  472. procedure tcgvecnode.second_dynamicarray;
  473. begin
  474. end;
  475. procedure tcgvecnode.rangecheck_array;
  476. var
  477. hightree : tnode;
  478. poslabel,
  479. neglabel : tasmlabel;
  480. hreg : tregister;
  481. paraloc1,paraloc2 : tcgpara;
  482. begin
  483. paraloc1.init;
  484. paraloc2.init;
  485. if is_open_array(left.resulttype.def) or
  486. is_array_of_const(left.resulttype.def) then
  487. begin
  488. { cdecl functions don't have high() so we can not check the range }
  489. if not(current_procinfo.procdef.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
  490. begin
  491. { Get high value }
  492. hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry));
  493. { it must be available }
  494. if not assigned(hightree) then
  495. internalerror(200212201);
  496. firstpass(hightree);
  497. secondpass(hightree);
  498. { generate compares }
  499. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  500. hreg:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_INT)
  501. else
  502. begin
  503. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  504. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,right.location,hreg);
  505. end;
  506. current_asmdata.getjumplabel(neglabel);
  507. current_asmdata.getjumplabel(poslabel);
  508. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_LT,0,hreg,poslabel);
  509. cg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_BE,hightree.location,hreg,neglabel);
  510. cg.a_label(current_asmdata.CurrAsmList,poslabel);
  511. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_RANGEERROR');
  512. cg.a_label(current_asmdata.CurrAsmList,neglabel);
  513. { release hightree }
  514. hightree.free;
  515. end;
  516. end
  517. else
  518. if is_dynamic_array(left.resulttype.def) then
  519. begin
  520. paramanager.getintparaloc(pocall_default,1,paraloc1);
  521. paramanager.getintparaloc(pocall_default,2,paraloc2);
  522. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  523. cg.a_param_loc(current_asmdata.CurrAsmList,right.location,paraloc2);
  524. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  525. cg.a_param_loc(current_asmdata.CurrAsmList,left.location,paraloc1);
  526. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  527. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  528. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  529. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DYNARRAY_RANGECHECK');
  530. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  531. end
  532. else
  533. cg.g_rangecheck(current_asmdata.CurrAsmList,right.location,right.resulttype.def,left.resulttype.def);
  534. paraloc1.done;
  535. paraloc2.done;
  536. end;
  537. procedure tcgvecnode.pass_2;
  538. var
  539. offsetdec,
  540. extraoffset : aint;
  541. t : tnode;
  542. href : treference;
  543. otl,ofl : tasmlabel;
  544. newsize : tcgsize;
  545. mulsize,
  546. bytemulsize,
  547. alignpow : aint;
  548. isjump : boolean;
  549. paraloc1,
  550. paraloc2 : tcgpara;
  551. subsetref : tsubsetreference;
  552. temp : longint;
  553. begin
  554. paraloc1.init;
  555. paraloc2.init;
  556. mulsize:=get_mul_size;
  557. if not is_packed_array(left.resulttype.def) then
  558. bytemulsize:=mulsize
  559. else
  560. bytemulsize:=mulsize div 8;
  561. newsize:=def_cgsize(resulttype.def);
  562. secondpass(left);
  563. if left.location.loc=LOC_CREFERENCE then
  564. location_reset(location,LOC_CREFERENCE,newsize)
  565. else
  566. location_reset(location,LOC_REFERENCE,newsize);
  567. { an ansistring needs to be dereferenced }
  568. if is_ansistring(left.resulttype.def) or
  569. is_widestring(left.resulttype.def) then
  570. begin
  571. if nf_callunique in flags then
  572. internalerror(200304236);
  573. {DM!!!!!}
  574. case left.location.loc of
  575. LOC_REGISTER,
  576. LOC_CREGISTER :
  577. location.reference.base:=left.location.register;
  578. LOC_CREFERENCE,
  579. LOC_REFERENCE :
  580. begin
  581. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  582. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
  583. end;
  584. else
  585. internalerror(2002032218);
  586. end;
  587. { check for a zero length string,
  588. we can use the ansistring routine here }
  589. if (cs_check_range in aktlocalswitches) then
  590. begin
  591. paramanager.getintparaloc(pocall_default,1,paraloc1);
  592. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  593. cg.a_param_reg(current_asmdata.CurrAsmList,OS_ADDR,location.reference.base,paraloc1);
  594. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  595. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  596. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO');
  597. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  598. end;
  599. { in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
  600. if is_ansistring(left.resulttype.def) then
  601. offsetdec:=1
  602. else
  603. offsetdec:=2;
  604. dec(location.reference.offset,offsetdec);
  605. end
  606. else if is_dynamic_array(left.resulttype.def) then
  607. begin
  608. case left.location.loc of
  609. LOC_REGISTER,
  610. LOC_CREGISTER :
  611. location.reference.base:=left.location.register;
  612. LOC_REFERENCE,
  613. LOC_CREFERENCE :
  614. begin
  615. location.reference.base:=cg.getaddressregister(current_asmdata.CurrAsmList);
  616. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,
  617. left.location.reference,location.reference.base);
  618. end;
  619. else
  620. internalerror(2002032219);
  621. end;
  622. end
  623. else
  624. location_copy(location,left.location);
  625. { location must be memory }
  626. if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  627. internalerror(200411013);
  628. { offset can only differ from 0 if arraydef }
  629. if (left.resulttype.def.deftype=arraydef) and
  630. not(is_dynamic_array(left.resulttype.def)) and
  631. (not(is_packed_array(left.resulttype.def)) or
  632. ((mulsize mod 8 = 0) and
  633. ispowerof2(mulsize div 8,temp))) then
  634. dec(location.reference.offset,bytemulsize*tarraydef(left.resulttype.def).lowrange);
  635. case right.nodetype of
  636. ordconstn:
  637. begin
  638. { offset can only differ from 0 if arraydef }
  639. case left.resulttype.def.deftype of
  640. arraydef :
  641. begin
  642. if not(is_open_array(left.resulttype.def)) and
  643. not(is_array_of_const(left.resulttype.def)) and
  644. not(is_dynamic_array(left.resulttype.def)) then
  645. begin
  646. if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or
  647. (tordconstnode(right).value<tarraydef(left.resulttype.def).lowrange) then
  648. begin
  649. { this should be caught in the resulttypepass! (JM) }
  650. if (cs_check_range in aktlocalswitches) then
  651. CGMessage(parser_e_range_check_error)
  652. else
  653. CGMessage(parser_w_range_check_error);
  654. end;
  655. end
  656. else
  657. begin
  658. { range checking for open and dynamic arrays needs
  659. runtime code }
  660. secondpass(right);
  661. if (cs_check_range in aktlocalswitches) then
  662. rangecheck_array;
  663. end;
  664. end;
  665. stringdef :
  666. begin
  667. if (cs_check_range in aktlocalswitches) then
  668. begin
  669. case tstringdef(left.resulttype.def).string_typ of
  670. { it's the same for ansi- and wide strings }
  671. st_widestring,
  672. st_ansistring:
  673. begin
  674. paramanager.getintparaloc(pocall_default,1,paraloc1);
  675. paramanager.getintparaloc(pocall_default,2,paraloc2);
  676. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  677. cg.a_param_const(current_asmdata.CurrAsmList,OS_INT,tordconstnode(right).value,paraloc2);
  678. href:=location.reference;
  679. dec(href.offset,sizeof(aint)-offsetdec);
  680. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  681. cg.a_param_ref(current_asmdata.CurrAsmList,OS_INT,href,paraloc1);
  682. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  683. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  684. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  685. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  686. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  687. end;
  688. st_shortstring:
  689. begin
  690. {!!!!!!!!!!!!!!!!!}
  691. { if this one is implemented making use of the high parameter for openshortstrings, update ncgutils.do_get_used_regvars() too (JM) }
  692. end;
  693. st_longstring:
  694. begin
  695. {!!!!!!!!!!!!!!!!!}
  696. end;
  697. end;
  698. end;
  699. end;
  700. end;
  701. if not(is_packed_array(left.resulttype.def)) or
  702. ((mulsize mod 8 = 0) and
  703. ispowerof2(mulsize div 8,temp)) then
  704. begin
  705. inc(location.reference.offset,
  706. bytemulsize*tordconstnode(right).value);
  707. { don't do this for floats etc.; needed to properly set the }
  708. { size for bitpacked arrays (e.g. a bitpacked array of }
  709. { enums who are size 2 but fit in one byte -> in the array }
  710. { they will be one byte and have to be stored like that) }
  711. if is_packed_array(left.resulttype.def) and
  712. (tcgsize2size[newsize] <> bytemulsize) then
  713. newsize:=int_cgsize(bytemulsize);
  714. end
  715. else
  716. begin
  717. subsetref.ref := location.reference;
  718. subsetref.ref.alignment := left.resulttype.def.alignment;
  719. if not ispowerof2(subsetref.ref.alignment,temp) then
  720. internalerror(2006081212);
  721. alignpow:=temp;
  722. inc(subsetref.ref.offset,((mulsize * (tordconstnode(right).value-tarraydef(left.resulttype.def).lowrange)) shr (3+alignpow)) shl alignpow);
  723. subsetref.bitindexreg := NR_NO;
  724. subsetref.startbit := (mulsize * (tordconstnode(right).value-tarraydef(left.resulttype.def).lowrange)) and ((1 shl (3+alignpow))-1);
  725. subsetref.bitlen := resulttype.def.packedbitsize;
  726. if (left.location.loc = LOC_REFERENCE) then
  727. location.loc := LOC_SUBSETREF
  728. else
  729. location.loc := LOC_CSUBSETREF;
  730. location.sref := subsetref;
  731. end;
  732. end;
  733. rangen:
  734. begin
  735. {Pbyte[0..9] syntax.
  736. The .. operator by itself does not generate code, it only determines
  737. the type of the resulting array. So we immediately call the second past
  738. of the lower bound, which determines the address.}
  739. {Get lower array bound.}
  740. secondpass(Trangenode(right).left);
  741. {If mulsize = 1, we won't have to modify the index }
  742. location_force_reg(current_asmdata.CurrAsmList,
  743. Trangenode(right).left.location,
  744. OS_ADDR,
  745. mulsize=1);
  746. update_reference_reg_mul(Trangenode(right).left.location.register,mulsize)
  747. end;
  748. else
  749. { not nodetype in [ordconstn,rangen] }
  750. if (cs_opt_level1 in aktoptimizerswitches) and
  751. { if we do range checking, we don't }
  752. { need that fancy code (it would be }
  753. { buggy) }
  754. not(cs_check_range in aktlocalswitches) and
  755. (left.resulttype.def.deftype=arraydef) and
  756. not is_packed_array(left.resulttype.def) then
  757. begin
  758. extraoffset:=0;
  759. if (right.nodetype=addn) then
  760. begin
  761. if taddnode(right).right.nodetype=ordconstn then
  762. begin
  763. extraoffset:=tordconstnode(taddnode(right).right).value;
  764. t:=taddnode(right).left;
  765. { First pass processed this with the assumption }
  766. { that there was an add node which may require an }
  767. { extra register. Fake it or die with IE10 (JM) }
  768. t.registersint := taddnode(right).registersint;
  769. taddnode(right).left:=nil;
  770. right.free;
  771. right:=t;
  772. end
  773. else if taddnode(right).left.nodetype=ordconstn then
  774. begin
  775. extraoffset:=tordconstnode(taddnode(right).left).value;
  776. t:=taddnode(right).right;
  777. t.registersint := right.registersint;
  778. taddnode(right).right:=nil;
  779. right.free;
  780. right:=t;
  781. end;
  782. end
  783. else if (right.nodetype=subn) then
  784. begin
  785. if taddnode(right).right.nodetype=ordconstn then
  786. begin
  787. extraoffset:=-tordconstnode(taddnode(right).right).value;
  788. t:=taddnode(right).left;
  789. t.registersint := right.registersint;
  790. taddnode(right).left:=nil;
  791. right.free;
  792. right:=t;
  793. end
  794. { You also have to negate right.right in this case! I can't add an
  795. unaryminusn without causing a crash, so I've disabled it (JM)
  796. else if right.left.nodetype=ordconstn then
  797. begin
  798. extraoffset:=right.left.value;
  799. t:=right.right;
  800. t^.registersint := right.registersint;
  801. putnode(right);
  802. putnode(right.left);
  803. right:=t;
  804. end;}
  805. end;
  806. inc(location.reference.offset,
  807. mulsize*extraoffset);
  808. end;
  809. { calculate from left to right }
  810. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  811. internalerror(200304237);
  812. isjump:=(right.expectloc=LOC_JUMP);
  813. if isjump then
  814. begin
  815. otl:=current_procinfo.CurrTrueLabel;
  816. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  817. ofl:=current_procinfo.CurrFalseLabel;
  818. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  819. end;
  820. secondpass(right);
  821. { if mulsize = 1, we won't have to modify the index }
  822. location_force_reg(current_asmdata.CurrAsmList,right.location,OS_ADDR,not is_packed_array(left.resulttype.def) and (mulsize = 1) );
  823. if isjump then
  824. begin
  825. current_procinfo.CurrTrueLabel:=otl;
  826. current_procinfo.CurrFalseLabel:=ofl;
  827. end
  828. else if (right.location.loc = LOC_JUMP) then
  829. internalerror(2006010801);
  830. { only range check now, we can't range check loc_flags/loc_jump }
  831. if cs_check_range in aktlocalswitches then
  832. begin
  833. if left.resulttype.def.deftype=arraydef then
  834. rangecheck_array;
  835. end;
  836. { produce possible range check code: }
  837. if cs_check_range in aktlocalswitches then
  838. begin
  839. if left.resulttype.def.deftype=arraydef then
  840. begin
  841. { done defore (PM) }
  842. end
  843. else if (left.resulttype.def.deftype=stringdef) then
  844. begin
  845. case tstringdef(left.resulttype.def).string_typ of
  846. { it's the same for ansi- and wide strings }
  847. st_widestring,
  848. st_ansistring:
  849. begin
  850. paramanager.getintparaloc(pocall_default,1,paraloc1);
  851. paramanager.getintparaloc(pocall_default,2,paraloc2);
  852. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc2);
  853. cg.a_param_reg(current_asmdata.CurrAsmList,OS_INT,right.location.register,paraloc2);
  854. href:=location.reference;
  855. dec(href.offset,sizeof(aint)-offsetdec);
  856. //dec(href.offset,7);
  857. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  858. cg.a_param_ref(current_asmdata.CurrAsmList,OS_INT,href,paraloc1);
  859. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  860. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc2);
  861. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  862. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  863. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  864. end;
  865. st_shortstring:
  866. begin
  867. {!!!!!!!!!!!!!!!!!}
  868. end;
  869. st_longstring:
  870. begin
  871. {!!!!!!!!!!!!!!!!!}
  872. end;
  873. end;
  874. end;
  875. end;
  876. { insert the register and the multiplication factor in the
  877. reference }
  878. if not is_packed_array(left.resulttype.def) then
  879. update_reference_reg_mul(right.location.register,mulsize)
  880. else
  881. update_reference_reg_packed(right.location.register,mulsize);
  882. end;
  883. location.size:=newsize;
  884. paraloc1.done;
  885. paraloc2.done;
  886. end;
  887. begin
  888. cloadvmtaddrnode:=tcgloadvmtaddrnode;
  889. cloadparentfpnode:=tcgloadparentfpnode;
  890. caddrnode:=tcgaddrnode;
  891. cderefnode:=tcgderefnode;
  892. csubscriptnode:=tcgsubscriptnode;
  893. cwithnode:=tcgwithnode;
  894. cvecnode:=tcgvecnode;
  895. end.