ncgmem.pas 49 KB

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