n386mem.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 fpcdefs.inc}
  20. interface
  21. uses
  22. node,nmem,ncgmem;
  23. type
  24. ti386addrnode = class(tcgaddrnode)
  25. procedure pass_2;override;
  26. end;
  27. ti386derefnode = class(tcgderefnode)
  28. procedure pass_2;override;
  29. end;
  30. ti386vecnode = class(tvecnode)
  31. procedure pass_2;override;
  32. end;
  33. implementation
  34. uses
  35. {$ifdef delphi}
  36. sysutils,
  37. {$endif}
  38. globtype,systems,
  39. cutils,verbose,globals,
  40. symconst,symtype,symdef,symsym,symtable,aasm,types,
  41. cginfo,cgbase,pass_2,
  42. pass_1,nld,ncon,nadd,
  43. cpubase,
  44. cgobj,cga,tgobj,rgobj,ncgutil;
  45. {*****************************************************************************
  46. TI386ADDRNODE
  47. *****************************************************************************}
  48. procedure ti386addrnode.pass_2;
  49. begin
  50. inherited pass_2;
  51. { for use of other segments }
  52. if left.location.reference.segment<>R_NO then
  53. location.segment:=left.location.reference.segment;
  54. end;
  55. {*****************************************************************************
  56. TI386DEREFNODE
  57. *****************************************************************************}
  58. procedure ti386derefnode.pass_2;
  59. var
  60. oldglobalswitches : tglobalswitches;
  61. begin
  62. oldglobalswitches:=aktglobalswitches;
  63. exclude(aktglobalswitches,cs_checkpointer);
  64. inherited pass_2;
  65. aktglobalswitches:=oldglobalswitches;
  66. if tpointerdef(left.resulttype.def).is_far then
  67. location.reference.segment:=R_FS;
  68. if not tpointerdef(left.resulttype.def).is_far and
  69. (cs_gdb_heaptrc in aktglobalswitches) and
  70. (cs_checkpointer in aktglobalswitches) then
  71. begin
  72. cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,1);
  73. cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
  74. end;
  75. end;
  76. {*****************************************************************************
  77. TI386VECNODE
  78. *****************************************************************************}
  79. procedure ti386vecnode.pass_2;
  80. function get_mul_size:longint;
  81. begin
  82. if nf_memindex in flags then
  83. get_mul_size:=1
  84. else
  85. begin
  86. if (left.resulttype.def.deftype=arraydef) then
  87. get_mul_size:=tarraydef(left.resulttype.def).elesize
  88. else
  89. get_mul_size:=resulttype.def.size;
  90. end
  91. end;
  92. procedure calc_emit_mul;
  93. var
  94. l1,l2 : longint;
  95. begin
  96. l1:=get_mul_size;
  97. case l1 of
  98. 1,2,4,8 : location.reference.scalefactor:=l1;
  99. else
  100. begin
  101. if ispowerof2(l1,l2) then
  102. emit_const_reg(A_SHL,S_L,l2,right.location.register)
  103. else
  104. emit_const_reg(A_IMUL,S_L,l1,right.location.register);
  105. end;
  106. end;
  107. end;
  108. var
  109. extraoffset : longint;
  110. { rl stores the resulttype.def of the left node, this is necessary }
  111. { to detect if it is an ansistring }
  112. { because in constant nodes which constant index }
  113. { the left tree is removed }
  114. t : tnode;
  115. href : treference;
  116. srsym : tsym;
  117. pushed : tpushedsaved;
  118. hightree : tnode;
  119. isjump : boolean;
  120. otl,ofl : tasmlabel;
  121. newsize : tcgsize;
  122. pushedregs : tmaybesave;
  123. begin
  124. newsize:=def_cgsize(resulttype.def);
  125. location_reset(location,LOC_REFERENCE,newsize);
  126. secondpass(left);
  127. { we load the array reference to location }
  128. { an ansistring needs to be dereferenced }
  129. if is_ansistring(left.resulttype.def) or
  130. is_widestring(left.resulttype.def) then
  131. begin
  132. if nf_callunique in flags then
  133. begin
  134. if left.location.loc<>LOC_REFERENCE then
  135. begin
  136. CGMessage(cg_e_illegal_expression);
  137. exit;
  138. end;
  139. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  140. cg.a_paramaddr_ref(exprasmlist,left.location.reference,1);
  141. rg.saveregvars(exprasmlist,all_registers);
  142. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_UNIQUE');
  143. cg.g_maybe_loadself(exprasmlist);
  144. rg.restoreusedregisters(exprasmlist,pushed);
  145. end;
  146. case left.location.loc of
  147. LOC_REGISTER,
  148. LOC_CREGISTER :
  149. location.reference.base:=left.location.register;
  150. LOC_CREFERENCE,
  151. LOC_REFERENCE :
  152. begin
  153. location_release(exprasmlist,left.location);
  154. location.reference.base:=rg.getregisterint(exprasmlist);
  155. cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.reference.base);
  156. end;
  157. else
  158. internalerror(2002032218);
  159. end;
  160. { check for a zero length string,
  161. we can use the ansistring routine here }
  162. if (cs_check_range in aktlocalswitches) then
  163. begin
  164. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  165. cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,1);
  166. rg.saveregvars(exprasmlist,all_registers);
  167. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO');
  168. cg.g_maybe_loadself(exprasmlist);
  169. rg.restoreusedregisters(exprasmlist,pushed);
  170. end;
  171. { in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
  172. if is_ansistring(left.resulttype.def) then
  173. dec(location.reference.offset)
  174. else
  175. dec(location.reference.offset,2);
  176. { we've also to keep left up-to-date, because it is used }
  177. { if a constant array index occurs, subject to change (FK) }
  178. location_copy(left.location,location);
  179. end
  180. else if is_dynamic_array(left.resulttype.def) then
  181. { ... also a dynamic string }
  182. begin
  183. case left.location.loc of
  184. LOC_REGISTER,
  185. LOC_CREGISTER :
  186. location.reference.base:=left.location.register;
  187. LOC_REFERENCE,
  188. LOC_CREFERENCE :
  189. begin
  190. location_release(exprasmlist,left.location);
  191. location.reference.base:=rg.getregisterint(exprasmlist);
  192. emit_ref_reg(A_MOV,S_L,
  193. left.location.reference,location.reference.base);
  194. end;
  195. else
  196. internalerror(2002032219);
  197. end;
  198. {$warning FIXME}
  199. { check for a zero length string,
  200. we can use the ansistring routine here }
  201. if (cs_check_range in aktlocalswitches) then
  202. begin
  203. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  204. emit_reg(A_PUSH,S_L,location.reference.base);
  205. rg.saveregvars(exprasmlist,all_registers);
  206. cg.a_call_name(exprasmlist,'FPC_ANSISTR_CHECKZERO');
  207. cg.g_maybe_loadself(exprasmlist);
  208. rg.restoreusedregisters(exprasmlist,pushed);
  209. end;
  210. { we've also to keep left up-to-date, because it is used }
  211. { if a constant array index occurs, subject to change (FK) }
  212. location_copy(left.location,location);
  213. end
  214. else
  215. location_copy(location,left.location);
  216. { offset can only differ from 0 if arraydef }
  217. if (left.resulttype.def.deftype=arraydef) and
  218. not(is_dynamic_array(left.resulttype.def)) then
  219. dec(location.reference.offset,
  220. get_mul_size*tarraydef(left.resulttype.def).lowrange);
  221. if right.nodetype=ordconstn then
  222. begin
  223. { offset can only differ from 0 if arraydef }
  224. if (left.resulttype.def.deftype=arraydef) then
  225. begin
  226. if not(is_open_array(left.resulttype.def)) and
  227. not(is_array_of_const(left.resulttype.def)) and
  228. not(is_dynamic_array(left.resulttype.def)) then
  229. begin
  230. if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or
  231. (tordconstnode(right).value<tarraydef(left.resulttype.def).lowrange) then
  232. begin
  233. if (cs_check_range in aktlocalswitches) then
  234. CGMessage(parser_e_range_check_error)
  235. else
  236. CGMessage(parser_w_range_check_error);
  237. end;
  238. dec(left.location.reference.offset,
  239. get_mul_size*tarraydef(left.resulttype.def).lowrange);
  240. end
  241. else
  242. begin
  243. { range checking for open and dynamic arrays !!!! }
  244. {$warning FIXME}
  245. {!!!!!!!!!!!!!!!!!}
  246. end;
  247. end
  248. else if (left.resulttype.def.deftype=stringdef) then
  249. begin
  250. if (tordconstnode(right).value=0) and
  251. not(is_shortstring(left.resulttype.def)) then
  252. CGMessage(cg_e_can_access_element_zero);
  253. if (cs_check_range in aktlocalswitches) then
  254. begin
  255. case tstringdef(left.resulttype.def).string_typ of
  256. { it's the same for ansi- and wide strings }
  257. st_widestring,
  258. st_ansistring:
  259. begin
  260. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  261. cg.a_param_const(exprasmlist,OS_INT,tordconstnode(right).value,2);
  262. href:=location.reference;
  263. dec(href.offset,7);
  264. cg.a_param_ref(exprasmlist,OS_INT,href,1);
  265. rg.saveregvars(exprasmlist,all_registers);
  266. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  267. rg.restoreusedregisters(exprasmlist,pushed);
  268. cg.g_maybe_loadself(exprasmlist);
  269. end;
  270. st_shortstring:
  271. begin
  272. {!!!!!!!!!!!!!!!!!}
  273. end;
  274. st_longstring:
  275. begin
  276. {!!!!!!!!!!!!!!!!!}
  277. end;
  278. end;
  279. end;
  280. end;
  281. inc(left.location.reference.offset,
  282. get_mul_size*tordconstnode(right).value);
  283. if nf_memseg in flags then
  284. left.location.reference.segment:=R_FS;
  285. location_copy(location,left.location);
  286. end
  287. else
  288. { not nodetype=ordconstn }
  289. begin
  290. if (cs_regalloc in aktglobalswitches) and
  291. { if we do range checking, we don't }
  292. { need that fancy code (it would be }
  293. { buggy) }
  294. not(cs_check_range in aktlocalswitches) and
  295. (left.resulttype.def.deftype=arraydef) then
  296. begin
  297. extraoffset:=0;
  298. if (right.nodetype=addn) then
  299. begin
  300. if taddnode(right).right.nodetype=ordconstn then
  301. begin
  302. extraoffset:=tordconstnode(taddnode(right).right).value;
  303. t:=taddnode(right).left;
  304. { First pass processed this with the assumption }
  305. { that there was an add node which may require an }
  306. { extra register. Fake it or die with IE10 (JM) }
  307. t.registers32 := taddnode(right).registers32;
  308. taddnode(right).left:=nil;
  309. right.free;
  310. right:=t;
  311. end
  312. else if taddnode(right).left.nodetype=ordconstn then
  313. begin
  314. extraoffset:=tordconstnode(taddnode(right).left).value;
  315. t:=taddnode(right).right;
  316. t.registers32 := right.registers32;
  317. taddnode(right).right:=nil;
  318. right.free;
  319. right:=t;
  320. end;
  321. end
  322. else if (right.nodetype=subn) then
  323. begin
  324. if taddnode(right).right.nodetype=ordconstn then
  325. begin
  326. { this was "extraoffset:=right.right.value;" Looks a bit like
  327. copy-paste bug :) (JM) }
  328. extraoffset:=-tordconstnode(taddnode(right).right).value;
  329. t:=taddnode(right).left;
  330. t.registers32 := right.registers32;
  331. taddnode(right).left:=nil;
  332. right.free;
  333. right:=t;
  334. end
  335. { You also have to negate right.right in this case! I can't add an
  336. unaryminusn without causing a crash, so I've disabled it (JM)
  337. else if right.left.nodetype=ordconstn then
  338. begin
  339. extraoffset:=right.left.value;
  340. t:=right.right;
  341. t^.registers32 := right.registers32;
  342. putnode(right);
  343. putnode(right.left);
  344. right:=t;
  345. end;}
  346. end;
  347. inc(location.reference.offset,
  348. get_mul_size*extraoffset);
  349. end;
  350. { calculate from left to right }
  351. if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  352. CGMessage(cg_e_illegal_expression);
  353. isjump:=(right.location.loc=LOC_JUMP);
  354. if isjump then
  355. begin
  356. otl:=truelabel;
  357. getlabel(truelabel);
  358. ofl:=falselabel;
  359. getlabel(falselabel);
  360. end;
  361. maybe_save(exprasmlist,right.registers32,location,pushedregs);
  362. secondpass(right);
  363. maybe_restore(exprasmlist,location,pushedregs);
  364. { here we change the location of right
  365. and the update was forgotten so it
  366. led to wrong code in emitrangecheck later PM
  367. so make range check before }
  368. if cs_check_range in aktlocalswitches then
  369. begin
  370. if left.resulttype.def.deftype=arraydef then
  371. begin
  372. if is_open_array(left.resulttype.def) or
  373. is_array_of_const(left.resulttype.def) then
  374. begin
  375. tarraydef(left.resulttype.def).genrangecheck;
  376. srsym:=searchsymonlyin(tloadnode(left).symtable,
  377. 'high'+tvarsym(tloadnode(left).symtableentry).name);
  378. hightree:=cloadnode.create(tvarsym(srsym),tloadnode(left).symtable);
  379. firstpass(hightree);
  380. secondpass(hightree);
  381. location_release(exprasmlist,hightree.location);
  382. reference_reset_symbol(href,newasmsymbol(tarraydef(left.resulttype.def).getrangecheckstring),4);
  383. cg.a_load_loc_ref(exprasmlist,hightree.location,href);
  384. hightree.free;
  385. hightree:=nil;
  386. end;
  387. cg.g_rangecheck(exprasmlist,right,left.resulttype.def);
  388. end;
  389. end;
  390. location_force_reg(exprasmlist,right.location,OS_32,false);
  391. if isjump then
  392. begin
  393. truelabel:=otl;
  394. falselabel:=ofl;
  395. end;
  396. { produce possible range check code: }
  397. if cs_check_range in aktlocalswitches then
  398. begin
  399. if left.resulttype.def.deftype=arraydef then
  400. begin
  401. { done defore (PM) }
  402. end
  403. else if (left.resulttype.def.deftype=stringdef) then
  404. begin
  405. case tstringdef(left.resulttype.def).string_typ of
  406. { it's the same for ansi- and wide strings }
  407. st_widestring,
  408. st_ansistring:
  409. begin
  410. rg.saveusedregisters(exprasmlist,pushed,all_registers);
  411. cg.a_param_reg(exprasmlist,OS_INT,right.location.register,1);
  412. href:=location.reference;
  413. dec(href.offset,7);
  414. cg.a_param_ref(exprasmlist,OS_INT,href,1);
  415. rg.saveregvars(exprasmlist,all_registers);
  416. cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
  417. rg.restoreusedregisters(exprasmlist,pushed);
  418. cg.g_maybe_loadself(exprasmlist);
  419. end;
  420. st_shortstring:
  421. begin
  422. {!!!!!!!!!!!!!!!!!}
  423. end;
  424. st_longstring:
  425. begin
  426. {!!!!!!!!!!!!!!!!!}
  427. end;
  428. end;
  429. end;
  430. end;
  431. if location.reference.index=R_NO then
  432. begin
  433. location.reference.index:=right.location.register;
  434. calc_emit_mul;
  435. end
  436. else
  437. begin
  438. if location.reference.base=R_NO then
  439. begin
  440. case location.reference.scalefactor of
  441. 2 : emit_const_reg(A_SHL,S_L,1,location.reference.index);
  442. 4 : emit_const_reg(A_SHL,S_L,2,location.reference.index);
  443. 8 : emit_const_reg(A_SHL,S_L,3,location.reference.index);
  444. end;
  445. calc_emit_mul;
  446. location.reference.base:=location.reference.index;
  447. location.reference.index:=right.location.register;
  448. end
  449. else
  450. begin
  451. emit_ref_reg(A_LEA,S_L,location.reference,location.reference.index);
  452. rg.ungetregisterint(exprasmlist,location.reference.base);
  453. { the symbol offset is loaded, }
  454. { so release the symbol name and set symbol }
  455. { to nil }
  456. location.reference.symbol:=nil;
  457. location.reference.offset:=0;
  458. calc_emit_mul;
  459. location.reference.base:=location.reference.index;
  460. location.reference.index:=right.location.register;
  461. end;
  462. end;
  463. if nf_memseg in flags then
  464. location.reference.segment:=R_FS;
  465. end;
  466. location.size:=newsize;
  467. end;
  468. begin
  469. caddrnode:=ti386addrnode;
  470. cderefnode:=ti386derefnode;
  471. cvecnode:=ti386vecnode;
  472. end.
  473. {
  474. $Log$
  475. Revision 1.34 2002-06-24 12:43:01 jonas
  476. * fixed errors found with new -CR code from Peter when cycling with -O2p3r
  477. Revision 1.33 2002/05/18 13:34:25 peter
  478. * readded missing revisions
  479. Revision 1.32 2002/05/16 19:46:51 carl
  480. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  481. + try to fix temp allocation (still in ifdef)
  482. + generic constructor calls
  483. + start of tassembler / tmodulebase class cleanup
  484. Revision 1.30 2002/05/13 19:54:38 peter
  485. * removed n386ld and n386util units
  486. * maybe_save/maybe_restore added instead of the old maybe_push
  487. Revision 1.29 2002/05/12 16:53:17 peter
  488. * moved entry and exitcode to ncgutil and cgobj
  489. * foreach gets extra argument for passing local data to the
  490. iterator function
  491. * -CR checks also class typecasts at runtime by changing them
  492. into as
  493. * fixed compiler to cycle with the -CR option
  494. * fixed stabs with elf writer, finally the global variables can
  495. be watched
  496. * removed a lot of routines from cga unit and replaced them by
  497. calls to cgobj
  498. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  499. u32bit then the other is typecasted also to u32bit without giving
  500. a rangecheck warning/error.
  501. * fixed pascal calling method with reversing also the high tree in
  502. the parast, detected by tcalcst3 test
  503. Revision 1.28 2002/04/21 19:02:07 peter
  504. * removed newn and disposen nodes, the code is now directly
  505. inlined from pexpr
  506. * -an option that will write the secondpass nodes to the .s file, this
  507. requires EXTDEBUG define to actually write the info
  508. * fixed various internal errors and crashes due recent code changes
  509. Revision 1.27 2002/04/20 21:37:07 carl
  510. + generic FPC_CHECKPOINTER
  511. + first parameter offset in stack now portable
  512. * rename some constants
  513. + move some cpu stuff to other units
  514. - remove unused constents
  515. * fix stacksize for some targets
  516. * fix generic size problems which depend now on EXTEND_SIZE constant
  517. * removing frame pointer in routines is only available for : i386,m68k and vis targets
  518. Revision 1.26 2002/04/19 15:39:35 peter
  519. * removed some more routines from cga
  520. * moved location_force_reg/mem to ncgutil
  521. * moved arrayconstructnode secondpass to ncgld
  522. Revision 1.25 2002/04/15 19:12:09 carl
  523. + target_info.size_of_pointer -> pointer_size
  524. + some cleanup of unused types/variables
  525. * move several constants from cpubase to their specific units
  526. (where they are used)
  527. + att_Reg2str -> gas_reg2str
  528. + int_reg2str -> std_reg2str
  529. Revision 1.24 2002/04/04 19:06:12 peter
  530. * removed unused units
  531. * use tlocation.size in cg.a_*loc*() routines
  532. Revision 1.23 2002/04/02 17:11:36 peter
  533. * tlocation,treference update
  534. * LOC_CONSTANT added for better constant handling
  535. * secondadd splitted in multiple routines
  536. * location_force_reg added for loading a location to a register
  537. of a specified size
  538. * secondassignment parses now first the right and then the left node
  539. (this is compatible with Kylix). This saves a lot of push/pop especially
  540. with string operations
  541. * adapted some routines to use the new cg methods
  542. Revision 1.22 2002/04/01 09:44:04 jonas
  543. * better fix for new/dispose bug with init/final data
  544. Revision 1.21 2002/03/31 20:26:39 jonas
  545. + a_loadfpu_* and a_loadmm_* methods in tcg
  546. * register allocation is now handled by a class and is mostly processor
  547. independent (+rgobj.pas and i386/rgcpu.pas)
  548. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  549. * some small improvements and fixes to the optimizer
  550. * some register allocation fixes
  551. * some fpuvaroffset fixes in the unary minus node
  552. * push/popusedregisters is now called rg.save/restoreusedregisters and
  553. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  554. also better optimizable)
  555. * fixed and optimized register saving/restoring for new/dispose nodes
  556. * LOC_FPU locations now also require their "register" field to be set to
  557. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  558. - list field removed of the tnode class because it's not used currently
  559. and can cause hard-to-find bugs
  560. Revision 1.20 2002/03/04 19:10:14 peter
  561. * removed compiler warnings
  562. }