nllvmflw.pas 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. aasmbase,aasmdata,
  22. nflw, ncgflw, ncgnstfl;
  23. type
  24. tllvmlabelnode = class(tcglabelnode)
  25. function getasmlabel: tasmlabel; override;
  26. end;
  27. tllvmexceptionstatehandler = class(tcgexceptionstatehandler)
  28. class procedure new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate); override;
  29. class procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate); override;
  30. end;
  31. implementation
  32. {*****************************************************************************
  33. SecondLabel
  34. *****************************************************************************}
  35. uses
  36. systems,
  37. symconst,symdef,llvmdef,
  38. cgbase,cgutils,hlcgobj,
  39. llvmbase,aasmllvm,
  40. procinfo,llvmpi;
  41. function tllvmlabelnode.getasmlabel: tasmlabel;
  42. begin
  43. { don't allocate global labels even if the label is accessed from
  44. another routine: we always have to refer to such labels using the
  45. blockaddress() construct, which works with local labels too.
  46. Additionally, LLVM does not support defining global labels in the
  47. middle of a routine -> jumping to such a label from assembler code
  48. from another function will not work anyway (have to handle that by
  49. passing a blockaddress as argument to an assembler block, although
  50. "some targets may provide defined semantics when using the value as
  51. the operand to an inline assembly") }
  52. if not(assigned(asmlabel)) then
  53. current_asmdata.getjumplabel(asmlabel);
  54. result:=asmlabel
  55. end;
  56. {*****************************************************************************
  57. tllvmexceptionstatehandler
  58. *****************************************************************************}
  59. class procedure tllvmexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate);
  60. var
  61. landingpadlabel: TAsmLabel;
  62. begin
  63. inherited;
  64. { all calls inside the exception block have to be invokes instead,
  65. which refer to the exception label. We can't use the same label as the
  66. one used by the setjmp/longjmp, because only invoke operations are
  67. allowed to refer to a landingpad label -> create an extra label and
  68. emit:
  69. landingpadlabel:
  70. %reg = landingpad ..
  71. exceptstate.exceptionlabel:
  72. <exception handling code>
  73. }
  74. current_asmdata.getjumplabel(landingpadlabel);
  75. { for consistency checking when popping }
  76. tllvmprocinfo(current_procinfo).pushexceptlabel(exceptstate.exceptionlabel);
  77. tllvmprocinfo(current_procinfo).pushexceptlabel(landingpadlabel);
  78. end;
  79. class procedure tllvmexceptionstatehandler.emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
  80. var
  81. reg: tregister;
  82. clause: taillvm;
  83. exc: treference;
  84. landingpaddef: trecorddef;
  85. begin
  86. { prevent fallthrough into the landingpad, not allowed }
  87. hlcg.a_jmp_always(list,exceptionstate.exceptionlabel);
  88. hlcg.a_label(list,tllvmprocinfo(current_procinfo).CurrExceptLabel);
  89. { indicate that we will catch everything to LLVM's control flow
  90. analysis; our personality function will (for now) indicate that it
  91. doesn't actually want to handle any exceptions, so the stack unwinders
  92. will ignore us anyway (our own exceptions are still handled via
  93. setjmp/longjmp) }
  94. clause:=taillvm.exceptclause(
  95. la_catch,voidpointertype,nil,nil);
  96. { dummy register (for now): we use the same code as on other platforms
  97. to determine the exception type, our "personality function" won't
  98. return anything useful }
  99. reg:=hlcg.getintregister(list,u32inttype);
  100. { use packrecords 1 because we don't want padding (LLVM 4.0+ requires
  101. exactly two fields in this struct) }
  102. landingpaddef:=llvmgettemprecorddef([voidpointertype,u32inttype],
  103. 1,
  104. targetinfos[target_info.system]^.alignment.recordalignmin,
  105. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  106. list.concat(taillvm.landingpad(reg,landingpaddef,clause));
  107. { remove current exception label from the stack }
  108. tllvmprocinfo(current_procinfo).popexceptlabel(tllvmprocinfo(current_procinfo).CurrExceptLabel);
  109. { consistency check }
  110. tllvmprocinfo(current_procinfo).popexceptlabel(exceptionstate.exceptionlabel);
  111. inherited;
  112. end;
  113. begin
  114. clabelnode:=tllvmlabelnode;
  115. cexceptionstatehandler:=tllvmexceptionstatehandler;
  116. end.