summaryrefslogtreecommitdiff
path: root/compiler/llvm/nllvmcon.pas
blob: 89d6e406687de3044290d98720b5cb802239d062 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{
    Copyright (c) 2013 by Jonas Maebe, member of the Free Pascal Compiler
    development team

    Generate llvm bitcode for constants

    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 nllvmcon;

{$i fpcdefs.inc}

interface

    uses
      symtype,
      node,ncgcon;

    type
       tllvmrealconstnode = class(tcgrealconstnode)
          function pass_1 : tnode;override;
          procedure pass_generate_code;override;
       end;

       tllvmstringconstnode = class(tcgstringconstnode)
          procedure pass_generate_code; override;
       protected
          procedure load_dynstring(const strpointerdef: tdef; const elementdef: tdef; const winlikewidestring: boolean); override;
       end;

implementation

    uses
      globtype,globals,verbose,cutils,
      symbase,symtable,symconst,symdef,symsym,defutil,
      aasmdata,aasmcnst,
      ncon,
      llvmbase,aasmllvm,hlcgobj,
      cgbase,cgutils;

{*****************************************************************************
                           tllvmstringconstnode
*****************************************************************************}

    procedure tllvmstringconstnode.pass_generate_code;
      var
        datadef, resptrdef: tdef;
        hreg: tregister;
      begin
        inherited pass_generate_code;
        if cst_type in [cst_conststring,cst_shortstring] then
          begin
            if location.loc<>LOC_CREFERENCE then
              internalerror(2014071202);
            case cst_type of
              cst_conststring:
                { this kind of string const is used both for array of char
                  constants (-> excludes terminating #0) and pchars (-> includes
                  terminating #0). The resultdef excludes the #0 while the data
                  includes it -> insert typecast from datadef to resultdef }
                datadef:=carraydef.getreusable(cansichartype,len+1);
              cst_shortstring:
                { the resultdef of the string constant is the type of the
                  string to which it is assigned, which can be longer or shorter
                  than the length of the string itself -> typecast it to the
                  correct string type }
                datadef:=carraydef.getreusable(cansichartype,min(len,255)+1);
              else
                internalerror(2014071203);
            end;
            { get address of array as pchar }
            resptrdef:=cpointerdef.getreusable(resultdef);
            hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resptrdef);
            hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,datadef,resptrdef,location.reference,hreg);
            hlcg.reference_reset_base(location.reference,resptrdef,hreg,0,location.reference.alignment);
          end;
      end;


    procedure tllvmstringconstnode.load_dynstring(const strpointerdef: tdef; const elementdef: tdef; const winlikewidestring: boolean);
      var
        stringtype: tstringtype;
        strrecdef: trecorddef;
        offset: pint;
        field: tfieldvarsym;
        llvmfield: tllvmshadowsymtableentry;
        dataptrdef: tdef;
        reg: tregister;
        href: treference;
      begin
        case cst_type of
          cst_ansistring:
            stringtype:=st_ansistring;
          cst_unicodestring:
            stringtype:=st_unicodestring;
          cst_widestring:
            stringtype:=st_widestring;
          else
            internalerror(2014040804);
        end;
        { get the recorddef for this string constant }
        strrecdef:=ctai_typedconstbuilder.get_dynstring_rec(stringtype,winlikewidestring,len);
        { offset in the record of the the string data }
        offset:=ctai_typedconstbuilder.get_string_symofs(stringtype,winlikewidestring);
        { field corresponding to this offset }
        field:=trecordsymtable(strrecdef.symtable).findfieldbyoffset(offset);
        llvmfield:=trecordsymtable(strrecdef.symtable).llvmst[field];
        if llvmfield.fieldoffset<>field.fieldoffset then
          internalerror(2015061001);
        { pointerdef to the string data array }
        dataptrdef:=cpointerdef.getreusable(field.vardef);
        { load the address of the string data }
        reg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,dataptrdef);
        reference_reset_symbol(href,lab_str,0,const_align(strpointerdef.size));
        current_asmdata.CurrAsmList.concat(
          taillvm.getelementptr_reg_size_ref_size_const(reg,cpointerdef.getreusable(strrecdef),href,
          s32inttype,field.llvmfieldnr,true));
        { convert into a pointer to the individual elements }
        hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,dataptrdef,strpointerdef,reg,location.register);
      end;

{*****************************************************************************
                           tllvmrealconstnode
*****************************************************************************}

    function tllvmrealconstnode.pass_1 : tnode;
      begin
         result:=nil;
         expectloc:=LOC_FPUREGISTER;
      end;


    procedure tllvmrealconstnode.pass_generate_code;
      begin
         { llvm supports floating point constants directly }
         location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
         location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
         case tfloatdef(resultdef).floattype of
           s32real,s64real:
             current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst_size(la_bitcast,location.register,resultdef,value_real,resultdef));
           { comp and currency are handled as int64 at the llvm level }
           s64comp,
           s64currency:
             { sc80floattype instead of resultdef, see comment in thlcgllvm.a_loadfpu_ref_reg }
             current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_sitofp,location.register,s64inttype,trunc(value_real),sc80floattype));
{$ifdef cpuextended}
           s80real,sc80real:
             current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst80_size(la_bitcast,location.register,resultdef,value_real,resultdef));
{$endif cpuextended}
           else
             internalerror(2013102501);
         end;
      end;


begin
   cstringconstnode:=tllvmstringconstnode;
   crealconstnode:=tllvmrealconstnode;
end.