2
0

nllvmbas.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. paradef: tpointerdef;
  67. begin
  68. key.sym:=sym;
  69. res:=fsymbollookup.FindOrAdd(@key,sizeof(key));
  70. if not assigned(res^.Data) then
  71. begin
  72. paradef:=cpointerdef.getreusable(sym.vardef);
  73. if (sym.typ=paravarsym) and
  74. paramanager.push_addr_param(sym.varspez,sym.vardef,current_procinfo.procdef.proccalloption) then
  75. paradef:=cpointerdef.getreusable(paradef);
  76. new(callpara,init(paradef,std_param_align,lve_none,[]));
  77. { address must be a temp register }
  78. if (sym.localloc.loc<>LOC_REFERENCE) or
  79. (sym.localloc.reference.base=NR_NO) or
  80. (sym.localloc.reference.index<>NR_NO) or
  81. (sym.localloc.reference.offset<>0) or
  82. assigned(sym.localloc.reference.symbol) then
  83. internalerror(2016111001);
  84. callpara^.loadreg(sym.localloc.reference.base);
  85. fsymboldata.add(callpara);
  86. ptruint(res^.Data):=fsymboldata.count-1;
  87. end;
  88. result:=longint(ptruint(res^.Data));
  89. end;
  90. function tllvmasmnode.getllvmasmparasym(sym: tabstractnormalvarsym): tasmsymbol;
  91. begin
  92. { these have to be transformed from `nr into into $nr; we use ` because
  93. we also have to double all other occurrences of '$' in the assembly
  94. code, and we can't differentiate between these and other '$'s in
  95. agllvm }
  96. result:=current_asmdata.RefAsmSymbol('`'+tostr(getllvmasmopindexforsym(sym)),AT_DATA,false);
  97. end;
  98. procedure tllvmasmnode.ResolveRef(const filepos: tfileposinfo; var op: toper);
  99. var
  100. sym: tabstractnormalvarsym;
  101. ref: treference;
  102. sofs: pint;
  103. indexreg : tregister;
  104. getoffset: boolean;
  105. {$ifdef x86}
  106. scale : byte;
  107. {$endif x86}
  108. begin
  109. { pure assembler routines are handled by the regular code generator }
  110. if po_assembler in current_procinfo.procdef.procoptions then
  111. begin
  112. inherited;
  113. exit;
  114. end;
  115. { translate all symbolic references to "parameters" of the llvm
  116. assembler statements }
  117. case op.typ of
  118. top_local:
  119. begin
  120. sofs:=op.localoper^.localsymofs;
  121. indexreg:=op.localoper^.localindexreg;
  122. {$ifdef x86}
  123. scale:=op.localoper^.localscale;
  124. {$endif x86}
  125. getoffset:=op.localoper^.localgetoffset;
  126. sym:=tabstractnormalvarsym(op.localoper^.localsym);
  127. dispose(op.localoper);
  128. case sym.localloc.loc of
  129. LOC_REFERENCE:
  130. begin
  131. if getoffset then
  132. begin
  133. { todo: print proper error. You cannot get the offset
  134. of a local variable since it may be in a register
  135. outside the assembler block with llvm }
  136. internalerror(2016102001);
  137. end
  138. else
  139. begin
  140. op.typ:=top_ref;
  141. new(op.ref);
  142. reference_reset_symbol(op.ref^,getllvmasmparasym(sym),sofs,
  143. newalignment(sym.localloc.reference.alignment,sofs),[]);
  144. op.ref^.index:=indexreg;
  145. {$ifdef x86}
  146. op.ref^.scalefactor:=scale;
  147. {$endif x86}
  148. end;
  149. end
  150. else
  151. { all locals accessed from assembler are forced into memory
  152. by FPC }
  153. internalerror(2016101506);
  154. end;
  155. end;
  156. else
  157. ;
  158. end;
  159. end;
  160. constructor tllvmasmnode.create(p: TAsmList);
  161. begin
  162. inherited;
  163. end;
  164. destructor tllvmasmnode.destroy;
  165. begin
  166. { normally already freed in pass_generate_code, but in case an error
  167. occurred that may not have happened }
  168. fsymboldata.free;
  169. fsymbollookup.free;
  170. inherited;
  171. end;
  172. procedure tllvmasmnode.pass_generate_code;
  173. var
  174. oldasmlist: tasmlist;
  175. asmai: tai;
  176. begin
  177. oldasmlist:=nil;
  178. if not(po_assembler in current_procinfo.procdef.procoptions) and
  179. not(asmnf_get_asm_position in asmnodeflags) then
  180. begin
  181. { store the assembler code in a separate list, so we can make it
  182. the argument of an asmblock instruction }
  183. oldasmlist:=current_asmdata.CurrAsmList;
  184. current_asmdata.CurrAsmList:=tasmlist.create;
  185. { record relation between parameters and replaced local assembler
  186. operands }
  187. fsymboldata:=tfplist.create;
  188. fsymbollookup:=THashSet.Create(8,True,False);
  189. end;
  190. inherited;
  191. if not(po_assembler in current_procinfo.procdef.procoptions) and
  192. not(asmnf_get_asm_position in asmnodeflags) then
  193. begin
  194. asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
  195. fsymboldata:=nil;
  196. fsymbollookup.free;
  197. fsymbollookup:=nil;
  198. oldasmlist.concat(asmai);
  199. current_asmdata.CurrAsmList:=oldasmlist;
  200. end;
  201. end;
  202. {*****************************************************************************
  203. TLLVMTEMPINFOACCESSOR
  204. *****************************************************************************}
  205. class procedure tllvmtempinfoaccessor.settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags);
  206. begin
  207. { it is not possible to typecast between e.g. an integer and a record
  208. in a register, which is a problem if such a typecast is performed on
  209. an lvalue (since we then have to store it first to a temp in memory,
  210. which means we no longer have an lvalue).
  211. Disable regvars altogether since LLVM will put the values in registers
  212. anyway if possible/useful. }
  213. inherited settempinfoflags(tempinfo,flags-[ti_may_be_in_reg]);
  214. end;
  215. {*****************************************************************************
  216. TTEMPCREATENODE
  217. *****************************************************************************}
  218. procedure tllvmtempcreatenode.pass_generate_code;
  219. begin
  220. inherited;
  221. { if a temp is in a register and we never assign anything to it (e.g.
  222. because it's the register for an inlined function result that never
  223. gets assigned a value), then llvm will be confused the first time
  224. we try to read from it (since it's never been defined) -> always
  225. immediately assign undef to such registers }
  226. if tempinfo^.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_FPUREGISTER,
  227. LOC_CFPUREGISTER,LOC_MMREGISTER,LOC_CMMREGISTER] then
  228. current_asmdata.CurrAsmList.concat(
  229. taillvm.op_reg_size_undef(la_bitcast,tempinfo^.location.register,tempinfo^.typedef)
  230. );
  231. end;
  232. begin
  233. casmnode:=tllvmasmnode;
  234. ctempinfoaccessor:=tllvmtempinfoaccessor;
  235. ctempcreatenode:=tllvmtempcreatenode;
  236. end.