ncpuset.pas 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. {
  2. Copyright (c) 2015 by Jonas Maebe
  3. Generate AArch64 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 ncpuset;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype;
  22. type
  23. taarch64casenode = class(tcgcasenode)
  24. protected
  25. procedure optimizevalues(var max_linear_list: int64; var max_dist: qword);override;
  26. function has_jumptable: boolean;override;
  27. procedure genjumptable(hp: pcaselabel ;min_, max_: int64);override;
  28. end;
  29. implementation
  30. uses
  31. systems,
  32. verbose,globals,constexp,
  33. symconst,symdef,defutil,
  34. paramgr,
  35. cpuinfo,
  36. pass_2,cgcpu,
  37. ncon,
  38. tgobj,ncgutil,rgobj,aasmcpu,
  39. procinfo,
  40. cgutils;
  41. {*****************************************************************************
  42. TCGCASENODE
  43. *****************************************************************************}
  44. procedure taarch64casenode.optimizevalues(var max_linear_list: int64; var max_dist: qword);
  45. begin
  46. max_linear_list:=10;
  47. end;
  48. function taarch64casenode.has_jumptable: boolean;
  49. begin
  50. has_jumptable:=true;
  51. end;
  52. procedure taarch64casenode.genjumptable(hp: pcaselabel; min_, max_: int64);
  53. var
  54. last: TConstExprInt;
  55. tablelabel: TAsmLabel;
  56. basereg,indexreg,jumpreg: TRegister;
  57. href: TReference;
  58. opcgsize: tcgsize;
  59. sectype: TAsmSectiontype;
  60. jtitemconsttype: taiconst_type;
  61. procedure genitem(list:TAsmList;t : pcaselabel);
  62. var
  63. i : int64;
  64. begin
  65. if assigned(t^.less) then
  66. genitem(list,t^.less);
  67. { fill possible hole }
  68. i:=last.svalue+1;
  69. while i<=t^._low.svalue-1 do
  70. begin
  71. list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,elselabel));
  72. inc(i);
  73. end;
  74. i:=t^._low.svalue;
  75. while i<=t^._high.svalue do
  76. begin
  77. list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,blocklabel(t^.blockid)));
  78. inc(i);
  79. end;
  80. last:=t^._high;
  81. if assigned(t^.greater) then
  82. genitem(list,t^.greater);
  83. end;
  84. begin
  85. if not(target_info.system in systems_darwin) then
  86. jtitemconsttype:=aitconst_32bit
  87. else
  88. { see https://gmplib.org/list-archives/gmp-bugs/2012-December/002836.html }
  89. jtitemconsttype:=aitconst_darwin_dwarf_delta32;
  90. last:=min_;
  91. opcgsize:=def_cgsize(opsize);
  92. { a <= x <= b <-> unsigned(x-a) <= (b-a) }
  93. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister);
  94. if not(jumptable_no_range) then
  95. begin
  96. { case expr greater than max_ => goto elselabel }
  97. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opcgsize,OC_A,aint(max_)-aint(min_),hregister,elselabel);
  98. min_:=0;
  99. end;
  100. { local label in order to avoid using GOT }
  101. current_asmdata.getlabel(tablelabel,alt_data);
  102. indexreg:=cg.makeregsize(current_asmdata.CurrAsmList,hregister,OS_ADDR);
  103. cg.a_load_reg_reg(current_asmdata.CurrAsmList,opcgsize,OS_ADDR,hregister,indexreg);
  104. { load table address }
  105. reference_reset_symbol(href,tablelabel,0,4,[]);
  106. basereg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  107. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,basereg);
  108. { load table slot, 32-bit sign extended }
  109. reference_reset_base(href,basereg,0,href.temppos,4,[]);
  110. href.index:=indexreg;
  111. href.shiftmode:=SM_LSL;
  112. href.shiftimm:=2;
  113. jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  114. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg);
  115. { add table address }
  116. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,basereg,jumpreg);
  117. { and finally jump }
  118. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_BR,jumpreg));
  119. { generate jump table }
  120. if not(target_info.system in systems_darwin) then
  121. sectype:=sec_rodata
  122. else
  123. begin
  124. { on Mac OS X, dead code stripping ("smart linking") happens based on
  125. global symbols: every global/static symbol (symbols that do not
  126. start with "L") marks the start of a new "subsection" that is
  127. discarded by the linker if there are no references to this symbol.
  128. This means that if you put the jump table in the rodata section, it
  129. will become part of the block of data associated with the previous
  130. non-L-label in the rodata section and stay or be thrown away
  131. depending on whether that block of data is referenced. Therefore,
  132. jump tables must be added in the code section and since aktlocaldata
  133. is inserted right after the routine, it will become part of the
  134. same subsection that contains the routine's code }
  135. sectype:=sec_code;
  136. end;
  137. new_section(current_procinfo.aktlocaldata,sectype,current_procinfo.procdef.mangledname,4);
  138. if target_info.system in systems_darwin then
  139. begin
  140. { additionally, these tables are now marked via ".data_region jt32"
  141. and ".end_data_region" }
  142. current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_data_region,'jt32'));
  143. end;
  144. current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel));
  145. genitem(current_procinfo.aktlocaldata,hp);
  146. if target_info.system in systems_darwin then
  147. current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_end_data_region,''));
  148. end;
  149. begin
  150. ccasenode:=taarch64casenode;
  151. end.