n386opt.pas 14 KB

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