n386mem.pas 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 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 n386mem;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,nmem;
  23. type
  24. ti386loadvmtnode = class(tloadvmtnode)
  25. procedure pass_2;override;
  26. end;
  27. ti386hnewnode = class(thnewnode)
  28. procedure pass_2;override;
  29. end;
  30. ti386newnode = class(tnewnode)
  31. procedure pass_2;override;
  32. end;
  33. ti386hdisposenode = class(thdisposenode)
  34. procedure pass_2;override;
  35. end;
  36. ti386simplenewdisposenode = class(tsimplenewdisposenode)
  37. procedure pass_2;override;
  38. end;
  39. ti386addrnode = class(taddrnode)
  40. procedure pass_2;override;
  41. end;
  42. ti386doubleaddrnode = class(tdoubleaddrnode)
  43. procedure pass_2;override;
  44. end;
  45. ti386derefnode = class(tderefnode)
  46. procedure pass_2;override;
  47. end;
  48. ti386subscriptnode = class(tsubscriptnode)
  49. procedure pass_2;override;
  50. end;
  51. ti386vecnode = class(tvecnode)
  52. procedure pass_2;override;
  53. end;
  54. ti386selfnode = class(tselfnode)
  55. procedure pass_2;override;
  56. end;
  57. ti386withnode = class(twithnode)
  58. procedure pass_2;override;
  59. end;
  60. implementation
  61. uses
  62. {$ifdef delphi}
  63. sysutils,
  64. {$else}
  65. strings,
  66. {$endif}
  67. {$ifdef GDB}
  68. gdb,
  69. {$endif GDB}
  70. globtype,systems,
  71. cutils,verbose,globals,
  72. symconst,symbase,symdef,symsym,symtable,aasm,types,
  73. hcodegen,temp_gen,pass_2,
  74. pass_1,nld,ncon,nadd,
  75. cpubase,cpuasm,
  76. cgai386,tgcpu,n386util;
  77. {*****************************************************************************
  78. TI386LOADNODE
  79. *****************************************************************************}
  80. procedure ti386loadvmtnode.pass_2;
  81. begin
  82. location.register:=getregister32;
  83. emit_sym_ofs_reg(A_MOV,
  84. S_L,newasmsymbol(pobjectdef(pclassrefdef(resulttype)^.pointertype.def)^.vmt_mangledname),0,
  85. location.register);
  86. end;
  87. {*****************************************************************************
  88. TI386HNEWNODE
  89. *****************************************************************************}
  90. procedure ti386hnewnode.pass_2;
  91. begin
  92. end;
  93. {*****************************************************************************
  94. TI386NEWNODE
  95. *****************************************************************************}
  96. procedure ti386newnode.pass_2;
  97. var
  98. pushed : tpushed;
  99. r : preference;
  100. begin
  101. if assigned(left) then
  102. begin
  103. secondpass(left);
  104. location.register:=left.location.register;
  105. end
  106. else
  107. begin
  108. pushusedregisters(pushed,$ff);
  109. gettempofsizereference(target_os.size_of_pointer,location.reference);
  110. { determines the size of the mem block }
  111. push_int(ppointerdef(resulttype)^.pointertype.def^.size);
  112. emit_push_lea_loc(location,false);
  113. saveregvars($ff);
  114. emitcall('FPC_GETMEM');
  115. if ppointerdef(resulttype)^.pointertype.def^.needs_inittable then
  116. begin
  117. new(r);
  118. reset_reference(r^);
  119. r^.symbol:=pstoreddef(ppointerdef(left.resulttype)^.pointertype.def)^.get_inittable_label;
  120. emitpushreferenceaddr(r^);
  121. dispose(r);
  122. { push pointer we just allocated, we need to initialize the
  123. data located at that pointer not the pointer self (PFV) }
  124. emit_push_loc(location);
  125. emitcall('FPC_INITIALIZE');
  126. end;
  127. popusedregisters(pushed);
  128. { may be load ESI }
  129. maybe_loadesi;
  130. end;
  131. if codegenerror then
  132. exit;
  133. end;
  134. {*****************************************************************************
  135. TI386HDISPOSENODE
  136. *****************************************************************************}
  137. procedure ti386hdisposenode.pass_2;
  138. begin
  139. secondpass(left);
  140. if codegenerror then
  141. exit;
  142. reset_reference(location.reference);
  143. case left.location.loc of
  144. LOC_REGISTER:
  145. location.reference.index:=left.location.register;
  146. LOC_CREGISTER:
  147. begin
  148. location.reference.index:=getregister32;
  149. emit_reg_reg(A_MOV,S_L,
  150. left.location.register,
  151. location.reference.index);
  152. end;
  153. LOC_MEM,LOC_REFERENCE :
  154. begin
  155. del_reference(left.location.reference);
  156. location.reference.index:=getregister32;
  157. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  158. location.reference.index);
  159. end;
  160. end;
  161. end;
  162. {*****************************************************************************
  163. TI386SIMPLENEWDISPOSENODE
  164. *****************************************************************************}
  165. procedure ti386simplenewdisposenode.pass_2;
  166. var
  167. pushed : tpushed;
  168. r : preference;
  169. begin
  170. secondpass(left);
  171. if codegenerror then
  172. exit;
  173. pushusedregisters(pushed,$ff);
  174. saveregvars($ff);
  175. { call the mem handling procedures }
  176. case nodetype of
  177. simpledisposen:
  178. begin
  179. if ppointerdef(left.resulttype)^.pointertype.def^.needs_inittable then
  180. begin
  181. new(r);
  182. reset_reference(r^);
  183. r^.symbol:=pstoreddef(ppointerdef(left.resulttype)^.pointertype.def)^.get_inittable_label;
  184. emitpushreferenceaddr(r^);
  185. dispose(r);
  186. { push pointer adress }
  187. emit_push_loc(left.location);
  188. emitcall('FPC_FINALIZE');
  189. end;
  190. emit_push_lea_loc(left.location,true);
  191. emitcall('FPC_FREEMEM');
  192. end;
  193. simplenewn:
  194. begin
  195. { determines the size of the mem block }
  196. push_int(ppointerdef(left.resulttype)^.pointertype.def^.size);
  197. emit_push_lea_loc(left.location,true);
  198. emitcall('FPC_GETMEM');
  199. if ppointerdef(left.resulttype)^.pointertype.def^.needs_inittable then
  200. begin
  201. new(r);
  202. reset_reference(r^);
  203. r^.symbol:=pstoreddef(ppointerdef(left.resulttype)^.pointertype.def)^.get_inittable_label;
  204. emitpushreferenceaddr(r^);
  205. dispose(r);
  206. emit_push_loc(left.location);
  207. emitcall('FPC_INITIALIZE');
  208. end;
  209. end;
  210. end;
  211. popusedregisters(pushed);
  212. { may be load ESI }
  213. maybe_loadesi;
  214. end;
  215. {*****************************************************************************
  216. TI386ADDRNODE
  217. *****************************************************************************}
  218. procedure ti386addrnode.pass_2;
  219. begin
  220. secondpass(left);
  221. { when loading procvar we do nothing with this node, so load the
  222. location of left }
  223. if nf_procvarload in flags then
  224. begin
  225. set_location(location,left.location);
  226. exit;
  227. end;
  228. location.loc:=LOC_REGISTER;
  229. del_reference(left.location.reference);
  230. location.register:=getregister32;
  231. {@ on a procvar means returning an address to the procedure that
  232. is stored in it.}
  233. { yes but left.symtableentry can be nil
  234. for example on @self !! }
  235. { symtableentry can be also invalid, if left is no tree node }
  236. if (m_tp_procvar in aktmodeswitches) and
  237. (left.nodetype=loadn) and
  238. assigned(tloadnode(left).symtableentry) and
  239. (tloadnode(left).symtableentry^.typ=varsym) and
  240. (pvarsym(tloadnode(left).symtableentry)^.vartype.def^.deftype=procvardef) then
  241. emit_ref_reg(A_MOV,S_L,
  242. newreference(left.location.reference),
  243. location.register)
  244. else
  245. emit_ref_reg(A_LEA,S_L,
  246. newreference(left.location.reference),
  247. location.register);
  248. { for use of other segments }
  249. if left.location.reference.segment<>R_NO then
  250. location.segment:=left.location.reference.segment;
  251. end;
  252. {*****************************************************************************
  253. TI386DOUBLEADDRNODE
  254. *****************************************************************************}
  255. procedure ti386doubleaddrnode.pass_2;
  256. begin
  257. secondpass(left);
  258. location.loc:=LOC_REGISTER;
  259. del_reference(left.location.reference);
  260. location.register:=getregister32;
  261. emit_ref_reg(A_LEA,S_L,
  262. newreference(left.location.reference),
  263. location.register);
  264. end;
  265. {*****************************************************************************
  266. TI386DEREFNODE
  267. *****************************************************************************}
  268. procedure ti386derefnode.pass_2;
  269. var
  270. hr : tregister;
  271. begin
  272. secondpass(left);
  273. reset_reference(location.reference);
  274. case left.location.loc of
  275. LOC_REGISTER:
  276. location.reference.base:=left.location.register;
  277. LOC_CREGISTER:
  278. begin
  279. { ... and reserve one for the pointer }
  280. hr:=getregister32;
  281. emit_reg_reg(A_MOV,S_L,left.location.register,hr);
  282. location.reference.base:=hr;
  283. end;
  284. else
  285. begin
  286. { free register }
  287. del_reference(left.location.reference);
  288. { ...and reserve one for the pointer }
  289. hr:=getregister32;
  290. emit_ref_reg(
  291. A_MOV,S_L,newreference(left.location.reference),
  292. hr);
  293. location.reference.base:=hr;
  294. end;
  295. end;
  296. if ppointerdef(left.resulttype)^.is_far then
  297. location.reference.segment:=R_FS;
  298. if not ppointerdef(left.resulttype)^.is_far and
  299. (cs_gdb_heaptrc in aktglobalswitches) and
  300. (cs_checkpointer in aktglobalswitches) then
  301. begin
  302. emit_reg(
  303. A_PUSH,S_L,location.reference.base);
  304. emitcall('FPC_CHECKPOINTER');
  305. end;
  306. end;
  307. {*****************************************************************************
  308. TI386SUBSCRIPTNODE
  309. *****************************************************************************}
  310. procedure ti386subscriptnode.pass_2;
  311. var
  312. hr : tregister;
  313. begin
  314. secondpass(left);
  315. if codegenerror then
  316. exit;
  317. { classes and interfaces must be dereferenced implicit }
  318. if is_class_or_interface(left.resulttype) then
  319. begin
  320. reset_reference(location.reference);
  321. case left.location.loc of
  322. LOC_REGISTER:
  323. location.reference.base:=left.location.register;
  324. LOC_CREGISTER:
  325. begin
  326. { ... and reserve one for the pointer }
  327. hr:=getregister32;
  328. emit_reg_reg(A_MOV,S_L,left.location.register,hr);
  329. location.reference.base:=hr;
  330. end;
  331. else
  332. begin
  333. { free register }
  334. del_reference(left.location.reference);
  335. { ... and reserve one for the pointer }
  336. hr:=getregister32;
  337. emit_ref_reg(
  338. A_MOV,S_L,newreference(left.location.reference),
  339. hr);
  340. location.reference.base:=hr;
  341. end;
  342. end;
  343. end
  344. else if is_interfacecom(left.resulttype) then
  345. begin
  346. gettempintfcomreference(location.reference);
  347. emit_mov_loc_ref(left.location,location.reference,S_L,false);
  348. end
  349. else
  350. set_location(location,left.location);
  351. inc(location.reference.offset,vs^.address);
  352. end;
  353. {*****************************************************************************
  354. TI386VECNODE
  355. *****************************************************************************}
  356. procedure ti386vecnode.pass_2;
  357. var
  358. is_pushed : boolean;
  359. ind,hr : tregister;
  360. //_p : tnode;
  361. function get_mul_size:longint;
  362. begin
  363. if nf_memindex in flags then
  364. get_mul_size:=1
  365. else
  366. begin
  367. if (left.resulttype^.deftype=arraydef) then
  368. get_mul_size:=parraydef(left.resulttype)^.elesize
  369. else
  370. get_mul_size:=resulttype^.size;
  371. end
  372. end;
  373. procedure calc_emit_mul;
  374. var
  375. l1,l2 : longint;
  376. begin
  377. l1:=get_mul_size;
  378. case l1 of
  379. 1,2,4,8 : location.reference.scalefactor:=l1;
  380. else
  381. begin
  382. if ispowerof2(l1,l2) then
  383. emit_const_reg(A_SHL,S_L,l2,ind)
  384. else
  385. emit_const_reg(A_IMUL,S_L,l1,ind);
  386. end;
  387. end;
  388. end;
  389. var
  390. extraoffset : longint;
  391. { rl stores the resulttype of the left node, this is necessary }
  392. { to detect if it is an ansistring }
  393. { because in constant nodes which constant index }
  394. { the left tree is removed }
  395. t : tnode;
  396. hp : preference;
  397. href : treference;
  398. tai : Taicpu;
  399. pushed : tpushed;
  400. hightree : tnode;
  401. hl,otl,ofl : pasmlabel;
  402. begin
  403. secondpass(left);
  404. { we load the array reference to location }
  405. { an ansistring needs to be dereferenced }
  406. if is_ansistring(left.resulttype) or
  407. is_widestring(left.resulttype) then
  408. begin
  409. reset_reference(location.reference);
  410. if nf_callunique in flags then
  411. begin
  412. if left.location.loc<>LOC_REFERENCE then
  413. begin
  414. CGMessage(cg_e_illegal_expression);
  415. exit;
  416. end;
  417. pushusedregisters(pushed,$ff);
  418. emitpushreferenceaddr(left.location.reference);
  419. saveregvars($ff);
  420. if is_ansistring(left.resulttype) then
  421. emitcall('FPC_ANSISTR_UNIQUE')
  422. else
  423. emitcall('FPC_WIDESTR_UNIQUE');
  424. maybe_loadesi;
  425. popusedregisters(pushed);
  426. end;
  427. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  428. begin
  429. location.reference.base:=left.location.register;
  430. end
  431. else
  432. begin
  433. del_reference(left.location.reference);
  434. location.reference.base:=getregister32;
  435. emit_ref_reg(A_MOV,S_L,
  436. newreference(left.location.reference),
  437. location.reference.base);
  438. end;
  439. { check for a zero length string,
  440. we can use the ansistring routine here }
  441. if (cs_check_range in aktlocalswitches) then
  442. begin
  443. pushusedregisters(pushed,$ff);
  444. emit_reg(A_PUSH,S_L,location.reference.base);
  445. saveregvars($ff);
  446. emitcall('FPC_ANSISTR_CHECKZERO');
  447. maybe_loadesi;
  448. popusedregisters(pushed);
  449. end;
  450. if is_ansistring(left.resulttype) then
  451. { in ansistrings S[1] is pchar(S)[0] !! }
  452. dec(location.reference.offset)
  453. else
  454. begin
  455. { in widestrings S[1] is pwchar(S)[0] !! }
  456. dec(location.reference.offset,2);
  457. emit_const_reg(A_SHL,S_L,
  458. 1,location.reference.base);
  459. end;
  460. { we've also to keep left up-to-date, because it is used }
  461. { if a constant array index occurs, subject to change (FK) }
  462. set_location(left.location,location);
  463. end
  464. else if is_dynamic_array(left.resulttype) then
  465. { ... also a dynamic string }
  466. begin
  467. reset_reference(location.reference);
  468. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  469. begin
  470. location.reference.base:=left.location.register;
  471. end
  472. else
  473. begin
  474. del_reference(left.location.reference);
  475. location.reference.base:=getregister32;
  476. emit_ref_reg(A_MOV,S_L,
  477. newreference(left.location.reference),
  478. location.reference.base);
  479. end;
  480. {$warning FIXME}
  481. { check for a zero length string,
  482. we can use the ansistring routine here }
  483. if (cs_check_range in aktlocalswitches) then
  484. begin
  485. pushusedregisters(pushed,$ff);
  486. emit_reg(A_PUSH,S_L,location.reference.base);
  487. saveregvars($ff);
  488. emitcall('FPC_ANSISTR_CHECKZERO');
  489. maybe_loadesi;
  490. popusedregisters(pushed);
  491. end;
  492. { we've also to keep left up-to-date, because it is used }
  493. { if a constant array index occurs, subject to change (FK) }
  494. set_location(left.location,location);
  495. end
  496. else
  497. set_location(location,left.location);
  498. { offset can only differ from 0 if arraydef }
  499. if (left.resulttype^.deftype=arraydef) and
  500. not(is_dynamic_array(left.resulttype)) then
  501. dec(location.reference.offset,
  502. get_mul_size*parraydef(left.resulttype)^.lowrange);
  503. if right.nodetype=ordconstn then
  504. begin
  505. { offset can only differ from 0 if arraydef }
  506. if (left.resulttype^.deftype=arraydef) then
  507. begin
  508. if not(is_open_array(left.resulttype)) and
  509. not(is_array_of_const(left.resulttype)) and
  510. not(is_dynamic_array(left.resulttype)) then
  511. begin
  512. if (tordconstnode(right).value>parraydef(left.resulttype)^.highrange) or
  513. (tordconstnode(right).value<parraydef(left.resulttype)^.lowrange) then
  514. begin
  515. if (cs_check_range in aktlocalswitches) then
  516. CGMessage(parser_e_range_check_error)
  517. else
  518. CGMessage(parser_w_range_check_error);
  519. end;
  520. dec(left.location.reference.offset,
  521. get_mul_size*parraydef(left.resulttype)^.lowrange);
  522. end
  523. else
  524. begin
  525. { range checking for open and dynamic arrays !!!! }
  526. {$warning FIXME}
  527. {!!!!!!!!!!!!!!!!!}
  528. end;
  529. end
  530. else if (left.resulttype^.deftype=stringdef) then
  531. begin
  532. if (tordconstnode(right).value=0) and not(is_shortstring(left.resulttype)) then
  533. CGMessage(cg_e_can_access_element_zero);
  534. if (cs_check_range in aktlocalswitches) then
  535. case pstringdef(left.resulttype)^.string_typ of
  536. { it's the same for ansi- and wide strings }
  537. st_widestring,
  538. st_ansistring:
  539. begin
  540. pushusedregisters(pushed,$ff);
  541. push_int(tordconstnode(right).value);
  542. hp:=newreference(location.reference);
  543. dec(hp^.offset,7);
  544. emit_ref(A_PUSH,S_L,hp);
  545. saveregvars($ff);
  546. emitcall('FPC_ANSISTR_RANGECHECK');
  547. popusedregisters(pushed);
  548. maybe_loadesi;
  549. end;
  550. st_shortstring:
  551. begin
  552. {!!!!!!!!!!!!!!!!!}
  553. end;
  554. st_longstring:
  555. begin
  556. {!!!!!!!!!!!!!!!!!}
  557. end;
  558. end;
  559. end;
  560. inc(left.location.reference.offset,
  561. get_mul_size*tordconstnode(right).value);
  562. if nf_memseg in flags then
  563. left.location.reference.segment:=R_FS;
  564. {
  565. left.resulttype:=resulttype;
  566. disposetree(right);
  567. _p:=left;
  568. putnode(p);
  569. p:=_p;
  570. }
  571. set_location(location,left.location);
  572. end
  573. else
  574. { not nodetype=ordconstn }
  575. begin
  576. if (cs_regalloc in aktglobalswitches) and
  577. { if we do range checking, we don't }
  578. { need that fancy code (it would be }
  579. { buggy) }
  580. not(cs_check_range in aktlocalswitches) and
  581. (left.resulttype^.deftype=arraydef) then
  582. begin
  583. extraoffset:=0;
  584. if (right.nodetype=addn) then
  585. begin
  586. if taddnode(right).right.nodetype=ordconstn then
  587. begin
  588. extraoffset:=tordconstnode(taddnode(right).right).value;
  589. t:=taddnode(right).left;
  590. { First pass processed this with the assumption }
  591. { that there was an add node which may require an }
  592. { extra register. Fake it or die with IE10 (JM) }
  593. t.registers32 := taddnode(right).registers32;
  594. taddnode(right).left:=nil;
  595. right.free;
  596. right:=t;
  597. end
  598. else if tordconstnode(taddnode(right).left).nodetype=ordconstn then
  599. begin
  600. extraoffset:=tordconstnode(taddnode(right).left).value;
  601. t:=taddnode(right).right;
  602. t.registers32 := right.registers32;
  603. taddnode(right).right:=nil;
  604. right.free;
  605. right:=t;
  606. end;
  607. end
  608. else if (right.nodetype=subn) then
  609. begin
  610. if taddnode(right).right.nodetype=ordconstn then
  611. begin
  612. { this was "extraoffset:=right.right.value;" Looks a bit like
  613. copy-paste bug :) (JM) }
  614. extraoffset:=-tordconstnode(taddnode(right).right).value;
  615. t:=taddnode(right).left;
  616. t.registers32 := right.registers32;
  617. taddnode(right).left:=nil;
  618. right.free;
  619. right:=t;
  620. end
  621. { You also have to negate right.right in this case! I can't add an
  622. unaryminusn without causing a crash, so I've disabled it (JM)
  623. else if right.left.nodetype=ordconstn then
  624. begin
  625. extraoffset:=right.left.value;
  626. t:=right.right;
  627. t^.registers32 := right.registers32;
  628. putnode(right);
  629. putnode(right.left);
  630. right:=t;
  631. end;}
  632. end;
  633. inc(location.reference.offset,
  634. get_mul_size*extraoffset);
  635. end;
  636. { calculate from left to right }
  637. if (location.loc<>LOC_REFERENCE) and
  638. (location.loc<>LOC_MEM) then
  639. CGMessage(cg_e_illegal_expression);
  640. if (right.location.loc=LOC_JUMP) then
  641. begin
  642. otl:=truelabel;
  643. getlabel(truelabel);
  644. ofl:=falselabel;
  645. getlabel(falselabel);
  646. end;
  647. is_pushed:=maybe_push(right.registers32,self,false);
  648. secondpass(right);
  649. if is_pushed then
  650. restore(self,false);
  651. { here we change the location of right
  652. and the update was forgotten so it
  653. led to wrong code in emitrangecheck later PM
  654. so make range check before }
  655. if cs_check_range in aktlocalswitches then
  656. begin
  657. if left.resulttype^.deftype=arraydef then
  658. begin
  659. if is_open_array(left.resulttype) or
  660. is_array_of_const(left.resulttype) then
  661. begin
  662. reset_reference(href);
  663. parraydef(left.resulttype)^.genrangecheck;
  664. href.symbol:=newasmsymbol(parraydef(left.resulttype)^.getrangecheckstring);
  665. href.offset:=4;
  666. getsymonlyin(tloadnode(left).symtable,
  667. 'high'+pvarsym(tloadnode(left).symtableentry)^.name);
  668. hightree:=genloadnode(pvarsym(srsym),tloadnode(left).symtable);
  669. firstpass(hightree);
  670. secondpass(hightree);
  671. emit_mov_loc_ref(hightree.location,href,S_L,true);
  672. hightree.free;
  673. hightree:=nil;
  674. end;
  675. emitrangecheck(right,left.resulttype);
  676. end;
  677. end;
  678. case right.location.loc of
  679. LOC_REGISTER:
  680. begin
  681. ind:=right.location.register;
  682. case right.resulttype^.size of
  683. 1:
  684. begin
  685. hr:=reg8toreg32(ind);
  686. emit_reg_reg(A_MOVZX,S_BL,ind,hr);
  687. ind:=hr;
  688. end;
  689. 2:
  690. begin
  691. hr:=reg16toreg32(ind);
  692. emit_reg_reg(A_MOVZX,S_WL,ind,hr);
  693. ind:=hr;
  694. end;
  695. end;
  696. end;
  697. LOC_CREGISTER:
  698. begin
  699. ind:=getregister32;
  700. case right.resulttype^.size of
  701. 1:
  702. emit_reg_reg(A_MOVZX,S_BL,right.location.register,ind);
  703. 2:
  704. emit_reg_reg(A_MOVZX,S_WL,right.location.register,ind);
  705. 4:
  706. emit_reg_reg(A_MOV,S_L,right.location.register,ind);
  707. end;
  708. end;
  709. LOC_FLAGS:
  710. begin
  711. ind:=getregister32;
  712. emit_flag2reg(right.location.resflags,reg32toreg8(ind));
  713. emit_reg_reg(A_MOVZX,S_BL,reg32toreg8(ind),ind);
  714. end;
  715. LOC_JUMP :
  716. begin
  717. ind:=getregister32;
  718. emitlab(truelabel);
  719. truelabel:=otl;
  720. emit_const_reg(A_MOV,S_L,1,ind);
  721. getlabel(hl);
  722. emitjmp(C_None,hl);
  723. emitlab(falselabel);
  724. falselabel:=ofl;
  725. emit_reg_reg(A_XOR,S_L,ind,ind);
  726. emitlab(hl);
  727. end;
  728. LOC_REFERENCE,LOC_MEM :
  729. begin
  730. del_reference(right.location.reference);
  731. ind:=getregister32;
  732. { Booleans are stored in an 8 bit memory location, so
  733. the use of MOVL is not correct }
  734. case right.resulttype^.size of
  735. 1 : tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,newreference(right.location.reference),ind);
  736. 2 : tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,newreference(right.location.reference),ind);
  737. 4 : tai:=Taicpu.Op_ref_reg(A_MOV,S_L,newreference(right.location.reference),ind);
  738. end;
  739. exprasmList.concat(tai);
  740. end;
  741. else
  742. internalerror(5913428);
  743. end;
  744. { produce possible range check code: }
  745. if cs_check_range in aktlocalswitches then
  746. begin
  747. if left.resulttype^.deftype=arraydef then
  748. begin
  749. { done defore (PM) }
  750. end
  751. else if (left.resulttype^.deftype=stringdef) then
  752. begin
  753. case pstringdef(left.resulttype)^.string_typ of
  754. { it's the same for ansi- and wide strings }
  755. st_widestring,
  756. st_ansistring:
  757. begin
  758. pushusedregisters(pushed,$ff);
  759. emit_reg(A_PUSH,S_L,ind);
  760. hp:=newreference(location.reference);
  761. dec(hp^.offset,7);
  762. emit_ref(A_PUSH,S_L,hp);
  763. saveregvars($ff);
  764. emitcall('FPC_ANSISTR_RANGECHECK');
  765. popusedregisters(pushed);
  766. maybe_loadesi;
  767. end;
  768. st_shortstring:
  769. begin
  770. {!!!!!!!!!!!!!!!!!}
  771. end;
  772. st_longstring:
  773. begin
  774. {!!!!!!!!!!!!!!!!!}
  775. end;
  776. end;
  777. end;
  778. end;
  779. if location.reference.index=R_NO then
  780. begin
  781. location.reference.index:=ind;
  782. calc_emit_mul;
  783. end
  784. else
  785. begin
  786. if location.reference.base=R_NO then
  787. begin
  788. case location.reference.scalefactor of
  789. 2 : emit_const_reg(A_SHL,S_L,1,location.reference.index);
  790. 4 : emit_const_reg(A_SHL,S_L,2,location.reference.index);
  791. 8 : emit_const_reg(A_SHL,S_L,3,location.reference.index);
  792. end;
  793. calc_emit_mul;
  794. location.reference.base:=location.reference.index;
  795. location.reference.index:=ind;
  796. end
  797. else
  798. begin
  799. emit_ref_reg(
  800. A_LEA,S_L,newreference(location.reference),
  801. location.reference.index);
  802. ungetregister32(location.reference.base);
  803. { the symbol offset is loaded, }
  804. { so release the symbol name and set symbol }
  805. { to nil }
  806. location.reference.symbol:=nil;
  807. location.reference.offset:=0;
  808. calc_emit_mul;
  809. location.reference.base:=location.reference.index;
  810. location.reference.index:=ind;
  811. end;
  812. end;
  813. if nf_memseg in flags then
  814. location.reference.segment:=R_FS;
  815. end;
  816. end;
  817. {*****************************************************************************
  818. TI386SELFNODE
  819. *****************************************************************************}
  820. procedure ti386selfnode.pass_2;
  821. begin
  822. reset_reference(location.reference);
  823. getexplicitregister32(R_ESI);
  824. if (resulttype^.deftype=classrefdef) or
  825. is_class(resulttype) then
  826. location.register:=R_ESI
  827. else
  828. location.reference.base:=R_ESI;
  829. end;
  830. {*****************************************************************************
  831. TI386WITHNODE
  832. *****************************************************************************}
  833. procedure ti386withnode.pass_2;
  834. var
  835. usetemp,with_expr_in_temp : boolean;
  836. {$ifdef GDB}
  837. withstartlabel,withendlabel : pasmlabel;
  838. pp : pchar;
  839. mangled_length : longint;
  840. const
  841. withlevel : longint = 0;
  842. {$endif GDB}
  843. begin
  844. if assigned(left) then
  845. begin
  846. secondpass(left);
  847. if left.location.reference.segment<>R_NO then
  848. message(parser_e_no_with_for_variable_in_other_segments);
  849. new(withreference);
  850. usetemp:=false;
  851. if (left.nodetype=loadn) and
  852. (tloadnode(left).symtable=aktprocsym^.definition^.localst) then
  853. begin
  854. { for locals use the local storage }
  855. withreference^:=left.location.reference;
  856. include(flags,nf_islocal);
  857. end
  858. else
  859. { call can have happend with a property }
  860. if is_class_or_interface(left.resulttype) then
  861. begin
  862. {$ifndef noAllocEdi}
  863. getexplicitregister32(R_EDI);
  864. {$endif noAllocEdi}
  865. emit_mov_loc_reg(left.location,R_EDI);
  866. usetemp:=true;
  867. end
  868. else
  869. begin
  870. {$ifndef noAllocEdi}
  871. getexplicitregister32(R_EDI);
  872. {$endif noAllocEdi}
  873. emit_lea_loc_reg(left.location,R_EDI,false);
  874. usetemp:=true;
  875. end;
  876. release_loc(left.location);
  877. { if the with expression is stored in a temp }
  878. { area we must make it persistent and shouldn't }
  879. { release it (FK) }
  880. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  881. istemp(left.location.reference) then
  882. begin
  883. normaltemptopersistant(left.location.reference.offset);
  884. with_expr_in_temp:=true;
  885. end
  886. else
  887. with_expr_in_temp:=false;
  888. { if usetemp is set the value must be in %edi }
  889. if usetemp then
  890. begin
  891. gettempofsizereference(4,withreference^);
  892. normaltemptopersistant(withreference^.offset);
  893. { move to temp reference }
  894. emit_reg_ref(A_MOV,S_L,R_EDI,newreference(withreference^));
  895. {$ifndef noAllocEdi}
  896. ungetregister32(R_EDI);
  897. {$endif noAllocEdi}
  898. {$ifdef GDB}
  899. if (cs_debuginfo in aktmoduleswitches) then
  900. begin
  901. inc(withlevel);
  902. getaddrlabel(withstartlabel);
  903. getaddrlabel(withendlabel);
  904. emitlab(withstartlabel);
  905. withdebugList.concat(Tai_stabs.Create(strpnew(
  906. '"with'+tostr(withlevel)+':'+tostr(symtablestack^.getnewtypecount)+
  907. '=*'+pstoreddef(left.resulttype)^.numberstring+'",'+
  908. tostr(N_LSYM)+',0,0,'+tostr(withreference^.offset))));
  909. mangled_length:=length(aktprocsym^.definition^.mangledname);
  910. getmem(pp,mangled_length+50);
  911. strpcopy(pp,'192,0,0,'+withstartlabel^.name);
  912. if (target_os.use_function_relative_addresses) then
  913. begin
  914. strpcopy(strend(pp),'-');
  915. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  916. end;
  917. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  918. end;
  919. {$endif GDB}
  920. end;
  921. { right can be optimize out !!! }
  922. if assigned(right) then
  923. secondpass(right);
  924. if usetemp then
  925. begin
  926. ungetpersistanttemp(withreference^.offset);
  927. {$ifdef GDB}
  928. if (cs_debuginfo in aktmoduleswitches) then
  929. begin
  930. emitlab(withendlabel);
  931. strpcopy(pp,'224,0,0,'+withendlabel^.name);
  932. if (target_os.use_function_relative_addresses) then
  933. begin
  934. strpcopy(strend(pp),'-');
  935. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  936. end;
  937. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  938. freemem(pp,mangled_length+50);
  939. dec(withlevel);
  940. end;
  941. {$endif GDB}
  942. end;
  943. if with_expr_in_temp then
  944. ungetpersistanttemp(left.location.reference.offset);
  945. dispose(withreference);
  946. withreference:=nil;
  947. end;
  948. end;
  949. begin
  950. cloadvmtnode:=ti386loadvmtnode;
  951. chnewnode:=ti386hnewnode;
  952. cnewnode:=ti386newnode;
  953. chdisposenode:=ti386hdisposenode;
  954. csimplenewdisposenode:=ti386simplenewdisposenode;
  955. caddrnode:=ti386addrnode;
  956. cdoubleaddrnode:=ti386doubleaddrnode;
  957. cderefnode:=ti386derefnode;
  958. csubscriptnode:=ti386subscriptnode;
  959. cvecnode:=ti386vecnode;
  960. cselfnode:=ti386selfnode;
  961. cwithnode:=ti386withnode;
  962. end.
  963. {
  964. $Log$
  965. Revision 1.8 2000-12-25 00:07:33 peter
  966. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  967. tlinkedlist objects)
  968. Revision 1.7 2000/12/05 11:44:33 jonas
  969. + new integer regvar handling, should be much more efficient
  970. Revision 1.6 2000/11/29 00:30:48 florian
  971. * unused units removed from uses clause
  972. * some changes for widestrings
  973. Revision 1.5 2000/11/04 14:25:24 florian
  974. + merged Attila's changes for interfaces, not tested yet
  975. Revision 1.4 2000/10/31 22:02:57 peter
  976. * symtable splitted, no real code changes
  977. Revision 1.3 2000/10/31 14:18:53 jonas
  978. * merged double deleting of left location when using a temp in
  979. secondwith (merged from fixes branch). This also fixes web bug1194
  980. Revision 1.2 2000/10/21 18:16:13 florian
  981. * a lot of changes:
  982. - basic dyn. array support
  983. - basic C++ support
  984. - some work for interfaces done
  985. ....
  986. Revision 1.1 2000/10/15 09:33:32 peter
  987. * moved n386*.pas to i386/ cpu_target dir
  988. Revision 1.2 2000/10/14 21:52:54 peter
  989. * fixed memory leaks
  990. Revision 1.1 2000/10/14 10:14:49 peter
  991. * moehrendorf oct 2000 rewrite
  992. }