nx64set.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate x86_64 assembler for in set/case nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nx64set;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. nset,nx86set;
  23. type
  24. tx8664casenode = class(tx86casenode)
  25. procedure optimizevalues(var max_linear_list:int64;var max_dist:qword);override;
  26. procedure genjumptable(hp : pcaselabel;min_,max_ : int64);override;
  27. end;
  28. implementation
  29. uses
  30. systems,
  31. verbose,globals,constexp,
  32. defutil,
  33. aasmbase,aasmtai,aasmdata,
  34. cgbase,
  35. cpubase,procinfo,
  36. cga,cgutils,cgobj;
  37. {*****************************************************************************
  38. TX8664CASENODE
  39. *****************************************************************************}
  40. procedure tx8664casenode.optimizevalues(var max_linear_list:int64;var max_dist:qword);
  41. begin
  42. inc(max_linear_list,9);
  43. end;
  44. { Always generate position-independent jump table, it is twice less in size at a price
  45. of two extra instructions (which shouldn't cause more slowdown than pipeline trashing) }
  46. procedure tx8664casenode.genjumptable(hp : pcaselabel; min_,max_ : int64);
  47. var
  48. last: TConstExprInt;
  49. tablelabel: TAsmLabel;
  50. basereg,indexreg,jumpreg: TRegister;
  51. href: TReference;
  52. opcgsize: tcgsize;
  53. sectype: TAsmSectiontype;
  54. jtitemconsttype: taiconst_type;
  55. procedure genitem(list:TAsmList;t : pcaselabel);
  56. var
  57. i : TConstExprInt;
  58. begin
  59. if assigned(t^.less) then
  60. genitem(list,t^.less);
  61. { fill possible hole }
  62. i:=last+1;
  63. while i<=t^._low-1 do
  64. begin
  65. list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,elselabel));
  66. i:=i+1;
  67. end;
  68. i:=t^._low;
  69. while i<=t^._high do
  70. begin
  71. list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,blocklabel(t^.blockid)));
  72. i:=i+1;
  73. end;
  74. last:=t^._high;
  75. if assigned(t^.greater) then
  76. genitem(list,t^.greater);
  77. end;
  78. begin
  79. if not(target_info.system in systems_darwin) then
  80. jtitemconsttype:=aitconst_32bit
  81. else
  82. { see https://gmplib.org/list-archives/gmp-bugs/2012-December/002836.html }
  83. jtitemconsttype:=aitconst_darwin_dwarf_delta32;
  84. last:=min_;
  85. opcgsize:=def_cgsize(opsize);
  86. if not(jumptable_no_range) then
  87. begin
  88. { a <= x <= b <-> unsigned(x-a) <= (b-a) }
  89. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister);
  90. { case expr greater than max_ => goto elselabel }
  91. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opcgsize,OC_A,aint(max_)-aint(min_),hregister,elselabel);
  92. min_:=0;
  93. { do not sign extend when we load the index register, as we applied an offset above }
  94. opcgsize:=tcgsize2unsigned[opcgsize];
  95. end;
  96. { local label in order to avoid using GOT }
  97. current_asmdata.getlabel(tablelabel,alt_data);
  98. indexreg:=cg.makeregsize(current_asmdata.CurrAsmList,hregister,OS_ADDR);
  99. cg.a_load_reg_reg(current_asmdata.CurrAsmList,opcgsize,OS_ADDR,hregister,indexreg);
  100. { load table address }
  101. reference_reset_symbol(href,tablelabel,0,4,[]);
  102. basereg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  103. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,basereg);
  104. { load table slot, 32-bit sign extended }
  105. reference_reset_base(href,basereg,-aint(min_)*4,ctempposinvalid,4,[]);
  106. href.index:=indexreg;
  107. href.scalefactor:=4;
  108. jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  109. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg);
  110. { add table address }
  111. reference_reset_base(href,basereg,0,ctempposinvalid,sizeof(pint),[]);
  112. href.index:=jumpreg;
  113. href.scalefactor:=1;
  114. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,jumpreg);
  115. { and finally jump }
  116. emit_reg(A_JMP,S_NO,jumpreg);
  117. { generate jump table }
  118. if not(target_info.system in systems_darwin) then
  119. sectype:=sec_rodata
  120. else
  121. { on Mac OS X, dead code stripping ("smart linking") happens based on
  122. global symbols: every global/static symbol (symbols that do not
  123. start with "L") marks the start of a new "subsection" that is
  124. discarded by the linker if there are no references to this symbol.
  125. This means that if you put the jump table in the rodata section, it
  126. will become part of the block of data associated with the previous
  127. non-L-label in the rodata section and stay or be thrown away
  128. depending on whether that block of data is referenced. Therefore,
  129. jump tables must be added in the code section and since aktlocaldata
  130. is inserted right after the routine, it will become part of the
  131. same subsection that contains the routine's code }
  132. sectype:=sec_code;
  133. new_section(current_procinfo.aktlocaldata,sectype,current_procinfo.procdef.mangledname,4);
  134. current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel));
  135. genitem(current_procinfo.aktlocaldata,hp);
  136. end;
  137. begin
  138. ccasenode:=tx8664casenode;
  139. end.