nllvmflw.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. {
  2. Copyright (c) 2016 by Jonas Maebe
  3. Generate assembler for nodes that influence the flow for llvm
  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 nllvmflw;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmbase,aasmdata,
  23. node, nflw, ncgflw, ncgnstfl;
  24. type
  25. tllvmlabelnode = class(tcglabelnode)
  26. function getasmlabel: tasmlabel; override;
  27. end;
  28. tllvmexceptionstatehandler = class(tcgexceptionstatehandler)
  29. class procedure new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate); override;
  30. class procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate); override;
  31. end;
  32. tllvmraisenode = class(tcgraisenode)
  33. function pass_1: tnode; override;
  34. procedure pass_generate_code; override;
  35. end;
  36. implementation
  37. uses
  38. systems,globals,verbose,
  39. symconst,symtable,symsym,llvmdef,defutil,
  40. pass_2,cgutils,hlcgobj,parabase,paramgr,tgobj,
  41. llvmbase,aasmtai,aasmllvm,
  42. procinfo,llvmpi;
  43. {*****************************************************************************
  44. SecondLabel
  45. *****************************************************************************}
  46. function tllvmlabelnode.getasmlabel: tasmlabel;
  47. begin
  48. { don't allocate global labels even if the label is accessed from
  49. another routine: we always have to refer to such labels using the
  50. blockaddress() construct, which works with local labels too.
  51. Additionally, LLVM does not support defining global labels in the
  52. middle of a routine -> jumping to such a label from assembler code
  53. from another function will not work anyway (have to handle that by
  54. passing a blockaddress as argument to an assembler block, although
  55. "some targets may provide defined semantics when using the value as
  56. the operand to an inline assembly") }
  57. if not(assigned(asmlabel)) then
  58. current_asmdata.getjumplabel(asmlabel);
  59. result:=asmlabel
  60. end;
  61. {*****************************************************************************
  62. tllvmexceptionstatehandler
  63. *****************************************************************************}
  64. class procedure tllvmexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate);
  65. var
  66. landingpadlabel: TAsmLabel;
  67. begin
  68. inherited;
  69. { all calls inside the exception block have to be invokes instead,
  70. which refer to the exception label. We can't use the same label as the
  71. one used by the setjmp/longjmp, because only invoke operations are
  72. allowed to refer to a landingpad label -> create an extra label and
  73. emit:
  74. landingpadlabel:
  75. %reg = landingpad ..
  76. exceptstate.exceptionlabel:
  77. <exception handling code>
  78. }
  79. current_asmdata.getjumplabel(landingpadlabel);
  80. { for consistency checking when popping }
  81. tllvmprocinfo(current_procinfo).pushexceptlabel(exceptstate.exceptionlabel);
  82. tllvmprocinfo(current_procinfo).pushexceptlabel(landingpadlabel);
  83. end;
  84. class procedure tllvmexceptionstatehandler.emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
  85. var
  86. reg: tregister;
  87. clause: taillvm;
  88. exc: treference;
  89. landingpaddef: trecorddef;
  90. begin
  91. { prevent fallthrough into the landingpad, not allowed }
  92. hlcg.a_jmp_always(list,exceptionstate.exceptionlabel);
  93. hlcg.a_label(list,tllvmprocinfo(current_procinfo).CurrExceptLabel);
  94. { indicate that we will catch everything to LLVM's control flow
  95. analysis; our personality function will (for now) indicate that it
  96. doesn't actually want to handle any exceptions, so the stack unwinders
  97. will ignore us anyway (our own exceptions are still handled via
  98. setjmp/longjmp) }
  99. clause:=taillvm.exceptclause(
  100. la_catch,voidpointertype,nil,nil);
  101. { dummy register (for now): we use the same code as on other platforms
  102. to determine the exception type, our "personality function" won't
  103. return anything useful }
  104. reg:=hlcg.getintregister(list,u32inttype);
  105. { use packrecords 1 because we don't want padding (LLVM 4.0+ requires
  106. exactly two fields in this struct) }
  107. landingpaddef:=llvmgettemprecorddef([voidpointertype,u32inttype],
  108. 1,
  109. targetinfos[target_info.system]^.alignment.recordalignmin,
  110. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  111. list.concat(taillvm.landingpad(reg,landingpaddef,clause));
  112. { remove current exception label from the stack }
  113. tllvmprocinfo(current_procinfo).popexceptlabel(tllvmprocinfo(current_procinfo).CurrExceptLabel);
  114. { consistency check }
  115. tllvmprocinfo(current_procinfo).popexceptlabel(exceptionstate.exceptionlabel);
  116. inherited;
  117. end;
  118. {*****************************************************************************
  119. tllvmexceptionstatehandler
  120. *****************************************************************************}
  121. function tllvmraisenode.pass_1: tnode;
  122. begin
  123. if assigned(left) then
  124. result:=inherited
  125. else
  126. begin
  127. expectloc:=LOC_VOID;
  128. result:=nil;
  129. end;
  130. end;
  131. procedure tllvmraisenode.pass_generate_code;
  132. var
  133. currexceptlabel: tasmlabel;
  134. begin
  135. location_reset(location,LOC_VOID,OS_NO);
  136. currexceptlabel:=nil;
  137. { a reraise must raise the exception to the parent exception frame }
  138. if fc_catching_exceptions in flowcontrol then
  139. begin
  140. currexceptlabel:=tllvmprocinfo(current_procinfo).CurrExceptLabel;
  141. if tllvmprocinfo(current_procinfo).popexceptlabel(currexceptlabel) then
  142. exclude(flowcontrol,fc_catching_exceptions);
  143. end;
  144. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  145. if assigned(currexceptlabel) then
  146. begin
  147. tllvmprocinfo(current_procinfo).pushexceptlabel(currexceptlabel);
  148. include(flowcontrol,fc_catching_exceptions);
  149. end;
  150. end;
  151. begin
  152. clabelnode:=tllvmlabelnode;
  153. cexceptionstatehandler:=tllvmexceptionstatehandler;
  154. craisenode:=tllvmraisenode;
  155. end.