cg386mem.pas 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 assembler for in memory related nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cg386mem;
  19. interface
  20. uses
  21. tree;
  22. procedure secondloadvmt(var p : ptree);
  23. procedure secondhnewn(var p : ptree);
  24. procedure secondnewn(var p : ptree);
  25. procedure secondhdisposen(var p : ptree);
  26. procedure secondsimplenewdispose(var p : ptree);
  27. procedure secondaddr(var p : ptree);
  28. procedure seconddoubleaddr(var p : ptree);
  29. procedure secondderef(var p : ptree);
  30. procedure secondsubscriptn(var p : ptree);
  31. procedure secondvecn(var p : ptree);
  32. procedure secondselfn(var p : ptree);
  33. procedure secondwith(var p : ptree);
  34. implementation
  35. uses
  36. globtype,systems,
  37. cobjects,verbose,globals,
  38. symtable,aasm,types,
  39. hcodegen,temp_gen,pass_2,pass_1,
  40. {$ifndef OLDASM}
  41. i386base,i386asm,
  42. {$else}
  43. i386,
  44. {$endif}
  45. cgai386,tgeni386;
  46. {*****************************************************************************
  47. SecondLoadVMT
  48. *****************************************************************************}
  49. procedure secondloadvmt(var p : ptree);
  50. begin
  51. p^.location.register:=getregister32;
  52. exprasmlist^.concat(new(pai386,op_sym_ofs_reg(A_MOV,
  53. S_L,newasmsymbol(pobjectdef(pclassrefdef(p^.resulttype)^.definition)^.vmt_mangledname),0,
  54. p^.location.register)));
  55. maybe_concat_external(pobjectdef(pclassrefdef(p^.resulttype)^.definition)^.owner,
  56. pobjectdef(pclassrefdef(p^.resulttype)^.definition)^.vmt_mangledname);
  57. end;
  58. {*****************************************************************************
  59. SecondHNewN
  60. *****************************************************************************}
  61. procedure secondhnewn(var p : ptree);
  62. begin
  63. end;
  64. {*****************************************************************************
  65. SecondNewN
  66. *****************************************************************************}
  67. procedure secondnewn(var p : ptree);
  68. var
  69. pushed : tpushed;
  70. r : preference;
  71. begin
  72. if assigned(p^.left) then
  73. begin
  74. secondpass(p^.left);
  75. p^.location.register:=p^.left^.location.register;
  76. end
  77. else
  78. begin
  79. pushusedregisters(exprasmlist,pushed,$ff);
  80. { code copied from simplenewdispose PM }
  81. { determines the size of the mem block }
  82. push_int(ppointerdef(p^.resulttype)^.definition^.size);
  83. gettempofsizereference(target_os.size_of_pointer,p^.location.reference);
  84. emitpushreferenceaddr(exprasmlist,p^.location.reference);
  85. emitcall('FPC_GETMEM',true);
  86. if ppointerdef(p^.resulttype)^.definition^.needs_inittable then
  87. begin
  88. new(r);
  89. reset_reference(r^);
  90. r^.symbol:=newasmsymbol(lab2str(ppointerdef(p^.left^.resulttype)^.definition^.get_inittable_label));
  91. emitpushreferenceaddr(exprasmlist,r^);
  92. { push pointer adress }
  93. emitpushreferenceaddr(exprasmlist,p^.location.reference);
  94. dispose(r);
  95. emitcall('FPC_INITIALIZE',true);
  96. end;
  97. popusedregisters(exprasmlist,pushed);
  98. { may be load ESI }
  99. maybe_loadesi;
  100. end;
  101. if codegenerror then
  102. exit;
  103. end;
  104. {*****************************************************************************
  105. SecondDisposeN
  106. *****************************************************************************}
  107. procedure secondhdisposen(var p : ptree);
  108. begin
  109. secondpass(p^.left);
  110. if codegenerror then
  111. exit;
  112. reset_reference(p^.location.reference);
  113. case p^.left^.location.loc of
  114. LOC_REGISTER,
  115. LOC_CREGISTER:
  116. begin
  117. p^.location.reference.index:=getregister32;
  118. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,S_L,
  119. p^.left^.location.register,
  120. p^.location.reference.index)));
  121. end;
  122. LOC_MEM,LOC_REFERENCE :
  123. begin
  124. del_reference(p^.left^.location.reference);
  125. p^.location.reference.index:=getregister32;
  126. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  127. p^.location.reference.index)));
  128. end;
  129. end;
  130. end;
  131. {*****************************************************************************
  132. SecondNewDispose
  133. *****************************************************************************}
  134. procedure secondsimplenewdispose(var p : ptree);
  135. var
  136. pushed : tpushed;
  137. r : preference;
  138. begin
  139. secondpass(p^.left);
  140. if codegenerror then
  141. exit;
  142. pushusedregisters(exprasmlist,pushed,$ff);
  143. { determines the size of the mem block }
  144. push_int(ppointerdef(p^.left^.resulttype)^.definition^.size);
  145. { push pointer adress }
  146. case p^.left^.location.loc of
  147. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,
  148. p^.left^.location.register)));
  149. LOC_REFERENCE:
  150. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  151. end;
  152. { call the mem handling procedures }
  153. case p^.treetype of
  154. simpledisposen:
  155. begin
  156. if ppointerdef(p^.left^.resulttype)^.definition^.needs_inittable then
  157. begin
  158. new(r);
  159. reset_reference(r^);
  160. r^.symbol:=newasmsymbol(lab2str(ppointerdef(p^.left^.resulttype)^.definition^.get_inittable_label));
  161. emitpushreferenceaddr(exprasmlist,r^);
  162. { push pointer adress }
  163. case p^.left^.location.loc of
  164. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,
  165. p^.left^.location.register)));
  166. LOC_REFERENCE:
  167. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  168. end;
  169. dispose(r);
  170. emitcall('FPC_FINALIZE',true);
  171. end;
  172. emitcall('FPC_FREEMEM',true);
  173. end;
  174. simplenewn:
  175. begin
  176. emitcall('FPC_GETMEM',true);
  177. if ppointerdef(p^.left^.resulttype)^.definition^.needs_inittable then
  178. begin
  179. new(r);
  180. reset_reference(r^);
  181. r^.symbol:=newasmsymbol(lab2str(ppointerdef(p^.left^.resulttype)^.definition^.get_inittable_label));
  182. emitpushreferenceaddr(exprasmlist,r^);
  183. { push pointer adress }
  184. case p^.left^.location.loc of
  185. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,
  186. p^.left^.location.register)));
  187. LOC_REFERENCE:
  188. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  189. end;
  190. dispose(r);
  191. emitcall('FPC_INITIALIZE',true);
  192. end;
  193. end;
  194. end;
  195. popusedregisters(exprasmlist,pushed);
  196. { may be load ESI }
  197. maybe_loadesi;
  198. end;
  199. {*****************************************************************************
  200. SecondAddr
  201. *****************************************************************************}
  202. procedure secondaddr(var p : ptree);
  203. begin
  204. secondpass(p^.left);
  205. p^.location.loc:=LOC_REGISTER;
  206. del_reference(p^.left^.location.reference);
  207. p^.location.register:=getregister32;
  208. {@ on a procvar means returning an address to the procedure that
  209. is stored in it.}
  210. { yes but p^.left^.symtableentry can be nil
  211. for example on @self !! }
  212. { symtableentry can be also invalid, if left is no tree node }
  213. if (m_tp_procvar in aktmodeswitches) and
  214. (p^.left^.treetype=loadn) and
  215. assigned(p^.left^.symtableentry) and
  216. (p^.left^.symtableentry^.typ=varsym) and
  217. (pvarsym(p^.left^.symtableentry)^.definition^.deftype=procvardef) then
  218. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  219. newreference(p^.left^.location.reference),
  220. p^.location.register)))
  221. else
  222. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  223. newreference(p^.left^.location.reference),
  224. p^.location.register)));
  225. { for use of other segments }
  226. if p^.left^.location.reference.segment<>R_NO then
  227. p^.location.segment:=p^.left^.location.reference.segment;
  228. end;
  229. {*****************************************************************************
  230. SecondDoubleAddr
  231. *****************************************************************************}
  232. procedure seconddoubleaddr(var p : ptree);
  233. begin
  234. secondpass(p^.left);
  235. p^.location.loc:=LOC_REGISTER;
  236. del_reference(p^.left^.location.reference);
  237. p^.location.register:=getregister32;
  238. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  239. newreference(p^.left^.location.reference),
  240. p^.location.register)));
  241. end;
  242. {*****************************************************************************
  243. SecondDeRef
  244. *****************************************************************************}
  245. procedure secondderef(var p : ptree);
  246. var
  247. hr : tregister;
  248. begin
  249. secondpass(p^.left);
  250. reset_reference(p^.location.reference);
  251. case p^.left^.location.loc of
  252. LOC_REGISTER:
  253. p^.location.reference.base:=p^.left^.location.register;
  254. LOC_CREGISTER:
  255. begin
  256. { ... and reserve one for the pointer }
  257. hr:=getregister32;
  258. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,hr);
  259. p^.location.reference.base:=hr;
  260. end;
  261. else
  262. begin
  263. { free register }
  264. del_reference(p^.left^.location.reference);
  265. { ...and reserve one for the pointer }
  266. hr:=getregister32;
  267. exprasmlist^.concat(new(pai386,op_ref_reg(
  268. A_MOV,S_L,newreference(p^.left^.location.reference),
  269. hr)));
  270. p^.location.reference.base:=hr;
  271. end;
  272. end;
  273. if ppointerdef(p^.left^.resulttype)^.is_far then
  274. p^.location.reference.segment:=R_FS;
  275. if not ppointerdef(p^.left^.resulttype)^.is_far and
  276. (cs_gdb_heaptrc in aktglobalswitches) and
  277. (cs_checkpointer in aktglobalswitches) then
  278. begin
  279. exprasmlist^.concat(new(pai386,op_reg(
  280. A_PUSH,S_L,p^.location.reference.base)));
  281. emitcall('FPC_CHECKPOINTER',true);
  282. end;
  283. end;
  284. {*****************************************************************************
  285. SecondSubScriptN
  286. *****************************************************************************}
  287. procedure secondsubscriptn(var p : ptree);
  288. var
  289. hr : tregister;
  290. begin
  291. secondpass(p^.left);
  292. if codegenerror then
  293. exit;
  294. { classes must be dereferenced implicit }
  295. if (p^.left^.resulttype^.deftype=objectdef) and
  296. pobjectdef(p^.left^.resulttype)^.isclass then
  297. begin
  298. reset_reference(p^.location.reference);
  299. case p^.left^.location.loc of
  300. LOC_REGISTER:
  301. p^.location.reference.base:=p^.left^.location.register;
  302. LOC_CREGISTER:
  303. begin
  304. { ... and reserve one for the pointer }
  305. hr:=getregister32;
  306. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,hr);
  307. p^.location.reference.base:=hr;
  308. end;
  309. else
  310. begin
  311. { free register }
  312. del_reference(p^.left^.location.reference);
  313. { ... and reserve one for the pointer }
  314. hr:=getregister32;
  315. exprasmlist^.concat(new(pai386,op_ref_reg(
  316. A_MOV,S_L,newreference(p^.left^.location.reference),
  317. hr)));
  318. p^.location.reference.base:=hr;
  319. end;
  320. end;
  321. end
  322. else
  323. set_location(p^.location,p^.left^.location);
  324. inc(p^.location.reference.offset,p^.vs^.address);
  325. end;
  326. {*****************************************************************************
  327. SecondVecN
  328. *****************************************************************************}
  329. procedure secondvecn(var p : ptree);
  330. var
  331. is_pushed : boolean;
  332. ind,hr : tregister;
  333. _p : ptree;
  334. function get_mul_size:longint;
  335. begin
  336. if p^.memindex then
  337. get_mul_size:=1
  338. else
  339. get_mul_size:=p^.resulttype^.size;
  340. end;
  341. procedure calc_emit_mul;
  342. var
  343. l1,l2 : longint;
  344. begin
  345. l1:=get_mul_size;
  346. case l1 of
  347. 1,2,4,8 : p^.location.reference.scalefactor:=l1;
  348. else
  349. begin
  350. if ispowerof2(l1,l2) then
  351. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,S_L,l2,ind)))
  352. else
  353. exprasmlist^.concat(new(pai386,op_const_reg(A_IMUL,S_L,l1,ind)));
  354. end;
  355. end;
  356. end;
  357. var
  358. extraoffset : longint;
  359. { rl stores the resulttype of the left node, this is necessary }
  360. { to detect if it is an ansistring }
  361. { because in constant nodes which constant index }
  362. { the left tree is removed }
  363. rl : pdef;
  364. t : ptree;
  365. hp : preference;
  366. href : treference;
  367. tai : Pai386;
  368. pushed : tpushed;
  369. hightree : ptree;
  370. begin
  371. secondpass(p^.left);
  372. rl:=p^.left^.resulttype;
  373. { we load the array reference to p^.location }
  374. { an ansistring needs to be dereferenced }
  375. if is_ansistring(p^.left^.resulttype) or
  376. is_widestring(p^.left^.resulttype) then
  377. begin
  378. reset_reference(p^.location.reference);
  379. if p^.callunique then
  380. begin
  381. if p^.left^.location.loc<>LOC_REFERENCE then
  382. begin
  383. CGMessage(cg_e_illegal_expression);
  384. exit;
  385. end;
  386. pushusedregisters(exprasmlist,pushed,$ff);
  387. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  388. if is_ansistring(p^.left^.resulttype) then
  389. emitcall('FPC_ANSISTR_UNIQUE',true)
  390. else
  391. emitcall('FPC_WIDESTR_UNIQUE',true);
  392. maybe_loadesi;
  393. popusedregisters(exprasmlist,pushed);
  394. end;
  395. if p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  396. begin
  397. p^.location.reference.base:=p^.left^.location.register;
  398. end
  399. else
  400. begin
  401. del_reference(p^.left^.location.reference);
  402. p^.location.reference.base:=getregister32;
  403. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  404. newreference(p^.left^.location.reference),
  405. p^.location.reference.base)));
  406. end;
  407. { check for a zero length string,
  408. we can use the ansistring routine here }
  409. if (cs_check_range in aktlocalswitches) then
  410. begin
  411. pushusedregisters(exprasmlist,pushed,$ff);
  412. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.location.reference.base)));
  413. emitcall('FPC_ANSISTR_CHECKZERO',true);
  414. maybe_loadesi;
  415. popusedregisters(exprasmlist,pushed);
  416. end;
  417. if is_ansistring(p^.left^.resulttype) then
  418. { in ansistrings S[1] is pchar(S)[0] !! }
  419. dec(p^.location.reference.offset)
  420. else
  421. begin
  422. { in widestrings S[1] is pwchar(S)[0] !! }
  423. dec(p^.location.reference.offset,2);
  424. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,S_L,
  425. 1,p^.location.reference.base)));
  426. end;
  427. { we've also to keep left up-to-date, because it is used }
  428. { if a constant array index occurs, subject to change (FK) }
  429. set_location(p^.left^.location,p^.location);
  430. end
  431. else
  432. set_location(p^.location,p^.left^.location);
  433. { offset can only differ from 0 if arraydef }
  434. if p^.left^.resulttype^.deftype=arraydef then
  435. dec(p^.location.reference.offset,
  436. get_mul_size*parraydef(p^.left^.resulttype)^.lowrange);
  437. if p^.right^.treetype=ordconstn then
  438. begin
  439. { offset can only differ from 0 if arraydef }
  440. if (p^.left^.resulttype^.deftype=arraydef) then
  441. begin
  442. if not(is_open_array(p^.left^.resulttype)) then
  443. begin
  444. if (p^.right^.value>parraydef(p^.left^.resulttype)^.highrange) or
  445. (p^.right^.value<parraydef(p^.left^.resulttype)^.lowrange) then
  446. begin
  447. if (cs_check_range in aktlocalswitches) then
  448. CGMessage(parser_e_range_check_error)
  449. else
  450. CGMessage(parser_w_range_check_error);
  451. end;
  452. dec(p^.left^.location.reference.offset,
  453. get_mul_size*parraydef(p^.left^.resulttype)^.lowrange);
  454. end
  455. else
  456. begin
  457. { range checking for open arrays !!!! }
  458. {!!!!!!!!!!!!!!!!!}
  459. end;
  460. end
  461. else if (p^.left^.resulttype^.deftype=stringdef) then
  462. begin
  463. if (p^.right^.value=0) and not(is_shortstring(p^.left^.resulttype)) then
  464. CGMessage(cg_e_can_access_element_zero);
  465. if (cs_check_range in aktlocalswitches) then
  466. case pstringdef(p^.left^.resulttype)^.string_typ of
  467. { it's the same for ansi- and wide strings }
  468. st_widestring,
  469. st_ansistring:
  470. begin
  471. pushusedregisters(exprasmlist,pushed,$ff);
  472. push_int(p^.right^.value);
  473. hp:=newreference(p^.location.reference);
  474. dec(hp^.offset,7);
  475. exprasmlist^.concat(new(pai386,op_ref(A_PUSH,S_L,hp)));
  476. emitcall('FPC_ANSISTR_RANGECHECK',true);
  477. popusedregisters(exprasmlist,pushed);
  478. maybe_loadesi;
  479. end;
  480. st_shortstring:
  481. begin
  482. {!!!!!!!!!!!!!!!!!}
  483. end;
  484. st_longstring:
  485. begin
  486. {!!!!!!!!!!!!!!!!!}
  487. end;
  488. end;
  489. end;
  490. inc(p^.left^.location.reference.offset,
  491. get_mul_size*p^.right^.value);
  492. if p^.memseg then
  493. p^.left^.location.reference.segment:=R_FS;
  494. p^.left^.resulttype:=p^.resulttype;
  495. disposetree(p^.right);
  496. _p:=p^.left;
  497. putnode(p);
  498. p:=_p;
  499. end
  500. else
  501. { not treetype=ordconstn }
  502. begin
  503. { quick hack, to overcome Delphi 2 }
  504. if (cs_regalloc in aktglobalswitches) and
  505. (p^.left^.resulttype^.deftype=arraydef) then
  506. begin
  507. extraoffset:=0;
  508. if (p^.right^.treetype=addn) then
  509. begin
  510. if p^.right^.right^.treetype=ordconstn then
  511. begin
  512. extraoffset:=p^.right^.right^.value;
  513. t:=p^.right^.left;
  514. putnode(p^.right);
  515. putnode(p^.right^.right);
  516. p^.right:=t
  517. end
  518. else if p^.right^.left^.treetype=ordconstn then
  519. begin
  520. extraoffset:=p^.right^.left^.value;
  521. t:=p^.right^.right;
  522. putnode(p^.right);
  523. putnode(p^.right^.left);
  524. p^.right:=t
  525. end;
  526. end
  527. else if (p^.right^.treetype=subn) then
  528. begin
  529. if p^.right^.right^.treetype=ordconstn then
  530. begin
  531. extraoffset:=p^.right^.right^.value;
  532. t:=p^.right^.left;
  533. putnode(p^.right);
  534. putnode(p^.right^.right);
  535. p^.right:=t
  536. end
  537. else if p^.right^.left^.treetype=ordconstn then
  538. begin
  539. extraoffset:=p^.right^.left^.value;
  540. t:=p^.right^.right;
  541. putnode(p^.right);
  542. putnode(p^.right^.left);
  543. p^.right:=t
  544. end;
  545. end;
  546. inc(p^.location.reference.offset,
  547. get_mul_size*extraoffset);
  548. end;
  549. { calculate from left to right }
  550. if (p^.location.loc<>LOC_REFERENCE) and
  551. (p^.location.loc<>LOC_MEM) then
  552. CGMessage(cg_e_illegal_expression);
  553. is_pushed:=maybe_push(p^.right^.registers32,p);
  554. secondpass(p^.right);
  555. if is_pushed then
  556. restore(p);
  557. { here we change the location of p^.right
  558. and the update was forgotten so it
  559. led to wrong code in emitrangecheck later PM
  560. so make range check before }
  561. if cs_check_range in aktlocalswitches then
  562. begin
  563. if p^.left^.resulttype^.deftype=arraydef then
  564. begin
  565. if is_open_array(p^.left^.resulttype) then
  566. begin
  567. reset_reference(href);
  568. parraydef(p^.left^.resulttype)^.genrangecheck;
  569. href.symbol:=newasmsymbol(parraydef(p^.left^.resulttype)^.getrangecheckstring);
  570. href.offset:=4;
  571. getsymonlyin(p^.left^.symtable,'high'+pvarsym(p^.left^.symtableentry)^.name);
  572. hightree:=genloadnode(pvarsym(srsym),p^.left^.symtable);
  573. firstpass(hightree);
  574. secondpass(hightree);
  575. emit_mov_loc_ref(hightree^.location,href);
  576. disposetree(hightree);
  577. end;
  578. emitrangecheck(p^.right,p^.left^.resulttype);
  579. end;
  580. end;
  581. case p^.right^.location.loc of
  582. LOC_REGISTER:
  583. begin
  584. ind:=p^.right^.location.register;
  585. case p^.right^.resulttype^.size of
  586. 1:
  587. begin
  588. hr:=reg8toreg32(ind);
  589. emit_reg_reg(A_MOVZX,S_BL,ind,hr);
  590. ind:=hr;
  591. end;
  592. 2:
  593. begin
  594. hr:=reg16toreg32(ind);
  595. emit_reg_reg(A_MOVZX,S_WL,ind,hr);
  596. ind:=hr;
  597. end;
  598. end;
  599. end;
  600. LOC_CREGISTER:
  601. begin
  602. ind:=getregister32;
  603. case p^.right^.resulttype^.size of
  604. 1:
  605. emit_reg_reg(A_MOVZX,S_BL,p^.right^.location.register,ind);
  606. 2:
  607. emit_reg_reg(A_MOVZX,S_WL,p^.right^.location.register,ind);
  608. 4:
  609. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,ind);
  610. end;
  611. end;
  612. LOC_FLAGS:
  613. begin
  614. ind:=getregister32;
  615. emit_flag2reg(p^.right^.location.resflags,reg32toreg8(ind));
  616. emit_reg_reg(A_MOVZX,S_BL,reg32toreg8(ind),ind);
  617. end
  618. else
  619. begin
  620. del_reference(p^.right^.location.reference);
  621. ind:=getregister32;
  622. { Booleans are stored in an 8 bit memory location, so
  623. the use of MOVL is not correct }
  624. case p^.right^.resulttype^.size of
  625. 1 : tai:=new(pai386,op_ref_reg(A_MOVZX,S_BL,newreference(p^.right^.location.reference),ind));
  626. 2 : tai:=new(Pai386,op_ref_reg(A_MOVZX,S_WL,newreference(p^.right^.location.reference),ind));
  627. 4 : tai:=new(Pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),ind));
  628. end;
  629. exprasmlist^.concat(tai);
  630. end;
  631. end;
  632. { produce possible range check code: }
  633. if cs_check_range in aktlocalswitches then
  634. begin
  635. if p^.left^.resulttype^.deftype=arraydef then
  636. begin
  637. { done defore (PM) }
  638. end
  639. else if (p^.left^.resulttype^.deftype=stringdef) then
  640. begin
  641. case pstringdef(p^.left^.resulttype)^.string_typ of
  642. { it's the same for ansi- and wide strings }
  643. st_widestring,
  644. st_ansistring:
  645. begin
  646. pushusedregisters(exprasmlist,pushed,$ff);
  647. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,ind)));
  648. hp:=newreference(p^.location.reference);
  649. dec(hp^.offset,7);
  650. exprasmlist^.concat(new(pai386,op_ref(A_PUSH,S_L,hp)));
  651. emitcall('FPC_ANSISTR_RANGECHECK',true);
  652. popusedregisters(exprasmlist,pushed);
  653. maybe_loadesi;
  654. end;
  655. st_shortstring:
  656. begin
  657. {!!!!!!!!!!!!!!!!!}
  658. end;
  659. st_longstring:
  660. begin
  661. {!!!!!!!!!!!!!!!!!}
  662. end;
  663. end;
  664. end;
  665. end;
  666. if p^.location.reference.index=R_NO then
  667. begin
  668. p^.location.reference.index:=ind;
  669. calc_emit_mul;
  670. end
  671. else
  672. begin
  673. if p^.location.reference.base=R_NO then
  674. begin
  675. case p^.location.reference.scalefactor of
  676. 2 : exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,S_L,1,p^.location.reference.index)));
  677. 4 : exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,S_L,2,p^.location.reference.index)));
  678. 8 : exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,S_L,3,p^.location.reference.index)));
  679. end;
  680. calc_emit_mul;
  681. p^.location.reference.base:=p^.location.reference.index;
  682. p^.location.reference.index:=ind;
  683. end
  684. else
  685. begin
  686. exprasmlist^.concat(new(pai386,op_ref_reg(
  687. A_LEA,S_L,newreference(p^.location.reference),
  688. p^.location.reference.index)));
  689. ungetregister32(p^.location.reference.base);
  690. { the symbol offset is loaded, }
  691. { so release the symbol name and set symbol }
  692. { to nil }
  693. p^.location.reference.symbol:=nil;
  694. p^.location.reference.offset:=0;
  695. calc_emit_mul;
  696. p^.location.reference.base:=p^.location.reference.index;
  697. p^.location.reference.index:=ind;
  698. end;
  699. end;
  700. if p^.memseg then
  701. p^.location.reference.segment:=R_FS;
  702. end;
  703. { have we to remove a temp. wide/ansistring ?
  704. c:=(s1+s2)[i]
  705. for example
  706. }
  707. if (p^.location.loc=LOC_MEM) and
  708. (rl^.deftype=stringdef) then
  709. begin
  710. case pstringdef(rl)^.string_typ of
  711. st_ansistring:
  712. begin
  713. del_reference(p^.location.reference);
  714. hr:=reg32toreg8(getregister32);
  715. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_B,
  716. newreference(p^.location.reference),hr)));
  717. reset_reference(p^.location.reference);
  718. p^.location.loc:=LOC_REGISTER;
  719. p^.location.register:=hr;
  720. end;
  721. st_widestring:
  722. begin
  723. del_reference(p^.location.reference);
  724. hr:=reg32toreg16(getregister32);
  725. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_W,
  726. newreference(p^.location.reference),hr))); reset_reference(p^.location.reference);
  727. p^.location.loc:=LOC_REGISTER;
  728. p^.location.register:=hr;
  729. end;
  730. end;
  731. end;
  732. end;
  733. {*****************************************************************************
  734. SecondSelfN
  735. *****************************************************************************}
  736. procedure secondselfn(var p : ptree);
  737. begin
  738. reset_reference(p^.location.reference);
  739. if (p^.resulttype^.deftype=classrefdef) or
  740. ((p^.resulttype^.deftype=objectdef)
  741. and pobjectdef(p^.resulttype)^.isclass
  742. ) then
  743. p^.location.register:=R_ESI
  744. else
  745. p^.location.reference.base:=R_ESI;
  746. end;
  747. {*****************************************************************************
  748. SecondWithN
  749. *****************************************************************************}
  750. procedure secondwith(var p : ptree);
  751. var
  752. usetemp : boolean;
  753. begin
  754. if assigned(p^.left) then
  755. begin
  756. secondpass(p^.left);
  757. if p^.left^.location.reference.segment<>R_NO then
  758. message(parser_e_no_with_for_variable_in_other_segments);
  759. new(p^.withreference);
  760. usetemp:=false;
  761. if (p^.left^.treetype=loadn) and
  762. (p^.left^.symtable=aktprocsym^.definition^.localst) then
  763. begin
  764. { for locals use the local storage }
  765. p^.withreference^:=p^.left^.location.reference;
  766. p^.islocal:=true;
  767. end
  768. else
  769. if (p^.left^.resulttype^.deftype=objectdef) and
  770. pobjectdef(p^.left^.resulttype)^.isclass then
  771. begin
  772. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  773. newreference(p^.left^.location.reference),R_EDI)));
  774. usetemp:=true;
  775. end
  776. else
  777. begin
  778. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  779. newreference(p^.left^.location.reference),R_EDI)));
  780. usetemp:=true;
  781. end;
  782. { if usetemp is set the value must be in %edi }
  783. if usetemp then
  784. begin
  785. gettempofsizereference(4,p^.withreference^);
  786. normaltemptopersistant(p^.withreference^.offset);
  787. { move to temp reference }
  788. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  789. R_EDI,newreference(p^.withreference^))));
  790. del_reference(p^.left^.location.reference);
  791. end;
  792. { p^.right can be optimize out !!! }
  793. if assigned(p^.right) then
  794. secondpass(p^.right);
  795. if usetemp then
  796. ungetpersistanttemp(p^.withreference^.offset);
  797. dispose(p^.withreference);
  798. p^.withreference:=nil;
  799. end;
  800. end;
  801. end.
  802. {
  803. $Log$
  804. Revision 1.42 1999-05-18 22:11:52 pierre
  805. * checkpointer code was wrong!
  806. Revision 1.41 1999/05/18 21:58:29 florian
  807. * fixed some bugs related to temp. ansistrings and functions results
  808. which return records/objects/arrays which need init/final.
  809. Revision 1.40 1999/05/18 14:15:26 peter
  810. * containsself fixes
  811. * checktypes()
  812. Revision 1.39 1999/05/17 23:51:39 peter
  813. * with temp vars now use a reference with a persistant temp instead
  814. of setting datasize
  815. Revision 1.38 1999/05/17 21:57:05 florian
  816. * new temporary ansistring handling
  817. Revision 1.37 1999/05/17 14:14:14 pierre
  818. + -gc for check pointer with heaptrc
  819. Revision 1.36 1999/05/12 00:19:44 peter
  820. * removed R_DEFAULT_SEG
  821. * uniform float names
  822. Revision 1.35 1999/05/01 13:24:13 peter
  823. * merged nasm compiler
  824. * old asm moved to oldasm/
  825. Revision 1.34 1999/04/26 18:29:54 peter
  826. * farpointerdef moved into pointerdef.is_far
  827. Revision 1.33 1999/03/26 11:43:26 pierre
  828. * bug0236 fixed
  829. Revision 1.32 1999/03/24 23:16:53 peter
  830. * fixed bugs 212,222,225,227,229,231,233
  831. Revision 1.31 1999/02/25 21:02:29 peter
  832. * ag386bin updates
  833. + coff writer
  834. Revision 1.30 1999/02/22 02:15:14 peter
  835. * updates for ag386bin
  836. Revision 1.29 1999/02/07 22:53:07 florian
  837. * potential bug in secondvecn fixed
  838. Revision 1.28 1999/02/04 17:16:51 peter
  839. * fixed crash with temp ansistring indexing
  840. Revision 1.27 1999/02/04 11:44:46 florian
  841. * fixed indexed access of ansistrings to temp. ansistring, i.e.
  842. c:=(s1+s2)[i], the temp is now correctly remove and the generated
  843. code is also fixed
  844. Revision 1.26 1999/02/04 10:49:41 florian
  845. + range checking for ansi- and widestrings
  846. * made it compilable with TP
  847. Revision 1.25 1999/01/21 16:40:52 pierre
  848. * fix for constructor inside with statements
  849. Revision 1.24 1999/01/19 12:05:27 pierre
  850. * bug with @procvar=procvar fiwed
  851. Revision 1.23 1998/12/30 22:15:45 peter
  852. + farpointer type
  853. * absolutesym now also stores if its far
  854. Revision 1.22 1998/12/11 00:02:55 peter
  855. + globtype,tokens,version unit splitted from globals
  856. Revision 1.21 1998/12/10 09:47:18 florian
  857. + basic operations with int64/qord (compiler with -dint64)
  858. + rtti of enumerations extended: names are now written
  859. Revision 1.20 1998/11/25 19:12:54 pierre
  860. * var:=new(pointer_type) support added
  861. Revision 1.19 1998/11/20 15:35:55 florian
  862. * problems with rtti fixed, hope it works
  863. Revision 1.18 1998/11/17 00:36:40 peter
  864. * more ansistring fixes
  865. Revision 1.17 1998/11/16 15:35:09 pierre
  866. * added error for with if different segment
  867. Revision 1.16 1998/10/21 11:44:42 florian
  868. + check for access to index 0 of long/wide/ansi strings added,
  869. gives now an error
  870. * problem with access to contant index of ansistrings fixed
  871. Revision 1.15 1998/10/12 09:49:53 florian
  872. + support of <procedure var type>:=<pointer> in delphi mode added
  873. Revision 1.14 1998/10/02 07:20:37 florian
  874. * range checking in units doesn't work if the units are smartlinked, fixed
  875. Revision 1.13 1998/09/27 10:16:23 florian
  876. * type casts pchar<->ansistring fixed
  877. * ansistring[..] calls does now an unique call
  878. Revision 1.12 1998/09/23 15:46:36 florian
  879. * problem with with and classes fixed
  880. Revision 1.11 1998/09/17 09:42:18 peter
  881. + pass_2 for cg386
  882. * Message() -> CGMessage() for pass_1/pass_2
  883. Revision 1.10 1998/09/14 10:43:52 peter
  884. * all internal RTL functions start with FPC_
  885. Revision 1.9 1998/09/03 16:03:15 florian
  886. + rtti generation
  887. * init table generation changed
  888. Revision 1.8 1998/08/23 21:04:34 florian
  889. + rtti generation for classes added
  890. + new/dispose do now also a call to INITIALIZE/FINALIZE, if necessaray
  891. Revision 1.7 1998/08/20 11:27:40 michael
  892. * Applied Peters Fix
  893. Revision 1.6 1998/08/10 14:49:49 peter
  894. + localswitches, moduleswitches, globalswitches splitting
  895. Revision 1.5 1998/07/26 21:58:58 florian
  896. + better support for switch $H
  897. + index access to ansi strings added
  898. + assigment of data (records/arrays) containing ansi strings
  899. Revision 1.4 1998/07/24 22:16:55 florian
  900. * internal error 10 together with array access fixed. I hope
  901. that's the final fix.
  902. Revision 1.3 1998/06/25 08:48:09 florian
  903. * first version of rtti support
  904. Revision 1.2 1998/06/08 13:13:35 pierre
  905. + temporary variables now in temp_gen.pas unit
  906. because it is processor independent
  907. * mppc68k.bat modified to undefine i386 and support_mmx
  908. (which are defaults for i386)
  909. Revision 1.1 1998/06/05 17:44:13 peter
  910. * splitted cgi386
  911. }