ncgmem.pas 48 KB

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