123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- {
- Copyright (c) 2016 by Jonas Maebe
- Generate assembler for nodes that influence the flow for llvm
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit nllvmflw;
- {$i fpcdefs.inc}
- interface
- uses
- aasmbase,aasmdata,
- nflw, ncgflw, ncgnstfl;
- type
- tllvmlabelnode = class(tcglabelnode)
- function getasmlabel: tasmlabel; override;
- end;
- tllvmexceptionstatehandler = class(tcgexceptionstatehandler)
- class procedure new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate); override;
- class procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate); override;
- end;
- implementation
- {*****************************************************************************
- SecondLabel
- *****************************************************************************}
- uses
- systems,
- symconst,symdef,llvmdef,
- cgbase,cgutils,hlcgobj,
- llvmbase,aasmllvm,
- procinfo,llvmpi;
- function tllvmlabelnode.getasmlabel: tasmlabel;
- begin
- { don't allocate global labels even if the label is accessed from
- another routine: we always have to refer to such labels using the
- blockaddress() construct, which works with local labels too.
- Additionally, LLVM does not support defining global labels in the
- middle of a routine -> jumping to such a label from assembler code
- from another function will not work anyway (have to handle that by
- passing a blockaddress as argument to an assembler block, although
- "some targets may provide defined semantics when using the value as
- the operand to an inline assembly") }
- if not(assigned(asmlabel)) then
- current_asmdata.getjumplabel(asmlabel);
- result:=asmlabel
- end;
- {*****************************************************************************
- tllvmexceptionstatehandler
- *****************************************************************************}
- class procedure tllvmexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps; out exceptstate: texceptionstate);
- var
- landingpadlabel: TAsmLabel;
- begin
- inherited;
- { all calls inside the exception block have to be invokes instead,
- which refer to the exception label. We can't use the same label as the
- one used by the setjmp/longjmp, because only invoke operations are
- allowed to refer to a landingpad label -> create an extra label and
- emit:
- landingpadlabel:
- %reg = landingpad ..
- exceptstate.exceptionlabel:
- <exception handling code>
- }
- current_asmdata.getjumplabel(landingpadlabel);
- { for consistency checking when popping }
- tllvmprocinfo(current_procinfo).pushexceptlabel(exceptstate.exceptionlabel);
- tllvmprocinfo(current_procinfo).pushexceptlabel(landingpadlabel);
- end;
- class procedure tllvmexceptionstatehandler.emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
- var
- reg: tregister;
- clause: taillvm;
- exc: treference;
- landingpaddef: trecorddef;
- begin
- { prevent fallthrough into the landingpad, not allowed }
- hlcg.a_jmp_always(list,exceptionstate.exceptionlabel);
- hlcg.a_label(list,tllvmprocinfo(current_procinfo).CurrExceptLabel);
- { indicate that we will catch everything to LLVM's control flow
- analysis; our personality function will (for now) indicate that it
- doesn't actually want to handle any exceptions, so the stack unwinders
- will ignore us anyway (our own exceptions are still handled via
- setjmp/longjmp) }
- clause:=taillvm.exceptclause(
- la_catch,voidpointertype,nil,nil);
- { dummy register (for now): we use the same code as on other platforms
- to determine the exception type, our "personality function" won't
- return anything useful }
- reg:=hlcg.getintregister(list,u32inttype);
- { use packrecords 1 because we don't want padding (LLVM 4.0+ requires
- exactly two fields in this struct) }
- landingpaddef:=llvmgettemprecorddef([voidpointertype,u32inttype],
- 1,
- targetinfos[target_info.system]^.alignment.recordalignmin,
- targetinfos[target_info.system]^.alignment.maxCrecordalign);
- list.concat(taillvm.landingpad(reg,landingpaddef,clause));
- { remove current exception label from the stack }
- tllvmprocinfo(current_procinfo).popexceptlabel(tllvmprocinfo(current_procinfo).CurrExceptLabel);
- { consistency check }
- tllvmprocinfo(current_procinfo).popexceptlabel(exceptionstate.exceptionlabel);
- inherited;
- end;
- begin
- clabelnode:=tllvmlabelnode;
- cexceptionstatehandler:=tllvmexceptionstatehandler;
- end.
|