n386opt.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Jonas Maebe
  4. This unit implements the 80x86 implementation of optimized 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 n386opt;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses node, nopt;
  22. type
  23. ti386addsstringcharoptnode = class(taddsstringcharoptnode)
  24. function det_resulttype: tnode; override;
  25. function pass_1: tnode; override;
  26. procedure pass_2; override;
  27. end;
  28. ti386addsstringcsstringoptnode = class(taddsstringcsstringoptnode)
  29. { must be duplicated from ti386addnode :( }
  30. procedure pass_2; override;
  31. end;
  32. implementation
  33. uses
  34. globtype,
  35. pass_1,defutil,htypechk,
  36. symdef,paramgr,
  37. aasmbase,aasmtai,
  38. ncnv, ncon, pass_2,
  39. cginfo, cgbase, cpubase,
  40. tgobj, rgobj, cgobj, ncgutil;
  41. {*****************************************************************************
  42. TI386ADDOPTNODE
  43. *****************************************************************************}
  44. function ti386addsstringcharoptnode.det_resulttype: tnode;
  45. begin
  46. det_resulttype := nil;
  47. resulttypepass(left);
  48. resulttypepass(right);
  49. if codegenerror then
  50. exit;
  51. { update the curmaxlen field (before converting to a string!) }
  52. updatecurmaxlen;
  53. if not is_shortstring(left.resulttype.def) then
  54. inserttypeconv(left,cshortstringtype);
  55. resulttype:=left.resulttype;
  56. end;
  57. function ti386addsstringcharoptnode.pass_1: tnode;
  58. begin
  59. pass_1 := nil;
  60. firstpass(left);
  61. firstpass(right);
  62. if codegenerror then
  63. exit;
  64. expectloc:=LOC_CREFERENCE;
  65. if not is_constcharnode(right) then
  66. { it's not sure we need the register, but we can't know it here yet }
  67. calcregisters(self,2,0,0)
  68. else
  69. calcregisters(self,1,0,0);
  70. end;
  71. procedure ti386addsstringcharoptnode.pass_2;
  72. var
  73. l: tasmlabel;
  74. href,href2 : treference;
  75. hreg, lengthreg: tregister;
  76. checklength: boolean;
  77. len : integer;
  78. begin
  79. { first, we have to more or less replicate some code from }
  80. { ti386addnode.pass_2 }
  81. secondpass(left);
  82. if not(tg.istemp(left.location.reference) and
  83. (tg.sizeoftemp(exprasmlist,left.location.reference) = 256)) and
  84. not(nf_use_strconcat in flags) then
  85. begin
  86. tg.Gettemp(exprasmlist,256,tt_normal,href);
  87. cg.g_copyshortstring(exprasmlist,left.location.reference,href,255,true,false);
  88. { location is released by copyshortstring }
  89. location_freetemp(exprasmlist,left.location);
  90. { return temp reference }
  91. location_reset(left.location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  92. left.location.reference:=href;
  93. end;
  94. secondpass(right);
  95. { special case for string := string + char (JM) }
  96. hreg.enum:=R_INTREGISTER;
  97. hreg.number:=NR_NO;
  98. { we have to load the char before checking the length, because we }
  99. { may need registers from the reference }
  100. { is it a constant char? }
  101. if not is_constcharnode(right) then
  102. { no, make sure it is in a register }
  103. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  104. begin
  105. { free the registers of right }
  106. reference_release(exprasmlist,right.location.reference);
  107. { get register for the char }
  108. hreg := rg.getregisterint(exprasmlist,OS_8);
  109. cg.a_load_ref_reg(exprasmlist,OS_8,right.location.reference,hreg);
  110. { I don't think a temp char exists, but it won't hurt (JM) }
  111. tg.ungetiftemp(exprasmlist,right.location.reference);
  112. end
  113. else hreg := right.location.register;
  114. { load the current string length }
  115. lengthreg := rg.getregisterint(exprasmlist,OS_INT);
  116. cg.a_load_ref_reg(exprasmlist,OS_8,left.location.reference,lengthreg);
  117. { do we have to check the length ? }
  118. if tg.istemp(left.location.reference) then
  119. checklength := curmaxlen = 255
  120. else
  121. checklength := curmaxlen >= tstringdef(left.resulttype.def).len;
  122. if checklength then
  123. begin
  124. { is it already maximal? }
  125. objectlibrary.getlabel(l);
  126. if tg.istemp(left.location.reference) then
  127. len:=255
  128. else
  129. len:=tstringdef(left.resulttype.def).len;
  130. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_EQ,len,lengthreg,l)
  131. end;
  132. { no, so increase the length and add the new character }
  133. href2 := left.location.reference;
  134. { we need a new reference to store the character }
  135. { at the end of the string. Check if the base or }
  136. { index register is still free }
  137. if (href2.base.number <> NR_NO) and
  138. (href2.index.number <> NR_NO) then
  139. begin
  140. { they're not free, so add the base reg to }
  141. { the string length (since the index can }
  142. { have a scalefactor) and use lengthreg as base }
  143. cg.a_op_reg_reg(exprasmlist,OP_ADD,OS_INT,href2.base,lengthreg);
  144. href2.base := lengthreg;
  145. end
  146. else
  147. { at least one is still free, so put EDI there }
  148. if href2.base.number = NR_NO then
  149. href2.base := lengthreg
  150. else
  151. begin
  152. href2.index := lengthreg;
  153. href2.scalefactor := 1;
  154. end;
  155. { we need to be one position after the last char }
  156. inc(href2.offset);
  157. { store the character at the end of the string }
  158. if (right.nodetype <> ordconstn) then
  159. begin
  160. { no new_reference(href2) because it's only }
  161. { used once (JM) }
  162. cg.a_load_reg_ref(exprasmlist,OS_8,hreg,href2);
  163. rg.ungetregisterint(exprasmlist,hreg);
  164. end
  165. else
  166. cg.a_load_const_ref(exprasmlist,OS_8,tordconstnode(right).value,href2);
  167. lengthreg.number:=(lengthreg.number and not $ff) or R_SUBL;
  168. { increase the string length }
  169. cg.a_op_const_reg(exprasmlist,OP_ADD,1,lengthreg);
  170. cg.a_load_reg_ref(exprasmlist,OS_8,lengthreg,left.location.reference);
  171. rg.ungetregisterint(exprasmlist,lengthreg);
  172. if checklength then
  173. cg.a_label(exprasmlist,l);
  174. location_copy(location,left.location);
  175. end;
  176. procedure ti386addsstringcsstringoptnode.pass_2;
  177. var
  178. href: treference;
  179. pushedregs: tpushedsavedint;
  180. regstopush: tsupregset;
  181. begin
  182. { first, we have to more or less replicate some code from }
  183. { ti386addnode.pass_2 }
  184. secondpass(left);
  185. if not(tg.istemp(left.location.reference) and
  186. (tg.sizeoftemp(exprasmlist,left.location.reference) = 256)) and
  187. not(nf_use_strconcat in flags) then
  188. begin
  189. tg.GetTemp(exprasmlist,256,tt_normal,href);
  190. cg.g_copyshortstring(exprasmlist,left.location.reference,href,255,true,false);
  191. { release the registers }
  192. location_freetemp(exprasmlist,left.location);
  193. { return temp reference }
  194. location_reset(left.location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  195. left.location.reference:=href;
  196. end;
  197. secondpass(right);
  198. { on the right we do not need the register anymore too }
  199. { Instead of releasing them already, simply do not }
  200. { push them (so the release is in the right place, }
  201. { because emitpushreferenceaddr doesn't need extra }
  202. { registers) (JM) }
  203. regstopush := all_intregisters;
  204. remove_non_regvars_from_loc(right.location,regstopush);
  205. rg.saveusedintregisters(exprasmlist,pushedregs,regstopush);
  206. { push the maximum possible length of the result }
  207. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(2));
  208. { the optimizer can more easily put the }
  209. { deallocations in the right place if it happens }
  210. { too early than when it happens too late (if }
  211. { the pushref needs a "lea (..),edi; push edi") }
  212. reference_release(exprasmlist,right.location.reference);
  213. cg.a_paramaddr_ref(exprasmlist,right.location.reference,paramanager.getintparaloc(1));
  214. rg.saveintregvars(exprasmlist,regstopush);
  215. cg.a_call_name(exprasmlist,'FPC_SHORTSTR_CONCAT');
  216. tg.ungetiftemp(exprasmlist,right.location.reference);
  217. rg.restoreusedintregisters(exprasmlist,pushedregs);
  218. location_copy(location,left.location);
  219. end;
  220. begin
  221. caddsstringcharoptnode := ti386addsstringcharoptnode;
  222. caddsstringcsstringoptnode := ti386addsstringcsstringoptnode
  223. end.
  224. {
  225. $Log$
  226. Revision 1.31 2003-04-22 23:50:23 peter
  227. * firstpass uses expectloc
  228. * checks if there are differences between the expectloc and
  229. location.loc from secondpass in EXTDEBUG
  230. Revision 1.30 2003/04/22 14:33:38 peter
  231. * removed some notes/hints
  232. Revision 1.29 2003/03/28 19:16:57 peter
  233. * generic constructor working for i386
  234. * remove fixed self register
  235. * esi added as address register for i386
  236. Revision 1.28 2003/02/19 22:00:15 daniel
  237. * Code generator converted to new register notation
  238. - Horribily outdated todo.txt removed
  239. Revision 1.27 2003/01/08 18:43:57 daniel
  240. * Tregister changed into a record
  241. Revision 1.26 2002/11/25 17:43:27 peter
  242. * splitted defbase in defutil,symutil,defcmp
  243. * merged isconvertable and is_equal into compare_defs(_ext)
  244. * made operator search faster by walking the list only once
  245. Revision 1.25 2002/11/15 01:58:57 peter
  246. * merged changes from 1.0.7 up to 04-11
  247. - -V option for generating bug report tracing
  248. - more tracing for option parsing
  249. - errors for cdecl and high()
  250. - win32 import stabs
  251. - win32 records<=8 are returned in eax:edx (turned off by default)
  252. - heaptrc update
  253. - more info for temp management in .s file with EXTDEBUG
  254. Revision 1.24 2002/08/23 16:14:49 peter
  255. * tempgen cleanup
  256. * tt_noreuse temp type added that will be used in genentrycode
  257. Revision 1.23 2002/08/11 14:32:30 peter
  258. * renamed current_library to objectlibrary
  259. Revision 1.22 2002/08/11 13:24:17 peter
  260. * saving of asmsymbols in ppu supported
  261. * asmsymbollist global is removed and moved into a new class
  262. tasmlibrarydata that will hold the info of a .a file which
  263. corresponds with a single module. Added librarydata to tmodule
  264. to keep the library info stored for the module. In the future the
  265. objectfiles will also be stored to the tasmlibrarydata class
  266. * all getlabel/newasmsymbol and friends are moved to the new class
  267. Revision 1.21 2002/07/20 11:58:04 florian
  268. * types.pas renamed to defbase.pas because D6 contains a types
  269. unit so this would conflicts if D6 programms are compiled
  270. + Willamette/SSE2 instructions to assembler added
  271. Revision 1.20 2002/07/11 14:41:34 florian
  272. * start of the new generic parameter handling
  273. Revision 1.19 2002/07/07 09:52:34 florian
  274. * powerpc target fixed, very simple units can be compiled
  275. * some basic stuff for better callparanode handling, far from being finished
  276. Revision 1.18 2002/07/01 18:46:33 peter
  277. * internal linker
  278. * reorganized aasm layer
  279. Revision 1.17 2002/05/18 13:34:25 peter
  280. * readded missing revisions
  281. Revision 1.16 2002/05/16 19:46:52 carl
  282. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  283. + try to fix temp allocation (still in ifdef)
  284. + generic constructor calls
  285. + start of tassembler / tmodulebase class cleanup
  286. Revision 1.14 2002/05/13 19:54:38 peter
  287. * removed n386ld and n386util units
  288. * maybe_save/maybe_restore added instead of the old maybe_push
  289. Revision 1.13 2002/05/12 16:53:17 peter
  290. * moved entry and exitcode to ncgutil and cgobj
  291. * foreach gets extra argument for passing local data to the
  292. iterator function
  293. * -CR checks also class typecasts at runtime by changing them
  294. into as
  295. * fixed compiler to cycle with the -CR option
  296. * fixed stabs with elf writer, finally the global variables can
  297. be watched
  298. * removed a lot of routines from cga unit and replaced them by
  299. calls to cgobj
  300. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  301. u32bit then the other is typecasted also to u32bit without giving
  302. a rangecheck warning/error.
  303. * fixed pascal calling method with reversing also the high tree in
  304. the parast, detected by tcalcst3 test
  305. Revision 1.12 2002/04/25 20:16:40 peter
  306. * moved more routines from cga/n386util
  307. Revision 1.11 2002/04/21 15:36:40 carl
  308. * changeregsize -> rg.makeregsize
  309. Revision 1.10 2002/04/15 19:44:21 peter
  310. * fixed stackcheck that would be called recursively when a stack
  311. error was found
  312. * generic changeregsize(reg,size) for i386 register resizing
  313. * removed some more routines from cga unit
  314. * fixed returnvalue handling
  315. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  316. Revision 1.9 2002/04/04 19:06:12 peter
  317. * removed unused units
  318. * use tlocation.size in cg.a_*loc*() routines
  319. Revision 1.8 2002/04/02 17:11:36 peter
  320. * tlocation,treference update
  321. * LOC_CONSTANT added for better constant handling
  322. * secondadd splitted in multiple routines
  323. * location_force_reg added for loading a location to a register
  324. of a specified size
  325. * secondassignment parses now first the right and then the left node
  326. (this is compatible with Kylix). This saves a lot of push/pop especially
  327. with string operations
  328. * adapted some routines to use the new cg methods
  329. Revision 1.7 2002/03/31 20:26:39 jonas
  330. + a_loadfpu_* and a_loadmm_* methods in tcg
  331. * register allocation is now handled by a class and is mostly processor
  332. independent (+rgobj.pas and i386/rgcpu.pas)
  333. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  334. * some small improvements and fixes to the optimizer
  335. * some register allocation fixes
  336. * some fpuvaroffset fixes in the unary minus node
  337. * push/popusedregisters is now called rg.save/restoreusedregisters and
  338. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  339. also better optimizable)
  340. * fixed and optimized register saving/restoring for new/dispose nodes
  341. * LOC_FPU locations now also require their "register" field to be set to
  342. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  343. - list field removed of the tnode class because it's not used currently
  344. and can cause hard-to-find bugs
  345. }