llvmpara.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. {
  2. Copyright (c) 2013 by Jonas Maebe
  3. Includes the llvm parameter manager
  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 llvmpara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,aasmdata,
  22. symconst,symtype,symdef,symsym,
  23. parabase,
  24. cpupara;
  25. type
  26. { LLVM stands for "low level code generator", and regarding parameter
  27. handling it is indeed very low level. We are responsible for decomposing
  28. aggregate parameters into multiple simple parameters in case they have
  29. to be passed in special registers (such as floating point or SSE), and
  30. also for indicating whether e.g. 8 bit parameters need to be sign or
  31. zero exntended. This corresponds to pretty much what we do when creating
  32. parameter locations, so we reuse the original parameter manager and then
  33. process its output.
  34. The future will tell whether we can do this without
  35. architecture-specific code, or whether we will have to integrate parts
  36. into the various tcpuparamanager classes }
  37. tllvmparamanager = class(tcpuparamanager)
  38. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  39. procedure createtempparaloc(list: TAsmList; calloption: tproccalloption; parasym: tparavarsym; can_use_final_stack_loc: boolean; var cgpara: TCGPara); override;
  40. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
  41. function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara; override;
  42. private
  43. procedure set_llvm_paraloc_name(p: tabstractprocdef; hp: tparavarsym; var para: tcgpara);
  44. procedure add_llvm_callee_paraloc_names(p: tabstractprocdef);
  45. end;
  46. implementation
  47. uses
  48. aasmbase,
  49. llvmsym,
  50. paramgr,
  51. cgbase,hlcgobj;
  52. { tllvmparamanager }
  53. function tllvmparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  54. begin
  55. { we can use the paraloc on the callee side if the SSA property is
  56. guaranteed, i.e., if it is a constant location (and if it's not been
  57. split up into multiple locations for ABI reasons). We can't deduce that
  58. from the paraloc though, we need the parasym for that. Potential
  59. future optimisation, although llvm will probably optimise away the
  60. temps we create anyway }
  61. result:=false;
  62. end;
  63. procedure tllvmparamanager.createtempparaloc(list: TAsmList; calloption: tproccalloption; parasym: tparavarsym; can_use_final_stack_loc: boolean; var cgpara: TCGPara);
  64. begin
  65. inherited;
  66. end;
  67. function tllvmparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint;
  68. begin
  69. result:=inherited create_paraloc_info(p, side);
  70. { on the calleeside, llvm declares the parameters similar to Pascal or C
  71. (a list of parameters and their types), but they correspond more
  72. closely to parameter locations than to parameters -> add names to the
  73. locations }
  74. if side=calleeside then
  75. add_llvm_callee_paraloc_names(p)
  76. end;
  77. { hp non-nil: parasym to check
  78. hp nil: function result
  79. }
  80. procedure tllvmparamanager.set_llvm_paraloc_name(p: tabstractprocdef; hp: tparavarsym; var para: tcgpara);
  81. { the default for llvm is to pass aggregates in integer registers or
  82. on the stack (as the ABI prescribes). Records that require special
  83. handling, e.g. (partly) passing in fpu registers, have to be handled
  84. explicitly. This function returns whether an aggregate is handled
  85. specially }
  86. function has_non_default_paraloc: boolean;
  87. var
  88. loc: PCGParaLocation;
  89. begin
  90. loc:=para.Location;
  91. result:=true;
  92. while assigned(loc) do
  93. begin
  94. if not(loc^.loc in [LOC_REGISTER,LOC_REFERENCE]) then
  95. exit;
  96. end;
  97. result:=false;
  98. end;
  99. var
  100. paraloc: PCGParaLocation;
  101. signextstr: TSymStr;
  102. usedef: tdef;
  103. paralocnr: longint;
  104. begin
  105. { byval: a pointer to a type that should actually be passed by
  106. value (e.g. a record that should be passed on the stack) }
  107. if (assigned(hp) and
  108. (hp.vardef.typ in [arraydef,recorddef,objectdef]) and
  109. not paramanager.push_addr_param(hp.varspez,hp.vardef,p.proccalloption) and
  110. not has_non_default_paraloc) or
  111. (not assigned(hp) and
  112. ret_in_param(para.def,p)) then
  113. begin
  114. { the first location is the name of the "byval" parameter }
  115. paraloc:=para.location;
  116. if assigned(hp) then
  117. begin
  118. paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,0),AB_LOCAL,AT_DATA);
  119. paraloc^.llvmvalueloc:=false;
  120. end
  121. else
  122. begin
  123. paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol('%f.result',AB_LOCAL,AT_DATA);
  124. paraloc^.llvmvalueloc:=true;
  125. end;
  126. { the other locations, if any, are not represented individually; llvm
  127. takes care of them behind the scenes }
  128. while assigned(paraloc^.next) do
  129. begin
  130. paraloc:=paraloc^.next;
  131. paraloc^.llvmloc:=nil;
  132. end;
  133. exit;
  134. end;
  135. paraloc:=hp.paraloc[calleeside].location;
  136. paralocnr:=0;
  137. repeat
  138. paraloc^.llvmloc:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,paralocnr),AB_LOCAL,AT_DATA);
  139. paraloc^.llvmvalueloc:=true;
  140. paraloc:=paraloc^.next;
  141. inc(paralocnr);
  142. until not assigned(paraloc);
  143. end;
  144. function tllvmparamanager.get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  145. begin
  146. result:=inherited;
  147. { TODO: initialise result.llvmloc }
  148. end;
  149. procedure tllvmparamanager.add_llvm_callee_paraloc_names(p: tabstractprocdef);
  150. var
  151. paranr: longint;
  152. para: tcgpara;
  153. hp: tparavarsym;
  154. first: boolean;
  155. begin
  156. first:=true;
  157. for paranr:=0 to p.paras.count-1 do
  158. begin
  159. hp:=tparavarsym(p.paras[paranr]);
  160. set_llvm_paraloc_name(p,hp,hp.paraloc[calleeside]);
  161. end;
  162. end;
  163. begin
  164. { replace the native code generator. Maybe this has to be moved to a procedure
  165. like the creations of the code generators, but possibly not since we still
  166. call the original paramanager }
  167. paramanager.free;
  168. paramanager:=tllvmparamanager.create;
  169. end.