cg386mem.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  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 cg386mem;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. tree;
  23. procedure secondloadvmt(var p : ptree);
  24. procedure secondhnewn(var p : ptree);
  25. procedure secondnewn(var p : ptree);
  26. procedure secondhdisposen(var p : ptree);
  27. procedure secondsimplenewdispose(var p : ptree);
  28. procedure secondaddr(var p : ptree);
  29. procedure seconddoubleaddr(var p : ptree);
  30. procedure secondderef(var p : ptree);
  31. procedure secondsubscriptn(var p : ptree);
  32. procedure secondvecn(var p : ptree);
  33. procedure secondselfn(var p : ptree);
  34. procedure secondwith(var p : ptree);
  35. implementation
  36. uses
  37. {$ifdef delphi}
  38. sysutils,
  39. {$else}
  40. strings,
  41. {$endif}
  42. {$ifdef GDB}
  43. gdb,
  44. {$endif GDB}
  45. globtype,systems,
  46. cutils,cobjects,verbose,globals,
  47. symconst,symtable,aasm,types,
  48. hcodegen,temp_gen,pass_2,pass_1,
  49. cpubase,cpuasm,
  50. cgai386,tgeni386;
  51. {*****************************************************************************
  52. SecondLoadVMT
  53. *****************************************************************************}
  54. procedure secondloadvmt(var p : ptree);
  55. begin
  56. p^.location.register:=getregister32;
  57. emit_sym_ofs_reg(A_MOV,
  58. S_L,newasmsymbol(pobjectdef(pclassrefdef(p^.resulttype)^.pointertype.def)^.vmt_mangledname),0,
  59. p^.location.register);
  60. end;
  61. {*****************************************************************************
  62. SecondHNewN
  63. *****************************************************************************}
  64. procedure secondhnewn(var p : ptree);
  65. begin
  66. end;
  67. {*****************************************************************************
  68. SecondNewN
  69. *****************************************************************************}
  70. procedure secondnewn(var p : ptree);
  71. var
  72. pushed : tpushed;
  73. r : preference;
  74. begin
  75. if assigned(p^.left) then
  76. begin
  77. secondpass(p^.left);
  78. p^.location.register:=p^.left^.location.register;
  79. end
  80. else
  81. begin
  82. pushusedregisters(pushed,$ff);
  83. gettempofsizereference(target_os.size_of_pointer,p^.location.reference);
  84. { determines the size of the mem block }
  85. push_int(ppointerdef(p^.resulttype)^.pointertype.def^.size);
  86. emit_push_lea_loc(p^.location,false);
  87. emitcall('FPC_GETMEM');
  88. if ppointerdef(p^.resulttype)^.pointertype.def^.needs_inittable then
  89. begin
  90. new(r);
  91. reset_reference(r^);
  92. r^.symbol:=ppointerdef(p^.left^.resulttype)^.pointertype.def^.get_inittable_label;
  93. emitpushreferenceaddr(r^);
  94. dispose(r);
  95. { push pointer we just allocated, we need to initialize the
  96. data located at that pointer not the pointer self (PFV) }
  97. emit_push_loc(p^.location);
  98. emitcall('FPC_INITIALIZE');
  99. end;
  100. popusedregisters(pushed);
  101. { may be load ESI }
  102. maybe_loadesi;
  103. end;
  104. if codegenerror then
  105. exit;
  106. end;
  107. {*****************************************************************************
  108. SecondDisposeN
  109. *****************************************************************************}
  110. procedure secondhdisposen(var p : ptree);
  111. begin
  112. secondpass(p^.left);
  113. if codegenerror then
  114. exit;
  115. reset_reference(p^.location.reference);
  116. case p^.left^.location.loc of
  117. LOC_REGISTER:
  118. p^.location.reference.index:=p^.left^.location.register;
  119. LOC_CREGISTER:
  120. begin
  121. p^.location.reference.index:=getregister32;
  122. emit_reg_reg(A_MOV,S_L,
  123. p^.left^.location.register,
  124. p^.location.reference.index);
  125. end;
  126. LOC_MEM,LOC_REFERENCE :
  127. begin
  128. del_reference(p^.left^.location.reference);
  129. p^.location.reference.index:=getregister32;
  130. emit_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  131. p^.location.reference.index);
  132. end;
  133. end;
  134. end;
  135. {*****************************************************************************
  136. SecondNewDispose
  137. *****************************************************************************}
  138. procedure secondsimplenewdispose(var p : ptree);
  139. var
  140. pushed : tpushed;
  141. r : preference;
  142. begin
  143. secondpass(p^.left);
  144. if codegenerror then
  145. exit;
  146. pushusedregisters(pushed,$ff);
  147. { call the mem handling procedures }
  148. case p^.treetype of
  149. simpledisposen:
  150. begin
  151. if ppointerdef(p^.left^.resulttype)^.pointertype.def^.needs_inittable then
  152. begin
  153. new(r);
  154. reset_reference(r^);
  155. r^.symbol:=ppointerdef(p^.left^.resulttype)^.pointertype.def^.get_inittable_label;
  156. emitpushreferenceaddr(r^);
  157. dispose(r);
  158. { push pointer adress }
  159. emit_push_loc(p^.left^.location);
  160. emitcall('FPC_FINALIZE');
  161. end;
  162. emit_push_lea_loc(p^.left^.location,true);
  163. emitcall('FPC_FREEMEM');
  164. end;
  165. simplenewn:
  166. begin
  167. { determines the size of the mem block }
  168. push_int(ppointerdef(p^.left^.resulttype)^.pointertype.def^.size);
  169. emit_push_lea_loc(p^.left^.location,true);
  170. emitcall('FPC_GETMEM');
  171. if ppointerdef(p^.left^.resulttype)^.pointertype.def^.needs_inittable then
  172. begin
  173. new(r);
  174. reset_reference(r^);
  175. r^.symbol:=ppointerdef(p^.left^.resulttype)^.pointertype.def^.get_inittable_label;
  176. emitpushreferenceaddr(r^);
  177. dispose(r);
  178. emit_push_loc(p^.left^.location);
  179. emitcall('FPC_INITIALIZE');
  180. end;
  181. end;
  182. end;
  183. popusedregisters(pushed);
  184. { may be load ESI }
  185. maybe_loadesi;
  186. end;
  187. {*****************************************************************************
  188. SecondAddr
  189. *****************************************************************************}
  190. procedure secondaddr(var p : ptree);
  191. begin
  192. secondpass(p^.left);
  193. { when loading procvar we do nothing with this node, so load the
  194. location of left }
  195. if p^.procvarload then
  196. begin
  197. set_location(p^.location,p^.left^.location);
  198. exit;
  199. end;
  200. p^.location.loc:=LOC_REGISTER;
  201. del_reference(p^.left^.location.reference);
  202. p^.location.register:=getregister32;
  203. {@ on a procvar means returning an address to the procedure that
  204. is stored in it.}
  205. { yes but p^.left^.symtableentry can be nil
  206. for example on @self !! }
  207. { symtableentry can be also invalid, if left is no tree node }
  208. if (m_tp_procvar in aktmodeswitches) and
  209. (p^.left^.treetype=loadn) and
  210. assigned(p^.left^.symtableentry) and
  211. (p^.left^.symtableentry^.typ=varsym) and
  212. (pvarsym(p^.left^.symtableentry)^.vartype.def^.deftype=procvardef) then
  213. emit_ref_reg(A_MOV,S_L,
  214. newreference(p^.left^.location.reference),
  215. p^.location.register)
  216. else
  217. emit_ref_reg(A_LEA,S_L,
  218. newreference(p^.left^.location.reference),
  219. p^.location.register);
  220. { for use of other segments }
  221. if p^.left^.location.reference.segment<>R_NO then
  222. p^.location.segment:=p^.left^.location.reference.segment;
  223. end;
  224. {*****************************************************************************
  225. SecondDoubleAddr
  226. *****************************************************************************}
  227. procedure seconddoubleaddr(var p : ptree);
  228. begin
  229. secondpass(p^.left);
  230. p^.location.loc:=LOC_REGISTER;
  231. del_reference(p^.left^.location.reference);
  232. p^.location.register:=getregister32;
  233. emit_ref_reg(A_LEA,S_L,
  234. newreference(p^.left^.location.reference),
  235. p^.location.register);
  236. end;
  237. {*****************************************************************************
  238. SecondDeRef
  239. *****************************************************************************}
  240. procedure secondderef(var p : ptree);
  241. var
  242. hr : tregister;
  243. begin
  244. secondpass(p^.left);
  245. reset_reference(p^.location.reference);
  246. case p^.left^.location.loc of
  247. LOC_REGISTER:
  248. p^.location.reference.base:=p^.left^.location.register;
  249. LOC_CREGISTER:
  250. begin
  251. { ... and reserve one for the pointer }
  252. hr:=getregister32;
  253. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,hr);
  254. p^.location.reference.base:=hr;
  255. end;
  256. else
  257. begin
  258. { free register }
  259. del_reference(p^.left^.location.reference);
  260. { ...and reserve one for the pointer }
  261. hr:=getregister32;
  262. emit_ref_reg(
  263. A_MOV,S_L,newreference(p^.left^.location.reference),
  264. hr);
  265. p^.location.reference.base:=hr;
  266. end;
  267. end;
  268. if ppointerdef(p^.left^.resulttype)^.is_far then
  269. p^.location.reference.segment:=R_FS;
  270. if not ppointerdef(p^.left^.resulttype)^.is_far and
  271. (cs_gdb_heaptrc in aktglobalswitches) and
  272. (cs_checkpointer in aktglobalswitches) then
  273. begin
  274. emit_reg(
  275. A_PUSH,S_L,p^.location.reference.base);
  276. emitcall('FPC_CHECKPOINTER');
  277. end;
  278. end;
  279. {*****************************************************************************
  280. SecondSubScriptN
  281. *****************************************************************************}
  282. procedure secondsubscriptn(var p : ptree);
  283. var
  284. hr : tregister;
  285. begin
  286. secondpass(p^.left);
  287. if codegenerror then
  288. exit;
  289. { classes must be dereferenced implicit }
  290. if (p^.left^.resulttype^.deftype=objectdef) and
  291. pobjectdef(p^.left^.resulttype)^.is_class then
  292. begin
  293. reset_reference(p^.location.reference);
  294. case p^.left^.location.loc of
  295. LOC_REGISTER:
  296. p^.location.reference.base:=p^.left^.location.register;
  297. LOC_CREGISTER:
  298. begin
  299. { ... and reserve one for the pointer }
  300. hr:=getregister32;
  301. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,hr);
  302. p^.location.reference.base:=hr;
  303. end;
  304. else
  305. begin
  306. { free register }
  307. del_reference(p^.left^.location.reference);
  308. { ... and reserve one for the pointer }
  309. hr:=getregister32;
  310. emit_ref_reg(
  311. A_MOV,S_L,newreference(p^.left^.location.reference),
  312. hr);
  313. p^.location.reference.base:=hr;
  314. end;
  315. end;
  316. end
  317. else
  318. set_location(p^.location,p^.left^.location);
  319. inc(p^.location.reference.offset,p^.vs^.address);
  320. end;
  321. {*****************************************************************************
  322. SecondVecN
  323. *****************************************************************************}
  324. procedure secondvecn(var p : ptree);
  325. var
  326. is_pushed : boolean;
  327. ind,hr : tregister;
  328. _p : ptree;
  329. function get_mul_size:longint;
  330. begin
  331. if p^.memindex then
  332. get_mul_size:=1
  333. else
  334. begin
  335. if (p^.left^.resulttype^.deftype=arraydef) then
  336. get_mul_size:=parraydef(p^.left^.resulttype)^.elesize
  337. else
  338. get_mul_size:=p^.resulttype^.size;
  339. end
  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. emit_const_reg(A_SHL,S_L,l2,ind)
  352. else
  353. emit_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. t : ptree;
  364. hp : preference;
  365. href : treference;
  366. tai : Paicpu;
  367. pushed : tpushed;
  368. hightree : ptree;
  369. hl,otl,ofl : pasmlabel;
  370. begin
  371. secondpass(p^.left);
  372. { we load the array reference to p^.location }
  373. { an ansistring needs to be dereferenced }
  374. if is_ansistring(p^.left^.resulttype) or
  375. is_widestring(p^.left^.resulttype) then
  376. begin
  377. reset_reference(p^.location.reference);
  378. if p^.callunique then
  379. begin
  380. if p^.left^.location.loc<>LOC_REFERENCE then
  381. begin
  382. CGMessage(cg_e_illegal_expression);
  383. exit;
  384. end;
  385. pushusedregisters(pushed,$ff);
  386. emitpushreferenceaddr(p^.left^.location.reference);
  387. if is_ansistring(p^.left^.resulttype) then
  388. emitcall('FPC_ANSISTR_UNIQUE')
  389. else
  390. emitcall('FPC_WIDESTR_UNIQUE');
  391. maybe_loadesi;
  392. popusedregisters(pushed);
  393. end;
  394. if p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  395. begin
  396. p^.location.reference.base:=p^.left^.location.register;
  397. end
  398. else
  399. begin
  400. del_reference(p^.left^.location.reference);
  401. p^.location.reference.base:=getregister32;
  402. emit_ref_reg(A_MOV,S_L,
  403. newreference(p^.left^.location.reference),
  404. p^.location.reference.base);
  405. end;
  406. { check for a zero length string,
  407. we can use the ansistring routine here }
  408. if (cs_check_range in aktlocalswitches) then
  409. begin
  410. pushusedregisters(pushed,$ff);
  411. emit_reg(A_PUSH,S_L,p^.location.reference.base);
  412. emitcall('FPC_ANSISTR_CHECKZERO');
  413. maybe_loadesi;
  414. popusedregisters(pushed);
  415. end;
  416. if is_ansistring(p^.left^.resulttype) then
  417. { in ansistrings S[1] is pchar(S)[0] !! }
  418. dec(p^.location.reference.offset)
  419. else
  420. begin
  421. { in widestrings S[1] is pwchar(S)[0] !! }
  422. dec(p^.location.reference.offset,2);
  423. emit_const_reg(A_SHL,S_L,
  424. 1,p^.location.reference.base);
  425. end;
  426. { we've also to keep left up-to-date, because it is used }
  427. { if a constant array index occurs, subject to change (FK) }
  428. set_location(p^.left^.location,p^.location);
  429. end
  430. else
  431. set_location(p^.location,p^.left^.location);
  432. { offset can only differ from 0 if arraydef }
  433. if p^.left^.resulttype^.deftype=arraydef then
  434. dec(p^.location.reference.offset,
  435. get_mul_size*parraydef(p^.left^.resulttype)^.lowrange);
  436. if p^.right^.treetype=ordconstn then
  437. begin
  438. { offset can only differ from 0 if arraydef }
  439. if (p^.left^.resulttype^.deftype=arraydef) then
  440. begin
  441. if not(is_open_array(p^.left^.resulttype)) and
  442. not(is_array_of_const(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(pushed,$ff);
  472. push_int(p^.right^.value);
  473. hp:=newreference(p^.location.reference);
  474. dec(hp^.offset,7);
  475. emit_ref(A_PUSH,S_L,hp);
  476. emitcall('FPC_ANSISTR_RANGECHECK');
  477. popusedregisters(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. { if we do range checking, we don't }
  506. { need that fancy code (it would be }
  507. { buggy) }
  508. not(cs_check_range in aktlocalswitches) and
  509. (p^.left^.resulttype^.deftype=arraydef) then
  510. begin
  511. extraoffset:=0;
  512. if (p^.right^.treetype=addn) then
  513. begin
  514. if p^.right^.right^.treetype=ordconstn then
  515. begin
  516. extraoffset:=p^.right^.right^.value;
  517. t:=p^.right^.left;
  518. { First pass processed this with the assumption }
  519. { that there was an add node which may require an }
  520. { extra register. Fake it or die with IE10 (JM) }
  521. t^.registers32 := p^.right^.registers32;
  522. putnode(p^.right^.right);
  523. putnode(p^.right);
  524. p^.right:=t;
  525. end
  526. else if p^.right^.left^.treetype=ordconstn then
  527. begin
  528. extraoffset:=p^.right^.left^.value;
  529. t:=p^.right^.right;
  530. t^.registers32 := p^.right^.registers32;
  531. putnode(p^.right^.left);
  532. putnode(p^.right);
  533. p^.right:=t;
  534. end;
  535. end
  536. else if (p^.right^.treetype=subn) then
  537. begin
  538. if p^.right^.right^.treetype=ordconstn then
  539. begin
  540. { this was "extraoffset:=p^.right^.right^.value;" Looks a bit like
  541. copy-paste bug :) (JM) }
  542. extraoffset:=-p^.right^.right^.value;
  543. t:=p^.right^.left;
  544. t^.registers32 := p^.right^.registers32;
  545. putnode(p^.right^.right);
  546. putnode(p^.right);
  547. p^.right:=t;
  548. end
  549. { You also have to negate p^.right^.right in this case! I can't add an
  550. unaryminusn without causing a crash, so I've disabled it (JM)
  551. else if p^.right^.left^.treetype=ordconstn then
  552. begin
  553. extraoffset:=p^.right^.left^.value;
  554. t:=p^.right^.right;
  555. t^.registers32 := p^.right^.registers32;
  556. putnode(p^.right);
  557. putnode(p^.right^.left);
  558. p^.right:=t;
  559. end;}
  560. end;
  561. inc(p^.location.reference.offset,
  562. get_mul_size*extraoffset);
  563. end;
  564. { calculate from left to right }
  565. if (p^.location.loc<>LOC_REFERENCE) and
  566. (p^.location.loc<>LOC_MEM) then
  567. CGMessage(cg_e_illegal_expression);
  568. if (p^.right^.location.loc=LOC_JUMP) then
  569. begin
  570. otl:=truelabel;
  571. getlabel(truelabel);
  572. ofl:=falselabel;
  573. getlabel(falselabel);
  574. end;
  575. is_pushed:=maybe_push(p^.right^.registers32,p,false);
  576. secondpass(p^.right);
  577. if is_pushed then
  578. restore(p,false);
  579. { here we change the location of p^.right
  580. and the update was forgotten so it
  581. led to wrong code in emitrangecheck later PM
  582. so make range check before }
  583. if cs_check_range in aktlocalswitches then
  584. begin
  585. if p^.left^.resulttype^.deftype=arraydef then
  586. begin
  587. if is_open_array(p^.left^.resulttype) or
  588. is_array_of_const(p^.left^.resulttype) then
  589. begin
  590. reset_reference(href);
  591. parraydef(p^.left^.resulttype)^.genrangecheck;
  592. href.symbol:=newasmsymbol(parraydef(p^.left^.resulttype)^.getrangecheckstring);
  593. href.offset:=4;
  594. getsymonlyin(p^.left^.symtable,'high'+pvarsym(p^.left^.symtableentry)^.name);
  595. hightree:=genloadnode(pvarsym(srsym),p^.left^.symtable);
  596. firstpass(hightree);
  597. secondpass(hightree);
  598. emit_mov_loc_ref(hightree^.location,href,S_L,true);
  599. disposetree(hightree);
  600. end;
  601. emitrangecheck(p^.right,p^.left^.resulttype);
  602. end;
  603. end;
  604. case p^.right^.location.loc of
  605. LOC_REGISTER:
  606. begin
  607. ind:=p^.right^.location.register;
  608. case p^.right^.resulttype^.size of
  609. 1:
  610. begin
  611. hr:=reg8toreg32(ind);
  612. emit_reg_reg(A_MOVZX,S_BL,ind,hr);
  613. ind:=hr;
  614. end;
  615. 2:
  616. begin
  617. hr:=reg16toreg32(ind);
  618. emit_reg_reg(A_MOVZX,S_WL,ind,hr);
  619. ind:=hr;
  620. end;
  621. end;
  622. end;
  623. LOC_CREGISTER:
  624. begin
  625. ind:=getregister32;
  626. case p^.right^.resulttype^.size of
  627. 1:
  628. emit_reg_reg(A_MOVZX,S_BL,p^.right^.location.register,ind);
  629. 2:
  630. emit_reg_reg(A_MOVZX,S_WL,p^.right^.location.register,ind);
  631. 4:
  632. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,ind);
  633. end;
  634. end;
  635. LOC_FLAGS:
  636. begin
  637. ind:=getregister32;
  638. emit_flag2reg(p^.right^.location.resflags,reg32toreg8(ind));
  639. emit_reg_reg(A_MOVZX,S_BL,reg32toreg8(ind),ind);
  640. end;
  641. LOC_JUMP :
  642. begin
  643. ind:=getregister32;
  644. emitlab(truelabel);
  645. truelabel:=otl;
  646. emit_const_reg(A_MOV,S_L,1,ind);
  647. getlabel(hl);
  648. emitjmp(C_None,hl);
  649. emitlab(falselabel);
  650. falselabel:=ofl;
  651. emit_reg_reg(A_XOR,S_L,ind,ind);
  652. emitlab(hl);
  653. end;
  654. LOC_REFERENCE,LOC_MEM :
  655. begin
  656. del_reference(p^.right^.location.reference);
  657. ind:=getregister32;
  658. { Booleans are stored in an 8 bit memory location, so
  659. the use of MOVL is not correct }
  660. case p^.right^.resulttype^.size of
  661. 1 : tai:=new(paicpu,op_ref_reg(A_MOVZX,S_BL,newreference(p^.right^.location.reference),ind));
  662. 2 : tai:=new(Paicpu,op_ref_reg(A_MOVZX,S_WL,newreference(p^.right^.location.reference),ind));
  663. 4 : tai:=new(Paicpu,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),ind));
  664. end;
  665. exprasmlist^.concat(tai);
  666. end;
  667. else
  668. internalerror(5913428);
  669. end;
  670. { produce possible range check code: }
  671. if cs_check_range in aktlocalswitches then
  672. begin
  673. if p^.left^.resulttype^.deftype=arraydef then
  674. begin
  675. { done defore (PM) }
  676. end
  677. else if (p^.left^.resulttype^.deftype=stringdef) then
  678. begin
  679. case pstringdef(p^.left^.resulttype)^.string_typ of
  680. { it's the same for ansi- and wide strings }
  681. st_widestring,
  682. st_ansistring:
  683. begin
  684. pushusedregisters(pushed,$ff);
  685. emit_reg(A_PUSH,S_L,ind);
  686. hp:=newreference(p^.location.reference);
  687. dec(hp^.offset,7);
  688. emit_ref(A_PUSH,S_L,hp);
  689. emitcall('FPC_ANSISTR_RANGECHECK');
  690. popusedregisters(pushed);
  691. maybe_loadesi;
  692. end;
  693. st_shortstring:
  694. begin
  695. {!!!!!!!!!!!!!!!!!}
  696. end;
  697. st_longstring:
  698. begin
  699. {!!!!!!!!!!!!!!!!!}
  700. end;
  701. end;
  702. end;
  703. end;
  704. if p^.location.reference.index=R_NO then
  705. begin
  706. p^.location.reference.index:=ind;
  707. calc_emit_mul;
  708. end
  709. else
  710. begin
  711. if p^.location.reference.base=R_NO then
  712. begin
  713. case p^.location.reference.scalefactor of
  714. 2 : emit_const_reg(A_SHL,S_L,1,p^.location.reference.index);
  715. 4 : emit_const_reg(A_SHL,S_L,2,p^.location.reference.index);
  716. 8 : emit_const_reg(A_SHL,S_L,3,p^.location.reference.index);
  717. end;
  718. calc_emit_mul;
  719. p^.location.reference.base:=p^.location.reference.index;
  720. p^.location.reference.index:=ind;
  721. end
  722. else
  723. begin
  724. emit_ref_reg(
  725. A_LEA,S_L,newreference(p^.location.reference),
  726. p^.location.reference.index);
  727. ungetregister32(p^.location.reference.base);
  728. { the symbol offset is loaded, }
  729. { so release the symbol name and set symbol }
  730. { to nil }
  731. p^.location.reference.symbol:=nil;
  732. p^.location.reference.offset:=0;
  733. calc_emit_mul;
  734. p^.location.reference.base:=p^.location.reference.index;
  735. p^.location.reference.index:=ind;
  736. end;
  737. end;
  738. if p^.memseg then
  739. p^.location.reference.segment:=R_FS;
  740. end;
  741. end;
  742. {*****************************************************************************
  743. SecondSelfN
  744. *****************************************************************************}
  745. procedure secondselfn(var p : ptree);
  746. begin
  747. reset_reference(p^.location.reference);
  748. getexplicitregister32(R_ESI);
  749. if (p^.resulttype^.deftype=classrefdef) or
  750. ((p^.resulttype^.deftype=objectdef)
  751. and pobjectdef(p^.resulttype)^.is_class
  752. ) then
  753. p^.location.register:=R_ESI
  754. else
  755. p^.location.reference.base:=R_ESI;
  756. end;
  757. {*****************************************************************************
  758. SecondWithN
  759. *****************************************************************************}
  760. procedure secondwith(var p : ptree);
  761. var
  762. usetemp,with_expr_in_temp : boolean;
  763. {$ifdef GDB}
  764. withstartlabel,withendlabel : pasmlabel;
  765. pp : pchar;
  766. mangled_length : longint;
  767. const
  768. withlevel : longint = 0;
  769. {$endif GDB}
  770. begin
  771. if assigned(p^.left) then
  772. begin
  773. secondpass(p^.left);
  774. if p^.left^.location.reference.segment<>R_NO then
  775. message(parser_e_no_with_for_variable_in_other_segments);
  776. new(p^.withreference);
  777. usetemp:=false;
  778. if (p^.left^.treetype=loadn) and
  779. (p^.left^.symtable=aktprocsym^.definition^.localst) then
  780. begin
  781. { for locals use the local storage }
  782. p^.withreference^:=p^.left^.location.reference;
  783. p^.islocal:=true;
  784. end
  785. else
  786. { call can have happend with a property }
  787. if (p^.left^.resulttype^.deftype=objectdef) and
  788. pobjectdef(p^.left^.resulttype)^.is_class then
  789. begin
  790. {$ifndef noAllocEdi}
  791. getexplicitregister32(R_EDI);
  792. {$endif noAllocEdi}
  793. emit_mov_loc_reg(p^.left^.location,R_EDI);
  794. usetemp:=true;
  795. end
  796. else
  797. begin
  798. {$ifndef noAllocEdi}
  799. getexplicitregister32(R_EDI);
  800. {$endif noAllocEdi}
  801. emit_lea_loc_reg(p^.left^.location,R_EDI,false);
  802. usetemp:=true;
  803. end;
  804. release_loc(p^.left^.location);
  805. { if the with expression is stored in a temp }
  806. { area we must make it persistent and shouldn't }
  807. { release it (FK) }
  808. if (p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  809. istemp(p^.left^.location.reference) then
  810. begin
  811. normaltemptopersistant(p^.left^.location.reference.offset);
  812. with_expr_in_temp:=true;
  813. end
  814. else
  815. with_expr_in_temp:=false;
  816. { if usetemp is set the value must be in %edi }
  817. if usetemp then
  818. begin
  819. gettempofsizereference(4,p^.withreference^);
  820. normaltemptopersistant(p^.withreference^.offset);
  821. { move to temp reference }
  822. emit_reg_ref(A_MOV,S_L,R_EDI,newreference(p^.withreference^));
  823. {$ifndef noAllocEdi}
  824. ungetregister32(R_EDI);
  825. {$endif noAllocEdi}
  826. {$ifdef GDB}
  827. if (cs_debuginfo in aktmoduleswitches) then
  828. begin
  829. inc(withlevel);
  830. getaddrlabel(withstartlabel);
  831. getaddrlabel(withendlabel);
  832. emitlab(withstartlabel);
  833. withdebuglist^.concat(new(pai_stabs,init(strpnew(
  834. '"with'+tostr(withlevel)+':'+tostr(symtablestack^.getnewtypecount)+
  835. '=*'+p^.left^.resulttype^.numberstring+'",'+
  836. tostr(N_LSYM)+',0,0,'+tostr(p^.withreference^.offset)))));
  837. mangled_length:=length(aktprocsym^.definition^.mangledname);
  838. getmem(pp,mangled_length+50);
  839. strpcopy(pp,'192,0,0,'+withstartlabel^.name);
  840. if (target_os.use_function_relative_addresses) then
  841. begin
  842. strpcopy(strend(pp),'-');
  843. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  844. end;
  845. withdebuglist^.concat(new(pai_stabn,init(strnew(pp))));
  846. end;
  847. {$endif GDB}
  848. del_reference(p^.left^.location.reference);
  849. end;
  850. { p^.right can be optimize out !!! }
  851. if assigned(p^.right) then
  852. secondpass(p^.right);
  853. if usetemp then
  854. begin
  855. ungetpersistanttemp(p^.withreference^.offset);
  856. {$ifdef GDB}
  857. if (cs_debuginfo in aktmoduleswitches) then
  858. begin
  859. emitlab(withendlabel);
  860. strpcopy(pp,'224,0,0,'+withendlabel^.name);
  861. if (target_os.use_function_relative_addresses) then
  862. begin
  863. strpcopy(strend(pp),'-');
  864. strpcopy(strend(pp),aktprocsym^.definition^.mangledname);
  865. end;
  866. withdebuglist^.concat(new(pai_stabn,init(strnew(pp))));
  867. freemem(pp,mangled_length+50);
  868. dec(withlevel);
  869. end;
  870. {$endif GDB}
  871. end;
  872. if with_expr_in_temp then
  873. ungetpersistanttemp(p^.left^.location.reference.offset);
  874. dispose(p^.withreference);
  875. p^.withreference:=nil;
  876. end;
  877. end;
  878. end.
  879. {
  880. $Log$
  881. Revision 1.7 2000-09-24 21:19:49 peter
  882. * delphi compile fixes
  883. Revision 1.6 2000/08/27 16:11:49 peter
  884. * moved some util functions from globals,cobjects to cutils
  885. * splitted files into finput,fmodule
  886. Revision 1.5 2000/07/28 07:38:13 jonas
  887. * refined previous fix (sometimes the number of necessary registers was
  888. overestimated) (merged from fixes branch)
  889. Revision 1.4 2000/07/27 12:41:54 jonas
  890. * fixed internalerror(10) when using -Or and complex arrays (merged
  891. from fixes branch)
  892. Revision 1.3 2000/07/21 15:14:02 jonas
  893. + added is_addr field for labels, if they are only used for getting the address
  894. (e.g. for io checks) and corresponding getaddrlabel() procedure
  895. Revision 1.2 2000/07/13 11:32:35 michael
  896. + removed logs
  897. }