n386mem.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  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,symtype,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(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. srsym : psym;
  400. pushed : tpushed;
  401. hightree : tnode;
  402. hl,otl,ofl : pasmlabel;
  403. begin
  404. secondpass(left);
  405. { we load the array reference to location }
  406. { an ansistring needs to be dereferenced }
  407. if is_ansistring(left.resulttype) or
  408. is_widestring(left.resulttype) then
  409. begin
  410. reset_reference(location.reference);
  411. if nf_callunique in flags then
  412. begin
  413. if left.location.loc<>LOC_REFERENCE then
  414. begin
  415. CGMessage(cg_e_illegal_expression);
  416. exit;
  417. end;
  418. pushusedregisters(pushed,$ff);
  419. emitpushreferenceaddr(left.location.reference);
  420. saveregvars($ff);
  421. if is_ansistring(left.resulttype) then
  422. emitcall('FPC_ANSISTR_UNIQUE')
  423. else
  424. emitcall('FPC_WIDESTR_UNIQUE');
  425. maybe_loadesi;
  426. popusedregisters(pushed);
  427. end;
  428. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  429. begin
  430. location.reference.base:=left.location.register;
  431. end
  432. else
  433. begin
  434. del_reference(left.location.reference);
  435. location.reference.base:=getregister32;
  436. emit_ref_reg(A_MOV,S_L,
  437. newreference(left.location.reference),
  438. location.reference.base);
  439. end;
  440. { check for a zero length string,
  441. we can use the ansistring routine here }
  442. if (cs_check_range in aktlocalswitches) then
  443. begin
  444. pushusedregisters(pushed,$ff);
  445. emit_reg(A_PUSH,S_L,location.reference.base);
  446. saveregvars($ff);
  447. emitcall('FPC_ANSISTR_CHECKZERO');
  448. maybe_loadesi;
  449. popusedregisters(pushed);
  450. end;
  451. if is_ansistring(left.resulttype) then
  452. { in ansistrings S[1] is pchar(S)[0] !! }
  453. dec(location.reference.offset)
  454. else
  455. begin
  456. { in widestrings S[1] is pwchar(S)[0] !! }
  457. dec(location.reference.offset,2);
  458. emit_const_reg(A_SHL,S_L,
  459. 1,location.reference.base);
  460. end;
  461. { we've also to keep left up-to-date, because it is used }
  462. { if a constant array index occurs, subject to change (FK) }
  463. set_location(left.location,location);
  464. end
  465. else if is_dynamic_array(left.resulttype) then
  466. { ... also a dynamic string }
  467. begin
  468. reset_reference(location.reference);
  469. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  470. begin
  471. location.reference.base:=left.location.register;
  472. end
  473. else
  474. begin
  475. del_reference(left.location.reference);
  476. location.reference.base:=getregister32;
  477. emit_ref_reg(A_MOV,S_L,
  478. newreference(left.location.reference),
  479. location.reference.base);
  480. end;
  481. {$warning FIXME}
  482. { check for a zero length string,
  483. we can use the ansistring routine here }
  484. if (cs_check_range in aktlocalswitches) then
  485. begin
  486. pushusedregisters(pushed,$ff);
  487. emit_reg(A_PUSH,S_L,location.reference.base);
  488. saveregvars($ff);
  489. emitcall('FPC_ANSISTR_CHECKZERO');
  490. maybe_loadesi;
  491. popusedregisters(pushed);
  492. end;
  493. { we've also to keep left up-to-date, because it is used }
  494. { if a constant array index occurs, subject to change (FK) }
  495. set_location(left.location,location);
  496. end
  497. else
  498. set_location(location,left.location);
  499. { offset can only differ from 0 if arraydef }
  500. if (left.resulttype^.deftype=arraydef) and
  501. not(is_dynamic_array(left.resulttype)) then
  502. dec(location.reference.offset,
  503. get_mul_size*parraydef(left.resulttype)^.lowrange);
  504. if right.nodetype=ordconstn then
  505. begin
  506. { offset can only differ from 0 if arraydef }
  507. if (left.resulttype^.deftype=arraydef) then
  508. begin
  509. if not(is_open_array(left.resulttype)) and
  510. not(is_array_of_const(left.resulttype)) and
  511. not(is_dynamic_array(left.resulttype)) then
  512. begin
  513. if (tordconstnode(right).value>parraydef(left.resulttype)^.highrange) or
  514. (tordconstnode(right).value<parraydef(left.resulttype)^.lowrange) then
  515. begin
  516. if (cs_check_range in aktlocalswitches) then
  517. CGMessage(parser_e_range_check_error)
  518. else
  519. CGMessage(parser_w_range_check_error);
  520. end;
  521. dec(left.location.reference.offset,
  522. get_mul_size*parraydef(left.resulttype)^.lowrange);
  523. end
  524. else
  525. begin
  526. { range checking for open and dynamic arrays !!!! }
  527. {$warning FIXME}
  528. {!!!!!!!!!!!!!!!!!}
  529. end;
  530. end
  531. else if (left.resulttype^.deftype=stringdef) then
  532. begin
  533. if (tordconstnode(right).value=0) and not(is_shortstring(left.resulttype)) then
  534. CGMessage(cg_e_can_access_element_zero);
  535. if (cs_check_range in aktlocalswitches) then
  536. case pstringdef(left.resulttype)^.string_typ of
  537. { it's the same for ansi- and wide strings }
  538. st_widestring,
  539. st_ansistring:
  540. begin
  541. pushusedregisters(pushed,$ff);
  542. push_int(tordconstnode(right).value);
  543. hp:=newreference(location.reference);
  544. dec(hp^.offset,7);
  545. emit_ref(A_PUSH,S_L,hp);
  546. saveregvars($ff);
  547. emitcall('FPC_ANSISTR_RANGECHECK');
  548. popusedregisters(pushed);
  549. maybe_loadesi;
  550. end;
  551. st_shortstring:
  552. begin
  553. {!!!!!!!!!!!!!!!!!}
  554. end;
  555. st_longstring:
  556. begin
  557. {!!!!!!!!!!!!!!!!!}
  558. end;
  559. end;
  560. end;
  561. inc(left.location.reference.offset,
  562. get_mul_size*tordconstnode(right).value);
  563. if nf_memseg in flags then
  564. left.location.reference.segment:=R_FS;
  565. {
  566. left.resulttype:=resulttype;
  567. disposetree(right);
  568. _p:=left;
  569. putnode(p);
  570. p:=_p;
  571. }
  572. set_location(location,left.location);
  573. end
  574. else
  575. { not nodetype=ordconstn }
  576. begin
  577. if (cs_regalloc in aktglobalswitches) and
  578. { if we do range checking, we don't }
  579. { need that fancy code (it would be }
  580. { buggy) }
  581. not(cs_check_range in aktlocalswitches) and
  582. (left.resulttype^.deftype=arraydef) then
  583. begin
  584. extraoffset:=0;
  585. if (right.nodetype=addn) then
  586. begin
  587. if taddnode(right).right.nodetype=ordconstn then
  588. begin
  589. extraoffset:=tordconstnode(taddnode(right).right).value;
  590. t:=taddnode(right).left;
  591. { First pass processed this with the assumption }
  592. { that there was an add node which may require an }
  593. { extra register. Fake it or die with IE10 (JM) }
  594. t.registers32 := taddnode(right).registers32;
  595. taddnode(right).left:=nil;
  596. right.free;
  597. right:=t;
  598. end
  599. else if tordconstnode(taddnode(right).left).nodetype=ordconstn then
  600. begin
  601. extraoffset:=tordconstnode(taddnode(right).left).value;
  602. t:=taddnode(right).right;
  603. t.registers32 := right.registers32;
  604. taddnode(right).right:=nil;
  605. right.free;
  606. right:=t;
  607. end;
  608. end
  609. else if (right.nodetype=subn) then
  610. begin
  611. if taddnode(right).right.nodetype=ordconstn then
  612. begin
  613. { this was "extraoffset:=right.right.value;" Looks a bit like
  614. copy-paste bug :) (JM) }
  615. extraoffset:=-tordconstnode(taddnode(right).right).value;
  616. t:=taddnode(right).left;
  617. t.registers32 := right.registers32;
  618. taddnode(right).left:=nil;
  619. right.free;
  620. right:=t;
  621. end
  622. { You also have to negate right.right in this case! I can't add an
  623. unaryminusn without causing a crash, so I've disabled it (JM)
  624. else if right.left.nodetype=ordconstn then
  625. begin
  626. extraoffset:=right.left.value;
  627. t:=right.right;
  628. t^.registers32 := right.registers32;
  629. putnode(right);
  630. putnode(right.left);
  631. right:=t;
  632. end;}
  633. end;
  634. inc(location.reference.offset,
  635. get_mul_size*extraoffset);
  636. end;
  637. { calculate from left to right }
  638. if (location.loc<>LOC_REFERENCE) and
  639. (location.loc<>LOC_MEM) then
  640. CGMessage(cg_e_illegal_expression);
  641. if (right.location.loc=LOC_JUMP) then
  642. begin
  643. otl:=truelabel;
  644. getlabel(truelabel);
  645. ofl:=falselabel;
  646. getlabel(falselabel);
  647. end;
  648. is_pushed:=maybe_push(right.registers32,self,false);
  649. secondpass(right);
  650. if is_pushed then
  651. restore(self,false);
  652. { here we change the location of right
  653. and the update was forgotten so it
  654. led to wrong code in emitrangecheck later PM
  655. so make range check before }
  656. if cs_check_range in aktlocalswitches then
  657. begin
  658. if left.resulttype^.deftype=arraydef then
  659. begin
  660. if is_open_array(left.resulttype) or
  661. is_array_of_const(left.resulttype) then
  662. begin
  663. reset_reference(href);
  664. parraydef(left.resulttype)^.genrangecheck;
  665. href.symbol:=newasmsymbol(parraydef(left.resulttype)^.getrangecheckstring);
  666. href.offset:=4;
  667. srsym:=searchsymonlyin(tloadnode(left).symtable,
  668. 'high'+pvarsym(tloadnode(left).symtableentry)^.name);
  669. hightree:=genloadnode(pvarsym(srsym),tloadnode(left).symtable);
  670. firstpass(hightree);
  671. secondpass(hightree);
  672. emit_mov_loc_ref(hightree.location,href,S_L,true);
  673. hightree.free;
  674. hightree:=nil;
  675. end;
  676. emitrangecheck(right,left.resulttype);
  677. end;
  678. end;
  679. case right.location.loc of
  680. LOC_REGISTER:
  681. begin
  682. ind:=right.location.register;
  683. case right.resulttype^.size of
  684. 1:
  685. begin
  686. hr:=reg8toreg32(ind);
  687. emit_reg_reg(A_MOVZX,S_BL,ind,hr);
  688. ind:=hr;
  689. end;
  690. 2:
  691. begin
  692. hr:=reg16toreg32(ind);
  693. emit_reg_reg(A_MOVZX,S_WL,ind,hr);
  694. ind:=hr;
  695. end;
  696. end;
  697. end;
  698. LOC_CREGISTER:
  699. begin
  700. ind:=getregister32;
  701. case right.resulttype^.size of
  702. 1:
  703. emit_reg_reg(A_MOVZX,S_BL,right.location.register,ind);
  704. 2:
  705. emit_reg_reg(A_MOVZX,S_WL,right.location.register,ind);
  706. 4:
  707. emit_reg_reg(A_MOV,S_L,right.location.register,ind);
  708. end;
  709. end;
  710. LOC_FLAGS:
  711. begin
  712. ind:=getregister32;
  713. emit_flag2reg(right.location.resflags,reg32toreg8(ind));
  714. emit_reg_reg(A_MOVZX,S_BL,reg32toreg8(ind),ind);
  715. end;
  716. LOC_JUMP :
  717. begin
  718. ind:=getregister32;
  719. emitlab(truelabel);
  720. truelabel:=otl;
  721. emit_const_reg(A_MOV,S_L,1,ind);
  722. getlabel(hl);
  723. emitjmp(C_None,hl);
  724. emitlab(falselabel);
  725. falselabel:=ofl;
  726. emit_reg_reg(A_XOR,S_L,ind,ind);
  727. emitlab(hl);
  728. end;
  729. LOC_REFERENCE,LOC_MEM :
  730. begin
  731. del_reference(right.location.reference);
  732. ind:=getregister32;
  733. { Booleans are stored in an 8 bit memory location, so
  734. the use of MOVL is not correct }
  735. case right.resulttype^.size of
  736. 1 : tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,newreference(right.location.reference),ind);
  737. 2 : tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,newreference(right.location.reference),ind);
  738. 4 : tai:=Taicpu.Op_ref_reg(A_MOV,S_L,newreference(right.location.reference),ind);
  739. end;
  740. exprasmList.concat(tai);
  741. end;
  742. else
  743. internalerror(5913428);
  744. end;
  745. { produce possible range check code: }
  746. if cs_check_range in aktlocalswitches then
  747. begin
  748. if left.resulttype^.deftype=arraydef then
  749. begin
  750. { done defore (PM) }
  751. end
  752. else if (left.resulttype^.deftype=stringdef) then
  753. begin
  754. case pstringdef(left.resulttype)^.string_typ of
  755. { it's the same for ansi- and wide strings }
  756. st_widestring,
  757. st_ansistring:
  758. begin
  759. pushusedregisters(pushed,$ff);
  760. emit_reg(A_PUSH,S_L,ind);
  761. hp:=newreference(location.reference);
  762. dec(hp^.offset,7);
  763. emit_ref(A_PUSH,S_L,hp);
  764. saveregvars($ff);
  765. emitcall('FPC_ANSISTR_RANGECHECK');
  766. popusedregisters(pushed);
  767. maybe_loadesi;
  768. end;
  769. st_shortstring:
  770. begin
  771. {!!!!!!!!!!!!!!!!!}
  772. end;
  773. st_longstring:
  774. begin
  775. {!!!!!!!!!!!!!!!!!}
  776. end;
  777. end;
  778. end;
  779. end;
  780. if location.reference.index=R_NO then
  781. begin
  782. location.reference.index:=ind;
  783. calc_emit_mul;
  784. end
  785. else
  786. begin
  787. if location.reference.base=R_NO then
  788. begin
  789. case location.reference.scalefactor of
  790. 2 : emit_const_reg(A_SHL,S_L,1,location.reference.index);
  791. 4 : emit_const_reg(A_SHL,S_L,2,location.reference.index);
  792. 8 : emit_const_reg(A_SHL,S_L,3,location.reference.index);
  793. end;
  794. calc_emit_mul;
  795. location.reference.base:=location.reference.index;
  796. location.reference.index:=ind;
  797. end
  798. else
  799. begin
  800. emit_ref_reg(
  801. A_LEA,S_L,newreference(location.reference),
  802. location.reference.index);
  803. ungetregister32(location.reference.base);
  804. { the symbol offset is loaded, }
  805. { so release the symbol name and set symbol }
  806. { to nil }
  807. location.reference.symbol:=nil;
  808. location.reference.offset:=0;
  809. calc_emit_mul;
  810. location.reference.base:=location.reference.index;
  811. location.reference.index:=ind;
  812. end;
  813. end;
  814. if nf_memseg in flags then
  815. location.reference.segment:=R_FS;
  816. end;
  817. end;
  818. {*****************************************************************************
  819. TI386SELFNODE
  820. *****************************************************************************}
  821. procedure ti386selfnode.pass_2;
  822. begin
  823. reset_reference(location.reference);
  824. getexplicitregister32(R_ESI);
  825. if (resulttype^.deftype=classrefdef) or
  826. is_class(resulttype) then
  827. location.register:=R_ESI
  828. else
  829. location.reference.base:=R_ESI;
  830. end;
  831. {*****************************************************************************
  832. TI386WITHNODE
  833. *****************************************************************************}
  834. procedure ti386withnode.pass_2;
  835. var
  836. usetemp,with_expr_in_temp : boolean;
  837. {$ifdef GDB}
  838. withstartlabel,withendlabel : pasmlabel;
  839. pp : pchar;
  840. mangled_length : longint;
  841. const
  842. withlevel : longint = 0;
  843. {$endif GDB}
  844. begin
  845. if assigned(left) then
  846. begin
  847. secondpass(left);
  848. if left.location.reference.segment<>R_NO then
  849. message(parser_e_no_with_for_variable_in_other_segments);
  850. new(withreference);
  851. usetemp:=false;
  852. if (left.nodetype=loadn) and
  853. (tloadnode(left).symtable=aktprocsym^.definition^.localst) then
  854. begin
  855. { for locals use the local storage }
  856. withreference^:=left.location.reference;
  857. include(flags,nf_islocal);
  858. end
  859. else
  860. { call can have happend with a property }
  861. if is_class_or_interface(left.resulttype) then
  862. begin
  863. {$ifndef noAllocEdi}
  864. getexplicitregister32(R_EDI);
  865. {$endif noAllocEdi}
  866. emit_mov_loc_reg(left.location,R_EDI);
  867. usetemp:=true;
  868. end
  869. else
  870. begin
  871. {$ifndef noAllocEdi}
  872. getexplicitregister32(R_EDI);
  873. {$endif noAllocEdi}
  874. emit_lea_loc_reg(left.location,R_EDI,false);
  875. usetemp:=true;
  876. end;
  877. release_loc(left.location);
  878. { if the with expression is stored in a temp }
  879. { area we must make it persistent and shouldn't }
  880. { release it (FK) }
  881. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  882. istemp(left.location.reference) then
  883. begin
  884. normaltemptopersistant(left.location.reference.offset);
  885. with_expr_in_temp:=true;
  886. end
  887. else
  888. with_expr_in_temp:=false;
  889. { if usetemp is set the value must be in %edi }
  890. if usetemp then
  891. begin
  892. gettempofsizereference(4,withreference^);
  893. normaltemptopersistant(withreference^.offset);
  894. { move to temp reference }
  895. emit_reg_ref(A_MOV,S_L,R_EDI,newreference(withreference^));
  896. {$ifndef noAllocEdi}
  897. ungetregister32(R_EDI);
  898. {$endif noAllocEdi}
  899. {$ifdef GDB}
  900. if (cs_debuginfo in aktmoduleswitches) then
  901. begin
  902. inc(withlevel);
  903. getaddrlabel(withstartlabel);
  904. getaddrlabel(withendlabel);
  905. emitlab(withstartlabel);
  906. withdebugList.concat(Tai_stabs.Create(strpnew(
  907. '"with'+tostr(withlevel)+':'+tostr(symtablestack^.getnewtypecount)+
  908. '=*'+pstoreddef(left.resulttype)^.numberstring+'",'+
  909. tostr(N_LSYM)+',0,0,'+tostr(withreference^.offset))));
  910. mangled_length:=length(aktprocsym^.definition^.mangledname);
  911. getmem(pp,mangled_length+50);
  912. strpcopy(pp,'192,0,0,'+withstartlabel^.name);
  913. if (target_os.use_function_relative_addresses) then
  914. begin
  915. strpcopy(strend(pp),'-');
  916. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  917. end;
  918. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  919. end;
  920. {$endif GDB}
  921. end;
  922. { right can be optimize out !!! }
  923. if assigned(right) then
  924. secondpass(right);
  925. if usetemp then
  926. begin
  927. ungetpersistanttemp(withreference^.offset);
  928. {$ifdef GDB}
  929. if (cs_debuginfo in aktmoduleswitches) then
  930. begin
  931. emitlab(withendlabel);
  932. strpcopy(pp,'224,0,0,'+withendlabel^.name);
  933. if (target_os.use_function_relative_addresses) then
  934. begin
  935. strpcopy(strend(pp),'-');
  936. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  937. end;
  938. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  939. freemem(pp,mangled_length+50);
  940. dec(withlevel);
  941. end;
  942. {$endif GDB}
  943. end;
  944. if with_expr_in_temp then
  945. ungetpersistanttemp(left.location.reference.offset);
  946. dispose(withreference);
  947. withreference:=nil;
  948. end;
  949. end;
  950. begin
  951. cloadvmtnode:=ti386loadvmtnode;
  952. chnewnode:=ti386hnewnode;
  953. cnewnode:=ti386newnode;
  954. chdisposenode:=ti386hdisposenode;
  955. csimplenewdisposenode:=ti386simplenewdisposenode;
  956. caddrnode:=ti386addrnode;
  957. cdoubleaddrnode:=ti386doubleaddrnode;
  958. cderefnode:=ti386derefnode;
  959. csubscriptnode:=ti386subscriptnode;
  960. cvecnode:=ti386vecnode;
  961. cselfnode:=ti386selfnode;
  962. cwithnode:=ti386withnode;
  963. end.
  964. {
  965. $Log$
  966. Revision 1.10 2001-03-11 22:58:52 peter
  967. * getsym redesign, removed the globals srsym,srsymtable
  968. Revision 1.9 2001/02/02 22:38:00 peter
  969. * fixed crash with new(precord), merged
  970. Revision 1.8 2000/12/25 00:07:33 peter
  971. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  972. tlinkedlist objects)
  973. Revision 1.7 2000/12/05 11:44:33 jonas
  974. + new integer regvar handling, should be much more efficient
  975. Revision 1.6 2000/11/29 00:30:48 florian
  976. * unused units removed from uses clause
  977. * some changes for widestrings
  978. Revision 1.5 2000/11/04 14:25:24 florian
  979. + merged Attila's changes for interfaces, not tested yet
  980. Revision 1.4 2000/10/31 22:02:57 peter
  981. * symtable splitted, no real code changes
  982. Revision 1.3 2000/10/31 14:18:53 jonas
  983. * merged double deleting of left location when using a temp in
  984. secondwith (merged from fixes branch). This also fixes web bug1194
  985. Revision 1.2 2000/10/21 18:16:13 florian
  986. * a lot of changes:
  987. - basic dyn. array support
  988. - basic C++ support
  989. - some work for interfaces done
  990. ....
  991. Revision 1.1 2000/10/15 09:33:32 peter
  992. * moved n386*.pas to i386/ cpu_target dir
  993. Revision 1.2 2000/10/14 21:52:54 peter
  994. * fixed memory leaks
  995. Revision 1.1 2000/10/14 10:14:49 peter
  996. * moehrendorf oct 2000 rewrite
  997. }