n386set.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 assembler for in set/case 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 n386set;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nset,pass_1,ncgset;
  23. type
  24. ti386casenode = class(tcgcasenode)
  25. procedure optimizevalues(var max_linear_list:longint;var max_dist:cardinal);override;
  26. function has_jumptable : boolean;override;
  27. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);override;
  28. procedure genlinearlist(hp : pcaserecord);override;
  29. end;
  30. implementation
  31. uses
  32. globtype,systems,
  33. verbose,globals,
  34. symconst,symdef,defutil,
  35. aasmbase,aasmtai,aasmcpu,
  36. cgbase,pass_2,
  37. ncon,
  38. cpubase,cpuinfo,procinfo,
  39. cga,cgutils,cgobj,ncgutil,
  40. cgx86;
  41. {*****************************************************************************
  42. TI386CASENODE
  43. *****************************************************************************}
  44. procedure ti386casenode.optimizevalues(var max_linear_list:longint;var max_dist:cardinal);
  45. begin
  46. { a jump table crashes the pipeline! }
  47. if aktoptprocessor=Class386 then
  48. inc(max_linear_list,3)
  49. else if aktoptprocessor=ClassPentium then
  50. inc(max_linear_list,6)
  51. else if aktoptprocessor in [ClassPentium2,ClassPentium3] then
  52. inc(max_linear_list,9)
  53. else if aktoptprocessor=ClassPentium4 then
  54. inc(max_linear_list,14);
  55. end;
  56. function ti386casenode.has_jumptable : boolean;
  57. begin
  58. has_jumptable:=true;
  59. end;
  60. procedure ti386casenode.genjumptable(hp : pcaserecord;min_,max_ : longint);
  61. var
  62. table : tasmlabel;
  63. last : TConstExprInt;
  64. indexreg : tregister;
  65. href : treference;
  66. jumpsegment : TAAsmOutput;
  67. procedure genitem(t : pcaserecord);
  68. var
  69. i : longint;
  70. begin
  71. if assigned(t^.less) then
  72. genitem(t^.less);
  73. { fill possible hole }
  74. for i:=last+1 to t^._low-1 do
  75. jumpSegment.concat(Tai_const_symbol.Create(elselabel));
  76. for i:=t^._low to t^._high do
  77. jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
  78. last:=t^._high;
  79. if assigned(t^.greater) then
  80. genitem(t^.greater);
  81. end;
  82. begin
  83. if (cs_create_smart in aktmoduleswitches) then
  84. jumpsegment:=current_procinfo.aktlocaldata
  85. else
  86. jumpsegment:=datasegment;
  87. if not(jumptable_no_range) then
  88. begin
  89. { case expr less than min_ => goto elselabel }
  90. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aword(min_),hregister,elselabel);
  91. { case expr greater than max_ => goto elselabel }
  92. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_gt,aword(max_),hregister,elselabel);
  93. end;
  94. objectlibrary.getlabel(table);
  95. { make it a 32bit register }
  96. indexreg:=cg.makeregsize(hregister,OS_INT);
  97. cg.a_load_reg_reg(exprasmlist,opsize,OS_INT,hregister,indexreg);
  98. { create reference }
  99. reference_reset_symbol(href,table,0);
  100. href.offset:=(-longint(min_))*4;
  101. href.index:=indexreg;
  102. href.scalefactor:=4;
  103. emit_ref(A_JMP,S_NO,href);
  104. { generate jump table }
  105. if not(cs_littlesize in aktglobalswitches) then
  106. jumpSegment.concat(Tai_Align.Create_Op(4,0));
  107. jumpSegment.concat(Tai_label.Create(table));
  108. last:=min_;
  109. genitem(hp);
  110. end;
  111. procedure ti386casenode.genlinearlist(hp : pcaserecord);
  112. var
  113. first : boolean;
  114. lastrange : boolean;
  115. last : TConstExprInt;
  116. cond_lt,cond_le : tresflags;
  117. procedure genitem(t : pcaserecord);
  118. begin
  119. if assigned(t^.less) then
  120. genitem(t^.less);
  121. { need we to test the first value }
  122. if first and (t^._low>get_min_value(left.resulttype.def)) then
  123. begin
  124. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aword(t^._low),hregister,elselabel);
  125. end;
  126. if t^._low=t^._high then
  127. begin
  128. if t^._low-last=0 then
  129. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,0,hregister,t^.statement)
  130. else
  131. begin
  132. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, aword(t^._low-last), hregister);
  133. cg.a_jmp_flags(exprasmlist,F_E,t^.statement);
  134. end;
  135. last:=t^._low;
  136. lastrange:=false;
  137. end
  138. else
  139. begin
  140. { it begins with the smallest label, if the value }
  141. { is even smaller then jump immediately to the }
  142. { ELSE-label }
  143. if first then
  144. begin
  145. { have we to ajust the first value ? }
  146. if (t^._low>get_min_value(left.resulttype.def)) then
  147. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, longint(t^._low), hregister);
  148. end
  149. else
  150. begin
  151. { if there is no unused label between the last and the }
  152. { present label then the lower limit can be checked }
  153. { immediately. else check the range in between: }
  154. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, longint(t^._low-last), hregister);
  155. { no jump necessary here if the new range starts at }
  156. { at the value following the previous one }
  157. if ((t^._low-last) <> 1) or
  158. (not lastrange) then
  159. cg.a_jmp_flags(exprasmlist,cond_lt,elselabel);
  160. end;
  161. {we need to use A_SUB, because A_DEC does not set the correct flags, therefor
  162. using a_op_const_reg(OP_SUB) is not possible }
  163. emit_const_reg(A_SUB,TCGSize2OpSize[opsize],longint(t^._high-t^._low),hregister);
  164. cg.a_jmp_flags(exprasmlist,cond_le,t^.statement);
  165. last:=t^._high;
  166. lastrange:=true;
  167. end;
  168. first:=false;
  169. if assigned(t^.greater) then
  170. genitem(t^.greater);
  171. end;
  172. begin
  173. if with_sign then
  174. begin
  175. cond_lt:=F_L;
  176. cond_le:=F_LE;
  177. end
  178. else
  179. begin
  180. cond_lt:=F_B;
  181. cond_le:=F_BE;
  182. end;
  183. { do we need to generate cmps? }
  184. if (with_sign and (min_label<0)) then
  185. genlinearcmplist(hp)
  186. else
  187. begin
  188. last:=0;
  189. lastrange:=false;
  190. first:=true;
  191. genitem(hp);
  192. cg.a_jmp_always(exprasmlist,elselabel);
  193. end;
  194. end;
  195. begin
  196. ccasenode:=ti386casenode;
  197. end.
  198. {
  199. $Log$
  200. Revision 1.73 2004-02-27 10:21:05 florian
  201. * top_symbol killed
  202. + refaddr to treference added
  203. + refsymbol to treference added
  204. * top_local stuff moved to an extra record to save memory
  205. + aint introduced
  206. * tppufile.get/putint64/aint implemented
  207. Revision 1.72 2004/02/22 12:04:04 florian
  208. + nx86set added
  209. * some more x86-64 fixes
  210. Revision 1.71 2004/02/03 22:32:54 peter
  211. * renamed xNNbittype to xNNinttype
  212. * renamed registers32 to registersint
  213. * replace some s32bit,u32bit with torddef([su]inttype).def.typ
  214. Revision 1.70 2003/11/07 15:58:32 florian
  215. * Florian's culmutative nr. 1; contains:
  216. - invalid calling conventions for a certain cpu are rejected
  217. - arm softfloat calling conventions
  218. - -Sp for cpu dependend code generation
  219. - several arm fixes
  220. - remaining code for value open array paras on heap
  221. Revision 1.69 2003/10/10 17:48:14 peter
  222. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  223. * tregisteralloctor renamed to trgobj
  224. * removed rgobj from a lot of units
  225. * moved location_* and reference_* to cgobj
  226. * first things for mmx register allocation
  227. Revision 1.68 2003/10/09 21:31:37 daniel
  228. * Register allocator splitted, ans abstract now
  229. Revision 1.67 2003/10/01 20:34:49 peter
  230. * procinfo unit contains tprocinfo
  231. * cginfo renamed to cgbase
  232. * moved cgmessage to verbose
  233. * fixed ppc and sparc compiles
  234. Revision 1.66 2003/09/28 21:48:20 peter
  235. * fix register leaks
  236. Revision 1.65 2003/09/07 22:09:35 peter
  237. * preparations for different default calling conventions
  238. * various RA fixes
  239. Revision 1.64 2003/09/05 11:21:39 marco
  240. * applied Peter's patch. Now cycles.
  241. Revision 1.63 2003/09/03 15:55:01 peter
  242. * NEWRA branch merged
  243. Revision 1.62.2.1 2003/08/29 17:29:00 peter
  244. * next batch of updates
  245. Revision 1.62 2003/06/12 22:10:44 jonas
  246. * t386innode.pass_2 already doesn't call a helper anymore since a long
  247. time
  248. Revision 1.61 2003/06/03 21:11:09 peter
  249. * cg.a_load_* get a from and to size specifier
  250. * makeregsize only accepts newregister
  251. * i386 uses generic tcgnotnode,tcgunaryminus
  252. Revision 1.60 2003/06/01 21:38:06 peter
  253. * getregisterfpu size parameter added
  254. * op_const_reg size parameter added
  255. * sparc updates
  256. Revision 1.59 2003/05/31 15:04:31 peter
  257. * load_loc_reg update
  258. Revision 1.58 2003/05/22 21:32:29 peter
  259. * removed some unit dependencies
  260. Revision 1.57 2003/04/27 11:21:35 peter
  261. * aktprocdef renamed to current_procdef
  262. * procinfo renamed to current_procinfo
  263. * procinfo will now be stored in current_module so it can be
  264. cleaned up properly
  265. * gen_main_procsym changed to create_main_proc and release_main_proc
  266. to also generate a tprocinfo structure
  267. * fixed unit implicit initfinal
  268. Revision 1.56 2003/04/25 08:25:26 daniel
  269. * Ifdefs around a lot of calls to cleartempgen
  270. * Fixed registers that are allocated but not freed in several nodes
  271. * Tweak to register allocator to cause less spills
  272. * 8-bit registers now interfere with esi,edi and ebp
  273. Compiler can now compile rtl successfully when using new register
  274. allocator
  275. Revision 1.55 2003/04/23 09:51:16 daniel
  276. * Removed usage of edi in a lot of places when new register allocator used
  277. + Added newra versions of g_concatcopy and secondadd_float
  278. Revision 1.54 2003/04/22 23:50:23 peter
  279. * firstpass uses expectloc
  280. * checks if there are differences between the expectloc and
  281. location.loc from secondpass in EXTDEBUG
  282. Revision 1.53 2003/04/22 14:33:38 peter
  283. * removed some notes/hints
  284. Revision 1.52 2003/04/22 10:09:35 daniel
  285. + Implemented the actual register allocator
  286. + Scratch registers unavailable when new register allocator used
  287. + maybe_save/maybe_restore unavailable when new register allocator used
  288. Revision 1.51 2003/03/13 19:52:23 jonas
  289. * and more new register allocator fixes (in the i386 code generator this
  290. time). At least now the ppc cross compiler can compile the linux
  291. system unit again, but I haven't tested it.
  292. Revision 1.50 2003/02/26 23:06:13 daniel
  293. * Fixed an illegal use of makeregsize
  294. Revision 1.49 2003/02/19 22:39:56 daniel
  295. * Fixed a few issues
  296. Revision 1.48 2003/02/19 22:00:15 daniel
  297. * Code generator converted to new register notation
  298. - Horribily outdated todo.txt removed
  299. Revision 1.47 2003/01/13 14:54:34 daniel
  300. * Further work to convert codegenerator register convention;
  301. internalerror bug fixed.
  302. Revision 1.46 2003/01/08 18:43:57 daniel
  303. * Tregister changed into a record
  304. Revision 1.45 2002/11/25 17:43:27 peter
  305. * splitted defbase in defutil,symutil,defcmp
  306. * merged isconvertable and is_equal into compare_defs(_ext)
  307. * made operator search faster by walking the list only once
  308. Revision 1.44 2002/10/03 21:34:45 carl
  309. * range check error fixes
  310. Revision 1.43 2002/09/17 18:54:05 jonas
  311. * a_load_reg_reg() now has two size parameters: source and dest. This
  312. allows some optimizations on architectures that don't encode the
  313. register size in the register name.
  314. Revision 1.42 2002/09/16 18:08:26 peter
  315. * fix last optimization in genlinearlist, detected by bug tw1066
  316. * use generic casenode.pass2 routine and override genlinearlist
  317. * add jumptable support to generic casenode, by default there is
  318. no jumptable support
  319. Revision 1.41 2002/09/09 13:57:45 jonas
  320. * small optimization to case genlist() case statements
  321. Revision 1.40 2002/08/17 09:23:46 florian
  322. * first part of procinfo rewrite
  323. Revision 1.39 2002/08/12 15:08:42 carl
  324. + stab register indexes for powerpc (moved from gdb to cpubase)
  325. + tprocessor enumeration moved to cpuinfo
  326. + linker in target_info is now a class
  327. * many many updates for m68k (will soon start to compile)
  328. - removed some ifdef or correct them for correct cpu
  329. Revision 1.38 2002/08/11 14:32:30 peter
  330. * renamed current_library to objectlibrary
  331. Revision 1.37 2002/08/11 13:24:17 peter
  332. * saving of asmsymbols in ppu supported
  333. * asmsymbollist global is removed and moved into a new class
  334. tasmlibrarydata that will hold the info of a .a file which
  335. corresponds with a single module. Added librarydata to tmodule
  336. to keep the library info stored for the module. In the future the
  337. objectfiles will also be stored to the tasmlibrarydata class
  338. * all getlabel/newasmsymbol and friends are moved to the new class
  339. Revision 1.36 2002/07/23 14:31:00 daniel
  340. * Added internal error when asked to generate code for 'if expr in []'
  341. Revision 1.35 2002/07/20 11:58:04 florian
  342. * types.pas renamed to defbase.pas because D6 contains a types
  343. unit so this would conflicts if D6 programms are compiled
  344. + Willamette/SSE2 instructions to assembler added
  345. Revision 1.34 2002/07/11 14:41:34 florian
  346. * start of the new generic parameter handling
  347. Revision 1.33 2002/07/06 20:27:26 carl
  348. + generic set handling
  349. Revision 1.32 2002/07/01 18:46:33 peter
  350. * internal linker
  351. * reorganized aasm layer
  352. Revision 1.31 2002/05/18 13:34:25 peter
  353. * readded missing revisions
  354. Revision 1.30 2002/05/16 19:46:52 carl
  355. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  356. + try to fix temp allocation (still in ifdef)
  357. + generic constructor calls
  358. + start of tassembler / tmodulebase class cleanup
  359. Revision 1.28 2002/05/13 19:54:38 peter
  360. * removed n386ld and n386util units
  361. * maybe_save/maybe_restore added instead of the old maybe_push
  362. Revision 1.27 2002/05/12 16:53:17 peter
  363. * moved entry and exitcode to ncgutil and cgobj
  364. * foreach gets extra argument for passing local data to the
  365. iterator function
  366. * -CR checks also class typecasts at runtime by changing them
  367. into as
  368. * fixed compiler to cycle with the -CR option
  369. * fixed stabs with elf writer, finally the global variables can
  370. be watched
  371. * removed a lot of routines from cga unit and replaced them by
  372. calls to cgobj
  373. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  374. u32bit then the other is typecasted also to u32bit without giving
  375. a rangecheck warning/error.
  376. * fixed pascal calling method with reversing also the high tree in
  377. the parast, detected by tcalcst3 test
  378. Revision 1.26 2002/04/25 20:16:40 peter
  379. * moved more routines from cga/n386util
  380. Revision 1.25 2002/04/21 19:02:07 peter
  381. * removed newn and disposen nodes, the code is now directly
  382. inlined from pexpr
  383. * -an option that will write the secondpass nodes to the .s file, this
  384. requires EXTDEBUG define to actually write the info
  385. * fixed various internal errors and crashes due recent code changes
  386. Revision 1.24 2002/04/21 15:37:26 carl
  387. * changeregsize -> rg.makeregsize
  388. Revision 1.23 2002/04/19 15:39:35 peter
  389. * removed some more routines from cga
  390. * moved location_force_reg/mem to ncgutil
  391. * moved arrayconstructnode secondpass to ncgld
  392. Revision 1.22 2002/04/15 19:44:21 peter
  393. * fixed stackcheck that would be called recursively when a stack
  394. error was found
  395. * generic changeregsize(reg,size) for i386 register resizing
  396. * removed some more routines from cga unit
  397. * fixed returnvalue handling
  398. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  399. Revision 1.21 2002/04/02 17:11:36 peter
  400. * tlocation,treference update
  401. * LOC_CONSTANT added for better constant handling
  402. * secondadd splitted in multiple routines
  403. * location_force_reg added for loading a location to a register
  404. of a specified size
  405. * secondassignment parses now first the right and then the left node
  406. (this is compatible with Kylix). This saves a lot of push/pop especially
  407. with string operations
  408. * adapted some routines to use the new cg methods
  409. Revision 1.20 2002/03/31 20:26:39 jonas
  410. + a_loadfpu_* and a_loadmm_* methods in tcg
  411. * register allocation is now handled by a class and is mostly processor
  412. independent (+rgobj.pas and i386/rgcpu.pas)
  413. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  414. * some small improvements and fixes to the optimizer
  415. * some register allocation fixes
  416. * some fpuvaroffset fixes in the unary minus node
  417. * push/popusedregisters is now called rg.save/restoreusedregisters and
  418. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  419. also better optimizable)
  420. * fixed and optimized register saving/restoring for new/dispose nodes
  421. * LOC_FPU locations now also require their "register" field to be set to
  422. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  423. - list field removed of the tnode class because it's not used currently
  424. and can cause hard-to-find bugs
  425. }