nllvmbas.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. {
  2. Copyright (c) 2015 by Jonas Maebe
  3. This unit implements llvm support for some basic 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 nllvmbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,cclasses,
  22. aasmbase,aasmtai,aasmdata,
  23. nbas,ncgbas,
  24. symsym;
  25. type
  26. tllvmasmnode = class(tcgasmnode)
  27. protected
  28. { map a tasmsymbol to an index in fsymboldata }
  29. fsymbollookup: THashSet;
  30. { the LLVM symbolic inline assembly operands to which the ones in the
  31. source code are mapped }
  32. fsymboldata: tfplist;
  33. function getllvmasmopindexforsym(sym: tabstractnormalvarsym): longint;
  34. function getllvmasmparasym(sym: tabstractnormalvarsym): tasmsymbol;
  35. procedure ResolveRef(const filepos: tfileposinfo; var op: toper); override;
  36. public
  37. constructor create(p : TAsmList); override;
  38. destructor destroy; override;
  39. procedure pass_generate_code; override;
  40. end;
  41. tllvmtempinfoaccessor = class(ttempinfoaccessor)
  42. protected
  43. class procedure settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags); override;
  44. end;
  45. tllvmtempcreatenode = class(tcgtempcreatenode)
  46. procedure pass_generate_code;override;
  47. end;
  48. implementation
  49. uses
  50. verbose,cutils,
  51. cgbase,cgutils,paramgr,
  52. symconst,symdef,procinfo,
  53. node,
  54. cpubase,llvmbase,aasmllvm
  55. ;
  56. {*****************************************************************************
  57. TLLVMASMNODE
  58. *****************************************************************************}
  59. function tllvmasmnode.getllvmasmopindexforsym(sym: tabstractnormalvarsym): longint;
  60. var
  61. key: record
  62. sym: pointer;
  63. end;
  64. res: PHashSetItem;
  65. callpara: pllvmcallpara;
  66. begin
  67. key.sym:=sym;
  68. res:=fsymbollookup.FindOrAdd(@key,sizeof(key));
  69. if not assigned(res^.Data) then
  70. begin
  71. new(callpara);
  72. callpara^.alignment:=std_param_align;
  73. callpara^.def:=cpointerdef.getreusable(sym.vardef);
  74. if (sym.typ=paravarsym) and
  75. paramanager.push_addr_param(sym.varspez,sym.vardef,current_procinfo.procdef.proccalloption) then
  76. callpara^.def:=cpointerdef.getreusable(callpara^.def);
  77. callpara^.sret:=false;
  78. callpara^.byval:=false;
  79. callpara^.valueext:=lve_none;
  80. callpara^.typ:=top_reg;
  81. { address must be a temp register }
  82. if (sym.localloc.loc<>LOC_REFERENCE) or
  83. (sym.localloc.reference.base=NR_NO) or
  84. (sym.localloc.reference.index<>NR_NO) or
  85. (sym.localloc.reference.offset<>0) or
  86. assigned(sym.localloc.reference.symbol) then
  87. internalerror(2016111001);
  88. callpara^.register:=sym.localloc.reference.base;
  89. fsymboldata.add(callpara);
  90. ptruint(res^.Data):=fsymboldata.count-1;
  91. end;
  92. result:=longint(ptruint(res^.Data));
  93. end;
  94. function tllvmasmnode.getllvmasmparasym(sym: tabstractnormalvarsym): tasmsymbol;
  95. begin
  96. { these have to be transformed from `nr into into $nr; we use ` because
  97. we also have to double all other occurrences of '$' in the assembly
  98. code, and we can't differentiate between these and other '$'s in
  99. agllvm }
  100. result:=current_asmdata.RefAsmSymbol('`'+tostr(getllvmasmopindexforsym(sym)),AT_DATA,false);
  101. end;
  102. procedure tllvmasmnode.ResolveRef(const filepos: tfileposinfo; var op: toper);
  103. var
  104. sym: tabstractnormalvarsym;
  105. ref: treference;
  106. sofs: pint;
  107. indexreg : tregister;
  108. getoffset: boolean;
  109. {$ifdef x86}
  110. scale : byte;
  111. {$endif x86}
  112. begin
  113. { pure assembler routines are handled by the regular code generator }
  114. if po_assembler in current_procinfo.procdef.procoptions then
  115. begin
  116. inherited;
  117. exit;
  118. end;
  119. { translate all symbolic references to "parameters" of the llvm
  120. assembler statements }
  121. case op.typ of
  122. top_local:
  123. begin
  124. sofs:=op.localoper^.localsymofs;
  125. indexreg:=op.localoper^.localindexreg;
  126. {$ifdef x86}
  127. scale:=op.localoper^.localscale;
  128. {$endif x86}
  129. getoffset:=op.localoper^.localgetoffset;
  130. sym:=tabstractnormalvarsym(op.localoper^.localsym);
  131. dispose(op.localoper);
  132. case sym.localloc.loc of
  133. LOC_REFERENCE:
  134. begin
  135. if getoffset then
  136. begin
  137. { todo: print proper error. You cannot get the offset
  138. of a local variable since it may be in a register
  139. outside the assembler block with llvm }
  140. internalerror(2016102001);
  141. end
  142. else
  143. begin
  144. op.typ:=top_ref;
  145. new(op.ref);
  146. reference_reset_symbol(op.ref^,getllvmasmparasym(sym),sofs,
  147. newalignment(sym.localloc.reference.alignment,sofs),[]);
  148. op.ref^.index:=indexreg;
  149. {$ifdef x86}
  150. op.ref^.scalefactor:=scale;
  151. {$endif x86}
  152. end;
  153. end
  154. else
  155. { all locals accessed from assembler are forced into memory
  156. by FPC }
  157. internalerror(2016101506);
  158. end;
  159. end;
  160. else
  161. ;
  162. end;
  163. end;
  164. constructor tllvmasmnode.create(p: TAsmList);
  165. begin
  166. inherited;
  167. end;
  168. destructor tllvmasmnode.destroy;
  169. begin
  170. { normally already freed in pass_generate_code, but in case an error
  171. occurred that may not have happened }
  172. fsymboldata.free;
  173. fsymbollookup.free;
  174. inherited;
  175. end;
  176. procedure tllvmasmnode.pass_generate_code;
  177. var
  178. oldasmlist: tasmlist;
  179. asmai: tai;
  180. begin
  181. oldasmlist:=nil;
  182. if not(po_assembler in current_procinfo.procdef.procoptions) and
  183. not(nf_get_asm_position in flags) then
  184. begin
  185. { store the assembler code in a separate list, so we can make it
  186. the argument of an asmblock instruction }
  187. oldasmlist:=current_asmdata.CurrAsmList;
  188. current_asmdata.CurrAsmList:=tasmlist.create;
  189. { record relation between parameters and replaced local assembler
  190. operands }
  191. fsymboldata:=tfplist.create;
  192. fsymbollookup:=THashSet.Create(8,True,False);
  193. end;
  194. inherited;
  195. if not(po_assembler in current_procinfo.procdef.procoptions) and
  196. not(nf_get_asm_position in flags) then
  197. begin
  198. asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
  199. fsymboldata:=nil;
  200. fsymbollookup.free;
  201. fsymbollookup:=nil;
  202. oldasmlist.concat(asmai);
  203. current_asmdata.CurrAsmList:=oldasmlist;
  204. end;
  205. end;
  206. {*****************************************************************************
  207. TLLVMTEMPINFOACCESSOR
  208. *****************************************************************************}
  209. class procedure tllvmtempinfoaccessor.settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags);
  210. begin
  211. { it is not possible to typecast between e.g. an integer and a record
  212. in a register, which is a problem if such a typecast is performed on
  213. an lvalue (since we then have to store it first to a temp in memory,
  214. which means we no longer have an lvalue).
  215. Disable regvars altogether since LLVM will put the values in registers
  216. anyway if possible/useful. }
  217. inherited settempinfoflags(tempinfo,flags-[ti_may_be_in_reg]);
  218. end;
  219. {*****************************************************************************
  220. TTEMPCREATENODE
  221. *****************************************************************************}
  222. procedure tllvmtempcreatenode.pass_generate_code;
  223. begin
  224. inherited;
  225. { if a temp is in a register and we never assign anything to it (e.g.
  226. because it's the register for an inlined function result that never
  227. gets assigned a value), then llvm will be confused the first time
  228. we try to read from it (since it's never been defined) -> always
  229. immediately assign undef to such registers }
  230. if tempinfo^.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_FPUREGISTER,
  231. LOC_CFPUREGISTER,LOC_MMREGISTER,LOC_CMMREGISTER] then
  232. current_asmdata.CurrAsmList.concat(
  233. taillvm.op_reg_size_undef(la_bitcast,tempinfo^.location.register,tempinfo^.typedef)
  234. );
  235. end;
  236. begin
  237. casmnode:=tllvmasmnode;
  238. ctempinfoaccessor:=tllvmtempinfoaccessor;
  239. ctempcreatenode:=tllvmtempcreatenode;
  240. end.