ncgmem.pas 45 KB

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