n386set.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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(exprasmlist,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.74 2004-05-22 23:34:28 peter
  201. tai_regalloc.allocation changed to ratype to notify rgobj of register size changes
  202. Revision 1.73 2004/02/27 10:21:05 florian
  203. * top_symbol killed
  204. + refaddr to treference added
  205. + refsymbol to treference added
  206. * top_local stuff moved to an extra record to save memory
  207. + aint introduced
  208. * tppufile.get/putint64/aint implemented
  209. Revision 1.72 2004/02/22 12:04:04 florian
  210. + nx86set added
  211. * some more x86-64 fixes
  212. Revision 1.71 2004/02/03 22:32:54 peter
  213. * renamed xNNbittype to xNNinttype
  214. * renamed registers32 to registersint
  215. * replace some s32bit,u32bit with torddef([su]inttype).def.typ
  216. Revision 1.70 2003/11/07 15:58:32 florian
  217. * Florian's culmutative nr. 1; contains:
  218. - invalid calling conventions for a certain cpu are rejected
  219. - arm softfloat calling conventions
  220. - -Sp for cpu dependend code generation
  221. - several arm fixes
  222. - remaining code for value open array paras on heap
  223. Revision 1.69 2003/10/10 17:48:14 peter
  224. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  225. * tregisteralloctor renamed to trgobj
  226. * removed rgobj from a lot of units
  227. * moved location_* and reference_* to cgobj
  228. * first things for mmx register allocation
  229. Revision 1.68 2003/10/09 21:31:37 daniel
  230. * Register allocator splitted, ans abstract now
  231. Revision 1.67 2003/10/01 20:34:49 peter
  232. * procinfo unit contains tprocinfo
  233. * cginfo renamed to cgbase
  234. * moved cgmessage to verbose
  235. * fixed ppc and sparc compiles
  236. Revision 1.66 2003/09/28 21:48:20 peter
  237. * fix register leaks
  238. Revision 1.65 2003/09/07 22:09:35 peter
  239. * preparations for different default calling conventions
  240. * various RA fixes
  241. Revision 1.64 2003/09/05 11:21:39 marco
  242. * applied Peter's patch. Now cycles.
  243. Revision 1.63 2003/09/03 15:55:01 peter
  244. * NEWRA branch merged
  245. Revision 1.62.2.1 2003/08/29 17:29:00 peter
  246. * next batch of updates
  247. Revision 1.62 2003/06/12 22:10:44 jonas
  248. * t386innode.pass_2 already doesn't call a helper anymore since a long
  249. time
  250. Revision 1.61 2003/06/03 21:11:09 peter
  251. * cg.a_load_* get a from and to size specifier
  252. * makeregsize only accepts newregister
  253. * i386 uses generic tcgnotnode,tcgunaryminus
  254. Revision 1.60 2003/06/01 21:38:06 peter
  255. * getregisterfpu size parameter added
  256. * op_const_reg size parameter added
  257. * sparc updates
  258. Revision 1.59 2003/05/31 15:04:31 peter
  259. * load_loc_reg update
  260. Revision 1.58 2003/05/22 21:32:29 peter
  261. * removed some unit dependencies
  262. Revision 1.57 2003/04/27 11:21:35 peter
  263. * aktprocdef renamed to current_procdef
  264. * procinfo renamed to current_procinfo
  265. * procinfo will now be stored in current_module so it can be
  266. cleaned up properly
  267. * gen_main_procsym changed to create_main_proc and release_main_proc
  268. to also generate a tprocinfo structure
  269. * fixed unit implicit initfinal
  270. Revision 1.56 2003/04/25 08:25:26 daniel
  271. * Ifdefs around a lot of calls to cleartempgen
  272. * Fixed registers that are allocated but not freed in several nodes
  273. * Tweak to register allocator to cause less spills
  274. * 8-bit registers now interfere with esi,edi and ebp
  275. Compiler can now compile rtl successfully when using new register
  276. allocator
  277. Revision 1.55 2003/04/23 09:51:16 daniel
  278. * Removed usage of edi in a lot of places when new register allocator used
  279. + Added newra versions of g_concatcopy and secondadd_float
  280. Revision 1.54 2003/04/22 23:50:23 peter
  281. * firstpass uses expectloc
  282. * checks if there are differences between the expectloc and
  283. location.loc from secondpass in EXTDEBUG
  284. Revision 1.53 2003/04/22 14:33:38 peter
  285. * removed some notes/hints
  286. Revision 1.52 2003/04/22 10:09:35 daniel
  287. + Implemented the actual register allocator
  288. + Scratch registers unavailable when new register allocator used
  289. + maybe_save/maybe_restore unavailable when new register allocator used
  290. Revision 1.51 2003/03/13 19:52:23 jonas
  291. * and more new register allocator fixes (in the i386 code generator this
  292. time). At least now the ppc cross compiler can compile the linux
  293. system unit again, but I haven't tested it.
  294. Revision 1.50 2003/02/26 23:06:13 daniel
  295. * Fixed an illegal use of makeregsize
  296. Revision 1.49 2003/02/19 22:39:56 daniel
  297. * Fixed a few issues
  298. Revision 1.48 2003/02/19 22:00:15 daniel
  299. * Code generator converted to new register notation
  300. - Horribily outdated todo.txt removed
  301. Revision 1.47 2003/01/13 14:54:34 daniel
  302. * Further work to convert codegenerator register convention;
  303. internalerror bug fixed.
  304. Revision 1.46 2003/01/08 18:43:57 daniel
  305. * Tregister changed into a record
  306. Revision 1.45 2002/11/25 17:43:27 peter
  307. * splitted defbase in defutil,symutil,defcmp
  308. * merged isconvertable and is_equal into compare_defs(_ext)
  309. * made operator search faster by walking the list only once
  310. Revision 1.44 2002/10/03 21:34:45 carl
  311. * range check error fixes
  312. Revision 1.43 2002/09/17 18:54:05 jonas
  313. * a_load_reg_reg() now has two size parameters: source and dest. This
  314. allows some optimizations on architectures that don't encode the
  315. register size in the register name.
  316. Revision 1.42 2002/09/16 18:08:26 peter
  317. * fix last optimization in genlinearlist, detected by bug tw1066
  318. * use generic casenode.pass2 routine and override genlinearlist
  319. * add jumptable support to generic casenode, by default there is
  320. no jumptable support
  321. Revision 1.41 2002/09/09 13:57:45 jonas
  322. * small optimization to case genlist() case statements
  323. Revision 1.40 2002/08/17 09:23:46 florian
  324. * first part of procinfo rewrite
  325. Revision 1.39 2002/08/12 15:08:42 carl
  326. + stab register indexes for powerpc (moved from gdb to cpubase)
  327. + tprocessor enumeration moved to cpuinfo
  328. + linker in target_info is now a class
  329. * many many updates for m68k (will soon start to compile)
  330. - removed some ifdef or correct them for correct cpu
  331. Revision 1.38 2002/08/11 14:32:30 peter
  332. * renamed current_library to objectlibrary
  333. Revision 1.37 2002/08/11 13:24:17 peter
  334. * saving of asmsymbols in ppu supported
  335. * asmsymbollist global is removed and moved into a new class
  336. tasmlibrarydata that will hold the info of a .a file which
  337. corresponds with a single module. Added librarydata to tmodule
  338. to keep the library info stored for the module. In the future the
  339. objectfiles will also be stored to the tasmlibrarydata class
  340. * all getlabel/newasmsymbol and friends are moved to the new class
  341. Revision 1.36 2002/07/23 14:31:00 daniel
  342. * Added internal error when asked to generate code for 'if expr in []'
  343. Revision 1.35 2002/07/20 11:58:04 florian
  344. * types.pas renamed to defbase.pas because D6 contains a types
  345. unit so this would conflicts if D6 programms are compiled
  346. + Willamette/SSE2 instructions to assembler added
  347. Revision 1.34 2002/07/11 14:41:34 florian
  348. * start of the new generic parameter handling
  349. Revision 1.33 2002/07/06 20:27:26 carl
  350. + generic set handling
  351. Revision 1.32 2002/07/01 18:46:33 peter
  352. * internal linker
  353. * reorganized aasm layer
  354. Revision 1.31 2002/05/18 13:34:25 peter
  355. * readded missing revisions
  356. Revision 1.30 2002/05/16 19:46:52 carl
  357. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  358. + try to fix temp allocation (still in ifdef)
  359. + generic constructor calls
  360. + start of tassembler / tmodulebase class cleanup
  361. Revision 1.28 2002/05/13 19:54:38 peter
  362. * removed n386ld and n386util units
  363. * maybe_save/maybe_restore added instead of the old maybe_push
  364. Revision 1.27 2002/05/12 16:53:17 peter
  365. * moved entry and exitcode to ncgutil and cgobj
  366. * foreach gets extra argument for passing local data to the
  367. iterator function
  368. * -CR checks also class typecasts at runtime by changing them
  369. into as
  370. * fixed compiler to cycle with the -CR option
  371. * fixed stabs with elf writer, finally the global variables can
  372. be watched
  373. * removed a lot of routines from cga unit and replaced them by
  374. calls to cgobj
  375. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  376. u32bit then the other is typecasted also to u32bit without giving
  377. a rangecheck warning/error.
  378. * fixed pascal calling method with reversing also the high tree in
  379. the parast, detected by tcalcst3 test
  380. Revision 1.26 2002/04/25 20:16:40 peter
  381. * moved more routines from cga/n386util
  382. Revision 1.25 2002/04/21 19:02:07 peter
  383. * removed newn and disposen nodes, the code is now directly
  384. inlined from pexpr
  385. * -an option that will write the secondpass nodes to the .s file, this
  386. requires EXTDEBUG define to actually write the info
  387. * fixed various internal errors and crashes due recent code changes
  388. Revision 1.24 2002/04/21 15:37:26 carl
  389. * changeregsize -> rg.makeregsize
  390. Revision 1.23 2002/04/19 15:39:35 peter
  391. * removed some more routines from cga
  392. * moved location_force_reg/mem to ncgutil
  393. * moved arrayconstructnode secondpass to ncgld
  394. Revision 1.22 2002/04/15 19:44:21 peter
  395. * fixed stackcheck that would be called recursively when a stack
  396. error was found
  397. * generic changeregsize(reg,size) for i386 register resizing
  398. * removed some more routines from cga unit
  399. * fixed returnvalue handling
  400. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  401. Revision 1.21 2002/04/02 17:11:36 peter
  402. * tlocation,treference update
  403. * LOC_CONSTANT added for better constant handling
  404. * secondadd splitted in multiple routines
  405. * location_force_reg added for loading a location to a register
  406. of a specified size
  407. * secondassignment parses now first the right and then the left node
  408. (this is compatible with Kylix). This saves a lot of push/pop especially
  409. with string operations
  410. * adapted some routines to use the new cg methods
  411. Revision 1.20 2002/03/31 20:26:39 jonas
  412. + a_loadfpu_* and a_loadmm_* methods in tcg
  413. * register allocation is now handled by a class and is mostly processor
  414. independent (+rgobj.pas and i386/rgcpu.pas)
  415. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  416. * some small improvements and fixes to the optimizer
  417. * some register allocation fixes
  418. * some fpuvaroffset fixes in the unary minus node
  419. * push/popusedregisters is now called rg.save/restoreusedregisters and
  420. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  421. also better optimizable)
  422. * fixed and optimized register saving/restoring for new/dispose nodes
  423. * LOC_FPU locations now also require their "register" field to be set to
  424. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  425. - list field removed of the tnode class because it's not used currently
  426. and can cause hard-to-find bugs
  427. }