浏览代码

+ some initial support for writing out llvm type information (orddef,
enumdef, records, arrays, strings, classrefdef)
(compile the compiler with OPT="-dsupport_llvm -Fullvm", then a
simple test program with -al and search for "= type" in the
generated assembler file)
o the llvm backend will always remain architecture-specific (that's how
llvm is designed), so in the long run there will be llvm-ppc, llvm-i386
etc backends. That's why llvmaasm and llvmbase exist in addition to the
architecture-specific files.

git-svn-id: branches/llvm@11330 -

Jonas Maebe 17 年之前
父节点
当前提交
f5de069682

+ 3 - 0
.gitattributes

@@ -200,6 +200,9 @@ compiler/ia64/ia64reg.dat svneol=native#text/plain
 compiler/impdef.pas svneol=native#text/plain
 compiler/import.pas svneol=native#text/plain
 compiler/link.pas svneol=native#text/plain
+compiler/llvm/aasmllvm.pas svneol=native#text/plain
+compiler/llvm/llvmbase.pas svneol=native#text/plain
+compiler/llvmdef.pas svneol=native#text/plain
 compiler/m68k/aasmcpu.pas svneol=native#text/plain
 compiler/m68k/ag68kgas.pas svneol=native#text/plain
 compiler/m68k/aoptcpu.pas svneol=native#text/plain

+ 91 - 1
compiler/aasmtai.pas

@@ -76,6 +76,13 @@ interface
 {$ifdef m68k}
           ait_labeled_instruction,
 {$endif m68k}
+{$ifdef support_llvm_typedef}
+          { (llvm) type definition }
+          ait_typedef,
+{$endif support_llvm_typedef}
+{$ifdef support_llvm}
+          ait_llvmins,
+{$endif support_llvm}
           { used to split into tiny assembler files }
           ait_cutobject,
           ait_regalloc,
@@ -160,6 +167,13 @@ interface
 {$ifdef m68k}
           'labeled_instr',
 {$endif m68k}
+{$ifdef support_llvm_typedef}
+          { (llvm) type definition }
+          'ait_typedef',
+{$endif support_llvm_typedef}
+{$ifdef support_llvm}
+          'ait_llvmins',
+{$endif support_llvm}
           'cut',
           'regalloc',
           'tempalloc',
@@ -178,6 +192,9 @@ interface
        { m68k only }
        ,top_regset
 {$endif m68k}
+{$ifdef support_llvm}
+       ,top_string
+{$endif support_llvm}
        { i386 only});
 
       { kinds of operations that an instruction can perform on an operand }
@@ -212,6 +229,9 @@ interface
       {$ifdef m68k}
           top_regset : (regset:^tcpuregisterset);
       {$endif m68k}
+      {$ifdef support_llvm}
+          top_string : (str: pchar);
+      {$endif support_llvm}
       end;
       poper=^toper;
 
@@ -620,6 +640,17 @@ interface
         end;
         tai_align_class = class of tai_align_abstract;
 
+{$ifdef support_llvm_typedef}
+        tai_typedef = class(tai);
+           namestr: pstring;
+           defstr: ansistring;
+           constructor create(const typename: string; const typedef: ansistring);
+           constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+           destructor destroy;override;
+           procedure ppuwrite(ppufile:tcompilerppufile);override;
+        end;
+{$endif support_llvm_typedef}
+
     var
       { array with all class types for tais }
       aiclass : taiclassarray;
@@ -647,7 +678,11 @@ implementation
       SysUtils,
       verbose,
       globals,
-      fmodule;
+      fmodule
+{$ifdef support_llvm}
+      ,strings
+{$endif support_llvm}
+      ;
 
     const
       pputaimarker = 254;
@@ -2031,6 +2066,12 @@ implementation
                     add_reg_instruction_hook(self,shifterop^.rs);
                 end;
 {$endif ARM}
+{$ifdef support_llvm}
+             top_string:
+               begin
+                 str:=strnew(o.str);
+               end;
+{$endif support_llvm}
              end;
           end;
       end;
@@ -2050,6 +2091,12 @@ implementation
               top_regset:
                 dispose(regset);
 {$endif ARM}
+{$ifdef support_llvm}
+             top_string:
+               begin
+                 freemem(str);
+               end;
+{$endif support_llvm}
             end;
             typ:=top_none;
           end;
@@ -2363,6 +2410,49 @@ implementation
       end;
 
 
+{$ifdef support_llvm_typedef}
+{****************************************************************************
+                                tai_typedef
+ ****************************************************************************}
+
+     constructor tai_typedef.create(const typename: string; const typedef: ansistring);
+       begin
+          inherited Create;
+          typ:=ait_typedef;
+          typestr:=strpnew(typename);
+          defstr:=typedef;
+        end
+
+
+    destructor tai_typedef.destroy;
+      begin
+        stringdispose(typestr);
+        inherited destroy;
+      end;
+
+
+    constructor tai_typedef.ppuload(t:taitype;ppufile:tcompilerppufile);
+      var
+        len: aint;
+      begin
+        inherited ppuload(t,ppufile);
+        typestr:=strpnew(ppufile.getstring);
+        len:=ppufile.getaint;
+        setlength(defstr,len);
+        ppufile.getdata(destr[1],len);
+      end;
+
+
+    procedure tai_typedef.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putstring(typestr^);
+        ppufile.putaint(length(defstr));
+        ppufile.putdata(defstr[1],length(defstr));
+      end;
+{$endif support_llvm_typedef}
+
+
 begin
   cai_cpu:=tai_cpu_abstract;
   { aasmcpu is earlier in the unit order and can

+ 38 - 1
compiler/aggas.pas

@@ -32,7 +32,11 @@ interface
       cclasses,
       globtype,globals,
       aasmbase,aasmtai,aasmdata,aasmcpu,
-      assemble;
+      assemble
+{$ifdef support_llvm}
+      , aasmllvm
+{$endif support_llvm}
+      ;
 
 
     type
@@ -46,6 +50,9 @@ interface
         procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder);
         procedure WriteExtraHeader;virtual;
         procedure WriteInstruction(hp: tai);
+{$ifdef support_llvm}
+        procedure WriteLlvmInstruction(hp: tai_llvmcpu);
+{$endif support_llvm}
        public
         function MakeCmdLine: TCmdStr; override;
         procedure WriteTree(p:TAsmList);override;
@@ -94,6 +101,9 @@ implementation
       cutils,cfileutl,systems,
       fmodule,finput,verbose,
       itcpugas,cpubase
+{$ifdef support_llvm}
+      , llvmbase
+{$endif support_llvm}
       ;
 
     const
@@ -414,6 +424,26 @@ implementation
           end;
       end;
 
+{$ifdef support_llvm}
+    procedure TGNUAssembler.WriteLlvmInstruction(hp: tai_llvmcpu);
+      begin
+        { write as comment for now so it can be easily mixed }
+        { into regular assembler                             }
+        AsmWrite('# ');
+        case tai_llvmcpu(hp).llvmopcode of
+          la_type:
+            begin
+              AsmWrite(hp.oper[0]^.ref^.symbol.name);
+              AsmWrite(' = type ');
+              AsmWritePChar(hp.oper[1]^.str);
+              AsmLn;
+            end;
+          else
+            internalerror(2008070301);
+        end;
+      end;
+{$endif support_llvm}
+
 
     procedure TGNUAssembler.WriteDecodedSleb128(a: int64);
       var
@@ -1056,6 +1086,13 @@ implementation
                  AsmWrite(tai_directive(hp).name^);
                AsmLn;
              end;
+{$ifdef support_llvm}
+           ait_llvmins:
+             begin
+               WriteLlvmInstruction(tai_llvmcpu(hp));
+             end;
+{$endif support_llvm}
+           
 
            else
              internalerror(2006012201);

+ 405 - 0
compiler/llvm/aasmllvm.pas

@@ -0,0 +1,405 @@
+{
+    Copyright (c) 1999-2002 by Jonas Maebe
+
+    Contains the assembler object for the PowerPC
+
+    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 aasmllvm;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,verbose,
+  aasmbase,aasmtai,aasmdata,
+  cpubase,cgbase,cgutils,
+  symdef,
+  llvmbase;
+
+    type
+      tai_llvmcpu = class(tai_cpu_abstract)
+        // switch_end (= ']'), unreachable
+        constructor create_llvm(op: tllvmop);
+        constructor op_none(op : tllvmop);
+
+        constructor op_ressym_string(op: tllvmop; sym: tasmsymbol; const str: ansistring);
+        procedure loadstring(opidx:longint;_str: pchar);
+        
+        llvmopcode: tllvmop;
+      end;
+(*
+    procedure InitLlvmAsm;
+    procedure DoneLlvmAsm;
+*)
+
+implementation
+
+uses
+  cutils, cclasses, strings, aasmcpu;
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    constructor tai_llvmcpu.create_llvm(op: tllvmop);
+      begin
+        create(a_none);
+        llvmopcode:=op;
+        typ:=ait_llvmins;
+      end;
+
+
+    procedure tai_llvmcpu.loadstring(opidx:longint;_str: pchar);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_reg then
+             clearop(opidx);
+           str:=strnew(_str);
+           typ:=top_string;
+         end;
+      end;
+
+
+    constructor tai_llvmcpu.op_ressym_string(op: tllvmop; sym: tasmsymbol; const str: ansistring);
+      begin
+        create_llvm(op);
+        ops:=2;
+        loadsymbol(0,sym,0);
+        loadstring(1,pchar(str));
+      end;
+
+
+    constructor tai_llvmcpu.op_none(op : tllvmop);
+      begin
+        create_llvm(op);
+      end;
+
+(*
+
+    constructor taicpu.op_reg(op : tllvmop;_op1 : tregister);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadreg(0,_op1);
+      end;
+
+
+    constructor taicpu.op_const(op : tllvmop;_op1 : aint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadconst(0,_op1);
+      end;
+
+
+    constructor taicpu.op_reg_reg(op : tllvmop;_op1,_op2 : tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+    constructor taicpu.op_reg_const(op:tllvmop; _op1: tregister; _op2: aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+     constructor taicpu.op_const_reg(op:tllvmop; _op1: aint; _op2: tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_ref(op : tllvmop;_op1 : tregister;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_const(op : tllvmop;_op1,_op2 : aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_reg_reg(op : tllvmop;_op1,_op2,_op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_reg_reg_const(op : tllvmop;_op1,_op2 : tregister; _op3: aint);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+     constructor taicpu.op_reg_reg_sym_ofs(op : tllvmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadsymbol(0,_op3,_op3ofs);
+      end;
+
+     constructor taicpu.op_reg_reg_ref(op : tllvmop;_op1,_op2 : tregister; const _op3: treference);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+    constructor taicpu.op_const_reg_reg(op : tllvmop;_op1 : aint;_op2, _op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_const_reg_const(op : tllvmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_const_const_const(op : tllvmop;_op1 : aint;_op2 : aint;_op3 : aint);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_reg(op : tllvmop;_op1,_op2,_op3,_op4 : tregister);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_reg(op : tllvmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_const(op : tllvmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: aint);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(0,_op2);
+         loadreg(0,_op3);
+         loadconst(0,cardinal(_op4));
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_const_const(op : tllvmop;_op1,_op2,_op3 : tregister;_op4,_op5 : aint);
+      begin
+         inherited create(op);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadconst(3,cardinal(_op4));
+         loadconst(4,cardinal(_op5));
+      end;
+
+     constructor taicpu.op_reg_reg_const_const_const(op : tllvmop;_op1,_op2 : tregister;_op3,_op4,_op5 : aint);
+      begin
+         inherited create(op);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+         loadconst(3,_op4);
+         loadconst(4,_op5);
+      end;
+
+    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         condition:=cond;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+     constructor taicpu.op_const_const_sym(op : tasmop;_op1,_op2 : aint; _op3: tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+         loadsymbol(2,_op3,0);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,_op1ofs);
+      end;
+
+
+     constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadsymbol(1,_op2,_op2ofs);
+      end;
+
+
+    constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadsymbol(0,_op1,_op1ofs);
+         loadref(1,_op2);
+      end;
+
+
+{ ****************************** newra stuff *************************** }
+
+    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+      begin
+        result :=
+          (((opcode=A_MR) and
+            (regtype = R_INTREGISTER)) or
+           ((opcode = A_FMR) and
+            (regtype = R_FPUREGISTER))) and
+          { these opcodes can only have registers as operands }
+          (oper[0]^.reg=oper[1]^.reg);
+      end;
+
+
+    function taicpu.spilling_get_operation_type(opnr: aint): topertype;
+      begin
+        result := operand_read;
+        case opcode of
+            A_STMW,A_LMW:
+              internalerror(2005021805);
+            A_STBU, A_STBUX, A_STHU, A_STHUX, A_STWU, A_STWUX, A_STFSU, A_STFSUX, A_STFDU, A_STFDUX, A_STB, A_STBX, A_STH, A_STHX, A_STW, A_STWX, A_STFS, A_STFSX, A_STFD, A_STFDX, A_STFIWX, A_STHBRX, A_STWBRX, A_STWCX_, A_CMP, A_CMPI, A_CMPL, A_CMPLI, A_DCBA, A_DCBI, A_DCBST, A_DCBT, A_DCBTST, A_DCBZ, A_ECOWX, A_FCMPO, A_FCMPU, A_MTMSR, A_TLBIE, A_TW, A_TWI, A_CMPWI, A_CMPW, A_CMPLWI, A_CMPLW, A_MT, A_MTLR, A_MTCTR:;
+            A_RLWIMI:
+              if opnr = 0 then
+                result := operand_readwrite;
+          else
+            if opnr = 0 then
+              result := operand_write;
+          end;
+      end;
+
+
+    function taicpu.spilling_get_operation_type_ref(opnr: aint; reg: tregister): topertype;
+      begin
+        result := operand_read;
+        case opcode of
+          A_STBU, A_STBUX, A_STHU, A_STHUX, A_STWU, A_STWUX, A_STFSU, A_STFSUX, A_STFDU, A_STFDUX:
+            if (oper[opnr]^.ref^.base = reg) then
+              result := operand_readwrite;
+        end;
+      end;
+
+    function spilling_create_load(const ref:treference;r:tregister): tai;
+      begin
+        case getregtype(r) of
+          R_INTREGISTER:
+            result:=taicpu.op_reg_ref(A_LWZ,r,ref);
+          R_FPUREGISTER:
+            result:=taicpu.op_reg_ref(A_LFD,r,ref);
+          else
+            internalerror(2005123101);
+        end;
+      end;
+
+
+    function spilling_create_store(r:tregister; const ref:treference): tai;
+      begin
+        case getregtype(r) of
+          R_INTREGISTER:
+            result:=taicpu.op_reg_ref(A_STW,r,ref);
+          R_FPUREGISTER:
+            result:=taicpu.op_reg_ref(A_STFD,r,ref);
+          else
+            internalerror(2005123102);
+        end;
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+
+*)
+
+end.

+ 67 - 0
compiler/llvm/llvmbase.pas

@@ -0,0 +1,67 @@
+{
+    Copyright (c) 2007-2008 by Jonas Maebe
+
+    Contains the base types 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.
+
+ ****************************************************************************
+}
+{ This Unit contains the base types for LLVM
+}
+unit llvmbase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  strings,globtype,
+  cutils,cclasses,aasmbase,cpuinfo,cgbase;
+
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+      tllvmop = (la_none,
+        { terminator instructions }
+        la_ret, la_br, la_switch, la_invoke, la_unwind, la_unreachable,
+        { binary operations }
+        la_add, la_sub, la_mul, la_div, la_urem, la_srem, la_frem, 
+        { bitwise binary operations }
+        la_shl, la_lshr, la_ashr, la_and, la_or, la_xor,
+        { vector operations }
+        la_extractelement, la_insertelement, la_shufflevector,
+        { memory access and memory addressing operations }
+        la_malloc, la_free, la_alloca,
+        la_load, la_store, la_getelementptr,
+        { conversion operations }
+        la_trunc, la_zext, la_sext, la_fptrunc, la_fpext,
+        la_fptoui, la_fptosi, la_uitofp, la_sitofp,
+        la_ptrtoint, la_inttoptr,
+        la_bitcast,
+        { other operations }
+        la_icmp, la_fcmp,
+        la_phi, la_select, la_call, la_va_arg, la_getresult,
+        la_type);
+
+      {# This should define the array of instructions as string }
+      llvmop2strtable=array[tllvmop] of string[8];
+
+  implementation
+
+end.

+ 1086 - 0
compiler/llvmdef.pas

@@ -0,0 +1,1086 @@
+{
+    Copyright (c) 2008 by Peter Vreman, Florian Klaempfl and Jonas Maebe
+
+    This units contains support for generating LLVM type info
+
+    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.
+
+ ****************************************************************************
+}
+{
+  This units contains support for LLVM type info generation.
+  
+  It's based on the debug info system, since it's quite similar
+}
+unit llvmdef;
+
+{$i fpcdefs.inc}
+{$h+}
+
+interface
+
+    uses
+      cclasses,globtype,
+      aasmbase,aasmtai,aasmdata,
+      symbase,symtype,symdef,symsym,
+      finput,
+      dbgbase;
+
+
+      { TLLVMDefInfo }
+    type
+      TLLVMDefInfo = class(TDebugInfo)
+        { collect all defs in one list so we can reset them easily }
+        defnumberlist,
+        deftowritelist   : TFPObjectList;
+
+        function def_llvm_name(def:tdef) : tasmsymbol;
+        function def_llvm_class_struct_name(def:tobjectdef) : tasmsymbol;
+//        function def_llvm_class_meta_name(def:tobjectdef) : tasmsymbol;
+      protected
+        vardatadef: trecorddef;
+
+        procedure record_def(def:tdef);
+
+        procedure beforeappenddef(list:TAsmList;def:tdef);override;
+        procedure afterappenddef(list:TAsmList;def:tdef);override;
+        procedure appenddef_ord(list:TAsmList;def:torddef);override;
+        procedure appenddef_float(list:TAsmList;def:tfloatdef);override;
+        procedure appenddef_enum(list:TAsmList;def:tenumdef);override;
+        procedure appenddef_array(list:TAsmList;def:tarraydef);override;
+        procedure appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
+        procedure appenddef_record(list:TAsmList;def:trecorddef);override;
+        procedure appenddef_pointer(list:TAsmList;def:tpointerdef);override;
+        procedure appenddef_classref(list:TAsmList;def: tclassrefdef);override;
+        procedure appenddef_string(list:TAsmList;def:tstringdef);override;
+        procedure appenddef_procvar(list:TAsmList;def:tprocvardef);override;
+        procedure appendprocdef(list:TAsmList;def:tprocdef);override;
+        procedure appenddef_formal(list:TAsmList;def: tformaldef);override;
+        procedure appenddef_object(list:TAsmList;def: tobjectdef);override;
+        procedure appenddef_set(list:TAsmList;def: tsetdef);override;
+        procedure appenddef_undefined(list:TAsmList;def: tundefineddef);override;
+        procedure appenddef_variant(list:TAsmList;def: tvariantdef);override;
+
+        procedure appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
+        procedure beforeappendsym(list:TAsmList;sym:tsym);override;
+        procedure appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);override;
+        procedure appendsym_paravar(list:TAsmList;sym:tparavarsym);override;
+        procedure appendsym_localvar(list:TAsmList;sym:tlocalvarsym);override;
+        procedure appendsym_fieldvar(list:TAsmList;sym:tfieldvarsym);override;
+        procedure appendsym_const(list:TAsmList;sym:tconstsym);override;
+        procedure appendsym_type(list:TAsmList;sym:ttypesym);override;
+        procedure appendsym_label(list:TAsmList;sym:tlabelsym);override;
+        procedure appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);override;
+        procedure appendsym_property(list:TAsmList;sym:tpropertysym);override;
+
+        function symname(sym:tsym): String;
+
+        procedure enum_membersyms_callback(p:TObject;arg:pointer);
+
+      public
+        constructor Create;override;
+        destructor Destroy;override;
+        procedure insertmoduleinfo;override;
+        procedure inserttypeinfo;override;
+        procedure referencesections(list:TAsmList);override;
+      end;
+
+implementation
+
+    uses
+      sysutils,cutils,cfileutl,constexp,
+      version,globals,verbose,systems,
+      cpubase,cgbase,paramgr,
+      fmodule,nobj,
+      defutil,symconst,symtable,
+      llvmbase, aasmllvm;
+
+{****************************************************************************
+                              TDebugInfoDwarf
+****************************************************************************}
+
+
+    procedure TLLVMDefInfo.record_def(def:tdef);
+      begin
+        if (def.dbg_state <> dbg_state_unused) then
+          exit;
+        { the name syms are set automatically when requested }
+        def.dbg_state:=dbg_state_used;
+        deftowritelist.Add(def);
+        defnumberlist.Add(def);
+      end;
+
+
+    function TLLVMDefInfo.def_llvm_name(def: tdef): tasmsymbol;
+      begin
+        record_def(def);
+        result:=def.llvm_name_sym;
+      end;
+
+
+    function TLLVMDefInfo.def_llvm_class_struct_name(def: tobjectdef): tasmsymbol;
+      begin
+        record_def(def);
+        result:=def.llvm_class_struct_name_sym;
+      end;
+
+
+    constructor TLLVMDefInfo.Create;
+      begin
+        inherited Create;
+      end;
+
+
+    destructor TLLVMDefInfo.Destroy;
+      begin
+        inherited destroy;
+      end;
+
+
+    procedure TLLVMDefInfo.enum_membersyms_callback(p:TObject; arg: pointer);
+      begin
+        case tsym(p).typ of
+          fieldvarsym:
+            appendsym_fieldvar(TAsmList(arg),tfieldvarsym(p));
+        end;
+      end;
+
+
+
+    procedure TLLVMDefInfo.appenddef_ord(list:TAsmList;def:torddef);
+      var
+        basedef      : tdef;
+        fullbytesize : byte;
+      begin
+        case def.ordtype of
+          s8bit,
+          s16bit,
+          s32bit,
+          s64bit,
+          u8bit,
+          u16bit,
+          u32bit,
+          u64bit,
+          uchar,
+          uwidechar,
+          pasbool,
+          bool8bit,
+          bool16bit,
+          bool32bit,
+          bool64bit,
+          scurrency:
+            begin
+              list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'i'+tostr(def.size*8)));
+            end;
+          uvoid :
+            begin
+              list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'void'));
+            end
+          else
+            internalerror(2008032901);
+        end;
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_float(list:TAsmList;def:tfloatdef);
+      begin
+        case def.floattype of
+          s32real:
+            list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'float'));
+          s64real:
+            list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'double'));
+          s80real:
+            list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'x86_fp80'));
+          s64currency,
+          s64comp:
+            list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'i64'));
+          else
+            internalerror(200601289);
+        end;
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_enum(list:TAsmList;def:tenumdef);
+      var
+        hp : tenumsym;
+      begin
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'i'+tostr(def.size*8)));
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_array(list:TAsmList;def:tarraydef);
+      var
+        typename: ansistring;
+        endstr: ansistring;
+        indexrange: aint;
+{$ifndef llvm_has_packed_arrays}
+      begin
+        if is_packed_array(def) then
+          begin
+            { have to use an array of byte of the appropriate size, }
+            { since llvm doesn't support packed arrays yet natively }
+            typename:=def_llvm_name(s8inttype).name;
+            indexrange:=def.size;
+          end
+        else
+          begin
+            typename:=def_llvm_name(def.elementdef).name;
+            if not is_open_array(def) and
+               not is_dynamic_array(def) then
+              indexrange:=def.highrange-def.lowrange+1
+            else
+              indexrange:=0;
+          end;
+        if not is_dynamic_array(def) then
+          endstr:=']'
+        else
+          endstr:=']*';
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'['+tostr(indexrange)+' x '+typename+endstr))
+{$else not llvm_has_packed_arrays}
+      var
+        arrstart, arrend, typename: ansistring;
+      begin
+        typename:='';
+        if not is_packed_array(def) then
+          begin
+            { regular array: '[' nritems 'x' type ']' }
+            arrstart:='[';
+            arrend:=']'
+          end
+        else
+          begin
+            { packed array: '<' nritems 'x' type '>' }
+            arrstart:='< [';
+            arrend:='] >';
+            if is_ordinal(def.elementdef) then
+              typename:='i'+tostr(def.elepackedbitsize);
+          end;
+        if (typename='') then
+          typename:=def_llvm_name(def.elementdef).name
+
+        if is_open_array(def) then
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),arrstart+'0 x '+typename+arrend))
+        else if is_dynamic_array(def) then
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'[0 x '+typename+']'+'*'))
+        else
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),arrstart+tostr(def.highrange-def.lowrange+1)+' x '+typename+arrend))
+{$endif not llvm_has_packed_arrays}
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_abstractrecord(list:TAsmList;def:tabstractrecorddef);
+      var
+        defstr, endstr: ansistring;
+        symdeflist: tfpobjectlist;
+        i: longint;
+      begin
+        if (tabstractrecordsymtable(def.symtable).usefieldalignment<>C_alignment) then
+          begin
+            { we handle the alignment/padding ourselves }
+            defstr:='< ';
+            endstr:='>'
+          end
+        else
+          begin
+            { let llvm do everything }
+            defstr:= '{ ';
+            endstr:= '}'
+          end;
+        if not assigned(tabstractrecordsymtable(def.symtable).llvmst) then
+          tabstractrecordsymtable(def.symtable).llvmst:=tllvmshadowsymtable.create(trecordsymtable(def.symtable));
+        symdeflist:=tabstractrecordsymtable(def.symtable).llvmst.symdeflist;
+        for i:=0 to pred(symdeflist.count) do
+          defstr:=defstr+def_llvm_name(tllvmshadowsymtableentry(symdeflist[i]).def).name+', ';
+        { remove last ', ' }
+        setlength(defstr,length(defstr)-2);
+        defstr:=defstr+' }';
+        if (def.typ <> objectdef) or
+           not(tobjectdef(def).objecttype in [odt_interfacecom,odt_interfacecorba,odt_dispinterface,odt_class]) then
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),defstr))
+        else
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_class_struct_name(tobjectdef(def)),defstr))
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_record(list:TAsmList;def:trecorddef);
+      begin
+        appenddef_abstractrecord(list,def);
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_pointer(list:TAsmList;def:tpointerdef);
+      begin
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),def_llvm_name(def.pointeddef).name+'*'));
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_classref(list:TAsmList;def: tclassrefdef);
+      var
+        defstr: ansistring;
+        vmtbuilder: tvmtbuilder;
+        i: longint;
+      begin
+        { a pointer to the VMT. Structure of the VMT: }
+        {   InstanceSize  : ptrint  }
+        {   -InstanceSize : ptrint  }
+        {   Parent        : ^parent }
+        {   ClassName     : pointer }
+        {   DynamicTable  : pointer }
+        {   MethodTable   : pointer }
+        {   FieldTable    : pointer }
+        {   TypeInfo      : pointer }
+        {   InitTable     : pointer }
+        {   AutoTable     : pointer }
+        {   IntfTable     : pointer }
+        {   MsgStrTable   : pointer }
+        {   Methods       : X times procvar }
+        defstr:=def_llvm_name(ptrsinttype).name+',';
+        defstr:='< '+defstr+defstr;
+{ needs to be pointer to the parent class' vmt!
+        if assigned(tobjectdef(def.pointeddef).childof) then
+          defstr:=defstr+def_llvm_name(tobjectdef(def.pointeddef).childof).name+'*,'
+        else
+}
+          defstr:=defstr+'void*,';
+        { class name (length+string) }
+        defstr:=defstr+'['+tostr(length(tobjectdef(def.pointeddef).objrealname^)+1)+' x i8]*,';
+        { the other fields }
+        for i:=1 to 8 do
+          defstr:=defstr+'void*,';
+        if not assigned(tobjectdef(def.pointeddef).VMTEntries) then
+          with TVMTBuilder.Create(tobjectdef(def.pointeddef)) do
+            begin
+              generate_vmt;
+              free;
+            end;
+        for i:= 0 to tobjectdef(def.pointeddef).VMTEntries.Count-1 do
+          defstr:=defstr+def_llvm_name(tprocdef(tobjectdef(def.pointeddef).VMTEntries[i])).name+'*,';
+        setlength(defstr,length(defstr)-1);
+        defstr:=defstr+' >*';
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),defstr));
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_string(list:TAsmList;def:tstringdef);
+
+      procedure addnormalstringdef(lendef: tdef);
+        var
+          defstr: ansistring;
+        begin
+          { record with length and array [maxlen x i8 ] }
+          { (also ok for openstrings, as [0 x i8] means }
+          {  "array of unspecified size" in llvm)       }
+          defstr:='< '+def_llvm_name(lendef).name+', ['+tostr(def.len)+' x i8] >';
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),defstr));
+        end;
+
+      begin
+        case def.stringtype of
+          st_shortstring:
+            begin
+              addnormalstringdef(u8inttype);
+            end;
+          st_longstring:
+            begin
+{$ifdef cpu64bitaddr}
+              addnormalstringdef(u64inttype);
+{$else cpu64bitaddr}
+              addnormalstringdef(u32inttype);
+{$endif cpu64bitaddr}
+           end;
+         st_ansistring:
+           begin
+             { looks like a pchar }
+             list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'i8*'));
+           end;
+         st_unicodestring,
+         st_widestring:
+           begin
+             { looks like a pwidechar }
+             list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'i16*'));
+           end;
+        end;
+      end;
+
+    procedure TLLVMDefInfo.appenddef_procvar(list:TAsmList;def:tprocvardef);
+
+      procedure doappend;
+        var
+          i : longint;
+        begin
+(*
+          if assigned(def.typesym) then
+            append_entry(DW_TAG_subroutine_type,true,[
+              DW_AT_name,DW_FORM_string,symname(def.typesym)+#0,
+              DW_AT_prototyped,DW_FORM_flag,true
+            ])
+          else
+            append_entry(DW_TAG_subroutine_type,true,[
+              DW_AT_prototyped,DW_FORM_flag,true
+            ]);
+          if not(is_void(tprocvardef(def).returndef)) then
+            append_labelentry_ref(DW_AT_type,def_dwarf_lab(tprocvardef(def).returndef));
+          finish_entry;
+
+          { write parameters }
+          for i:=0 to def.paras.count-1 do
+            begin
+              append_entry(DW_TAG_formal_parameter,false,[
+                DW_AT_name,DW_FORM_string,symname(tsym(def.paras[i]))+#0
+              ]);
+              append_labelentry_ref(DW_AT_type,def_dwarf_lab(tparavarsym(def.paras[i]).vardef));
+              finish_entry;
+            end;
+
+          finish_children;
+*)
+        end;
+
+      var
+        proc : tasmlabel;
+
+      begin
+        if def.is_methodpointer then
+          begin
+            list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'methodpointer*'));
+          end
+        else
+          list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'procvar*'));
+      end;
+
+
+    procedure TLLVMDefInfo.beforeappenddef(list:TAsmList;def:tdef);
+      var
+        labsym : tasmsymbol;
+      begin
+        list.concat(tai_comment.Create(strpnew('LLVM definition '+def.typename)));
+(*
+        labsym:=def_dwarf_lab(def);
+        if ds_dwarf_dbg_info_written in def.defstates then
+          current_asmdata.asmlists[al_dwarf_info].concat(tai_symbol.create_global(labsym,0))
+        else
+          current_asmdata.asmlists[al_dwarf_info].concat(tai_symbol.create(labsym,0));
+*)
+      end;
+
+
+    procedure TLLVMDefInfo.afterappenddef(list:TAsmList;def:tdef);
+      begin
+      end;
+
+
+    procedure TLLVMDefInfo.appendprocdef(list:TAsmList;def:tprocdef);
+      var
+        procendlabel   : tasmlabel;
+        funcrettype    : tasmsymbol;
+        procentry      : string;
+        dreg           : byte;
+      begin
+        if not assigned(def.procstarttai) then
+          exit;
+
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'procedure/function'));
+(*
+        current_asmdata.asmlists[al_dwarf_info].concat(tai_comment.Create(strpnew('Procdef '+def.fullprocname(true))));
+        append_entry(DW_TAG_subprogram,true,
+          [DW_AT_name,DW_FORM_string,symname(def.procsym)+#0,
+           DW_AT_external,DW_FORM_flag,po_global in def.procoptions
+          { data continues below }
+          { problem: base reg isn't known here
+            DW_AT_frame_base,DW_FORM_block1,1
+          }
+          ]);
+        { append block data }
+        { current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(dwarf_reg(def.))); }
+
+        if not(is_void(tprocdef(def).returndef)) then
+          append_labelentry_ref(DW_AT_type,def_dwarf_lab(tprocdef(def).returndef));
+
+        { mark end of procedure }
+        current_asmdata.getlabel(procendlabel,alt_dbgtype);
+        current_asmdata.asmlists[al_procedures].insertbefore(tai_label.create(procendlabel),def.procendtai);
+
+        if (target_info.system = system_powerpc64_linux) then
+          procentry := '.' + def.mangledname
+        else
+          procentry := def.mangledname;
+
+        append_labelentry(DW_AT_low_pc,current_asmdata.RefAsmSymbol(procentry));
+        append_labelentry(DW_AT_high_pc,procendlabel);
+
+        if assigned(def.funcretsym) and
+           (tabstractnormalvarsym(def.funcretsym).refs>0) then
+          begin
+            if tabstractnormalvarsym(def.funcretsym).localloc.loc=LOC_REFERENCE then
+              begin
+                finish_entry;
+
+                if paramanager.ret_in_param(def.returndef,def.proccalloption) then
+                  funcrettype:=def_dwarf_ref_lab(def.returndef)
+                else
+                  funcrettype:=def_dwarf_lab(def.returndef);
+
+                append_entry(DW_TAG_formal_parameter,false,[
+                  DW_AT_name,DW_FORM_string,def.procsym.name+#0,
+                  {
+                  DW_AT_decl_file,DW_FORM_data1,0,
+                  DW_AT_decl_line,DW_FORM_data1,
+                  }
+                  { data continues below }
+                  DW_AT_location,DW_FORM_block1,1+Lengthsleb128(tabstractnormalvarsym(def.funcretsym).localloc.reference.offset)
+                ]);
+
+                { append block data }
+                dreg:=dwarf_reg(tabstractnormalvarsym(def.funcretsym).localloc.reference.base);
+                current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(ord(DW_OP_breg0)+dreg));
+                current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_sleb128bit(tabstractnormalvarsym(def.funcretsym).localloc.reference.offset));
+                append_labelentry_ref(DW_AT_type,funcrettype);
+              end;
+          end;
+        finish_entry;
+
+        if assigned(def.parast) then
+          write_symtable_syms(current_asmdata.asmlists[al_dwarf_info],def.parast);
+        { local type defs and vars should not be written
+          inside the main proc }
+        if assigned(def.localst) and
+           (def.localst.symtabletype=localsymtable) then
+          write_symtable_syms(current_asmdata.asmlists[al_dwarf_info],def.localst);
+
+        { last write the types from this procdef }
+        if assigned(def.parast) then
+          write_symtable_defs(current_asmdata.asmlists[al_dwarf_info],def.parast);
+        if assigned(def.localst) and
+           (def.localst.symtabletype=localsymtable) then
+          write_symtable_defs(current_asmdata.asmlists[al_dwarf_info],def.localst);
+
+        finish_children;
+*)
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_var(list:TAsmList;sym:tabstractnormalvarsym);
+      var
+        templist : TAsmList;
+        blocksize : longint;
+        dreg : byte;
+      begin      
+        { external symbols can't be resolved at link time, so we
+          can't generate stabs for them
+
+          not sure if this applies to dwarf as well (FK)
+        }
+        if vo_is_external in sym.varoptions then
+          exit;
+
+        def_llvm_name(sym.vardef);
+
+        { There is no space allocated for not referenced locals }
+        if (sym.owner.symtabletype=localsymtable) and (sym.refs=0) then
+          exit;
+(*
+        templist:=TAsmList.create;
+
+        case sym.localloc.loc of
+          LOC_REGISTER,
+          LOC_CREGISTER,
+          LOC_MMREGISTER,
+          LOC_CMMREGISTER,
+          LOC_FPUREGISTER,
+          LOC_CFPUREGISTER :
+            begin
+              templist.concat(tai_const.create_8bit(ord(DW_OP_regx)));
+              dreg:=dwarf_reg(sym.localloc.register);
+              templist.concat(tai_const.create_uleb128bit(dreg));
+              blocksize:=1+Lengthuleb128(dreg);
+            end;
+          else
+            begin
+              case sym.typ of
+                staticvarsym:
+                  begin
+                    if (vo_is_thread_var in sym.varoptions) then
+                      begin
+{$warning !!! FIXME: dwarf for thread vars !!!
+}
+                        blocksize:=0;
+                      end
+                    else
+                      begin
+                        templist.concat(tai_const.create_8bit(3));
+                        templist.concat(tai_const.createname(sym.mangledname,0));
+                        blocksize:=1+sizeof(puint);
+                      end;
+                  end;
+                paravarsym,
+                localvarsym:
+                  begin
+                    dreg:=dwarf_reg(sym.localloc.reference.base);
+                    templist.concat(tai_const.create_8bit(ord(DW_OP_breg0)+dreg));
+                    templist.concat(tai_const.create_sleb128bit(sym.localloc.reference.offset));
+                    blocksize:=1+Lengthsleb128(sym.localloc.reference.offset);
+                  end
+                else
+                  internalerror(200601288);
+              end;
+            end;
+        end;
+
+        if sym.typ=paravarsym then
+          tag:=DW_TAG_formal_parameter
+        else
+          tag:=DW_TAG_variable;
+
+        if not(sym.localloc.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_MMREGISTER,
+                                 LOC_CMMREGISTER,LOC_FPUREGISTER,LOC_CFPUREGISTER]) and
+           ((sym.owner.symtabletype = globalsymtable) or
+            (sp_static in sym.symoptions) or
+            (vo_is_public in sym.varoptions)) then
+          append_entry(tag,false,[
+            DW_AT_name,DW_FORM_string,symname(sym)+#0,
+            {
+            DW_AT_decl_file,DW_FORM_data1,0,
+            DW_AT_decl_line,DW_FORM_data1,
+            }
+            DW_AT_external,DW_FORM_flag,true,
+            { data continues below }
+            DW_AT_location,DW_FORM_block1,blocksize
+            ])
+{$ifdef gdb_supports_DW_AT_variable_parameter}
+        else if (sym.typ=paravarsym) and
+            paramanager.push_addr_param(sym.varspez,sym.vardef,tprocdef(sym.owner.defowner).proccalloption) and
+            not(vo_has_local_copy in sym.varoptions) and
+            not is_open_string(sym.vardef) then
+          append_entry(tag,false,[
+            DW_AT_name,DW_FORM_string,symname(sym)+#0,
+            DW_AT_variable_parameter,DW_FORM_flag,true,
+            {
+            DW_AT_decl_file,DW_FORM_data1,0,
+            DW_AT_decl_line,DW_FORM_data1,
+            }
+            { data continues below }
+            DW_AT_location,DW_FORM_block1,blocksize
+            ])
+{$endif gdb_supports_DW_AT_variable_parameter}
+        else
+          append_entry(tag,false,[
+            DW_AT_name,DW_FORM_string,symname(sym)+#0,
+            {
+            DW_AT_decl_file,DW_FORM_data1,0,
+            DW_AT_decl_line,DW_FORM_data1,
+            }
+            { data continues below }
+            DW_AT_location,DW_FORM_block1,blocksize
+            ]);
+        { append block data }
+        current_asmdata.asmlists[al_dwarf_info].concatlist(templist);
+{$ifndef gdb_supports_DW_AT_variable_parameter}
+        if (sym.typ=paravarsym) and
+            paramanager.push_addr_param(sym.varspez,sym.vardef,tprocdef(sym.owner.defowner).proccalloption) and
+            not(vo_has_local_copy in sym.varoptions) and
+            not is_open_string(sym.vardef) then
+          append_labelentry_ref(DW_AT_type,def_dwarf_ref_lab(sym.vardef))
+        else
+{$endif not gdb_supports_DW_AT_variable_parameter}
+          append_labelentry_ref(DW_AT_type,def_dwarf_lab(sym.vardef));
+
+        templist.free;
+
+        finish_entry;
+*)
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_staticvar(list:TAsmList;sym:tstaticvarsym);
+      begin
+        appendsym_var(list,sym);
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_localvar(list:TAsmList;sym:tlocalvarsym);
+      begin
+        appendsym_var(list,sym);
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_paravar(list:TAsmList;sym:tparavarsym);
+      begin
+        appendsym_var(list,sym);
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_fieldvar(list:TAsmList;sym: tfieldvarsym);
+      var
+        bitoffset,
+        fieldoffset,
+        fieldnatsize: aint;
+      begin
+//        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE),'fieldvasym');
+(*
+        if sp_static in sym.symoptions then
+          exit;
+
+        if (tabstractrecordsymtable(sym.owner).usefieldalignment<>bit_alignment) or
+           { only ordinals are bitpacked }
+           not is_ordinal(sym.vardef) then
+          begin
+            { other kinds of fields can however also appear in a bitpacked   }
+            { record, and then their offset is also specified in bits rather }
+            { than in bytes                                                  }
+            if (tabstractrecordsymtable(sym.owner).usefieldalignment<>bit_alignment) then
+              fieldoffset:=sym.fieldoffset
+            else
+              fieldoffset:=sym.fieldoffset div 8;
+            append_entry(DW_TAG_member,false,[
+              DW_AT_name,DW_FORM_string,symname(sym)+#0,
+              DW_AT_data_member_location,DW_FORM_block1,1+lengthuleb128(fieldoffset)
+              ]);
+          end
+        else
+          begin
+            if (sym.vardef.packedbitsize > 255) then
+              internalerror(2007061201);
+
+            { we don't bitpack according to the ABI, but as close as }
+            { possible, i.e., equivalent to gcc's                    }
+            { __attribute__((__packed__)), which is also what gpc    }
+            { does.                                                  }
+            fieldnatsize:=max(sizeof(pint),sym.vardef.size);
+            fieldoffset:=(sym.fieldoffset div (fieldnatsize*8)) * fieldnatsize;
+            bitoffset:=sym.fieldoffset mod (fieldnatsize*8);
+            if (target_info.endian=endian_little) then
+              bitoffset:=(fieldnatsize*8)-bitoffset-sym.vardef.packedbitsize;
+            append_entry(DW_TAG_member,false,[
+              DW_AT_name,DW_FORM_string,symname(sym)+#0,
+              { gcc also generates both a bit and byte size attribute }
+              { we don't support ordinals >= 256 bits }
+              DW_AT_byte_size,DW_FORM_data1,fieldnatsize,
+              { nor >= 256 bits (not yet, anyway, see IE above) }
+              DW_AT_bit_size,DW_FORM_data1,sym.vardef.packedbitsize,
+              { data1 and data2 are unsigned, bitoffset can also be negative }
+              DW_AT_bit_offset,DW_FORM_data4,bitoffset,
+              DW_AT_data_member_location,DW_FORM_block1,1+lengthuleb128(fieldoffset)
+              ]);
+          end;
+        current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(ord(DW_OP_plus_uconst)));
+        current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_uleb128bit(fieldoffset));
+
+        append_labelentry_ref(DW_AT_type,def_dwarf_lab(sym.vardef));
+        finish_entry;
+*)
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_const(list:TAsmList;sym:tconstsym);
+      begin
+//        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE),'constsym');
+(*
+        append_entry(DW_TAG_constant,false,[
+          DW_AT_name,DW_FORM_string,symname(sym)+#0
+          ]);
+        { for string constants, constdef isn't set because they have no real type }
+        if not(sym.consttyp in [conststring,constresourcestring,constwstring]) then
+          append_labelentry_ref(DW_AT_type,def_dwarf_lab(sym.constdef));
+        current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_AT_const_value)));
+        case sym.consttyp of
+          conststring:
+            begin
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_string)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_string.create(strpas(pchar(sym.value.valueptr))));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(0));
+            end;
+          constset,
+          constwstring,
+          constguid,
+          constresourcestring:
+            begin
+              { write dummy for now }
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_string)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_string.create(''));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(0));
+            end;
+          constord:
+            begin
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_sdata)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_sleb128bit(sym.value.valueord.svalue));
+            end;
+          constnil:
+            begin
+{$ifdef cpu64bitaddr}
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_data8)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_64bit(0));
+{$else cpu64bitaddr}
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_data4)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_32bit(0));
+{$endif cpu64bitaddr}
+            end;
+          constpointer:
+            begin
+{$ifdef cpu64bitaddr}
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_data8)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_64bit(int64(sym.value.valueordptr)));
+{$else cpu64bitaddr}
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_data4)));
+              current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_32bit(sym.value.valueordptr));
+{$endif cpu64bitaddr}
+            end;
+          constreal:
+            begin
+              current_asmdata.asmlists[al_dwarf_abbrev].concat(tai_const.create_uleb128bit(ord(DW_FORM_block1)));
+              case tfloatdef(sym.constdef).floattype of
+                s32real:
+                  begin
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(4));
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_real_32bit.create(psingle(sym.value.valueptr)^));
+                  end;
+                s64comp,
+                s64currency,
+                s64real:
+                  begin
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(8));
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_real_64bit.create(pdouble(sym.value.valueptr)^));
+                  end;
+                s80real:
+                  begin
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_const.create_8bit(10));
+                    current_asmdata.asmlists[al_dwarf_info].concat(tai_real_80bit.create(pextended(sym.value.valueptr)^));
+                  end;
+                else
+                  internalerror(200601291);
+              end;
+            end;
+          else
+            internalerror(200601292);
+        end;
+        finish_entry;
+*)
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_label(list:TAsmList;sym: tlabelsym);
+      begin
+        { ignore label syms for now, the problem is that a label sym
+          can have more than one label associated e.g. in case of
+          an inline procedure expansion }
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_property(list:TAsmList;sym: tpropertysym);
+      begin
+        { ignored for now }
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_type(list:TAsmList;sym: ttypesym);
+      begin
+//        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,'typesym');
+        record_def(sym.typedef);
+      end;
+
+
+    procedure TLLVMDefInfo.appendsym_absolute(list:TAsmList;sym:tabsolutevarsym);
+      var
+        templist : TAsmList;
+        blocksize : longint;
+        symlist : ppropaccesslistitem;
+      begin
+//        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE),'absolutesym'));
+      end;
+
+
+    procedure TLLVMDefInfo.beforeappendsym(list:TAsmList;sym:tsym);
+      begin
+      end;
+
+
+    procedure TLLVMDefInfo.insertmoduleinfo;
+      begin
+      end;
+
+
+    procedure TLLVMDefInfo.inserttypeinfo;
+
+      procedure write_defs_to_write;
+        var
+          n       : integer;
+          looplist,
+          templist: TFPObjectList;
+          def     : tdef;
+        begin
+          templist := TFPObjectList.Create(False);
+          looplist := deftowritelist;
+          while looplist.count > 0 do
+            begin
+              deftowritelist := templist;
+              for n := 0 to looplist.count - 1 do
+                begin
+                  def := tdef(looplist[n]);
+                  case def.dbg_state of
+                    dbg_state_written:
+                      continue;
+                    dbg_state_writing:
+                      internalerror(200610052);
+                    dbg_state_unused:
+                      internalerror(200610053);
+                    dbg_state_used:
+                      appenddef(current_asmdata.asmlists[al_dwarf_info],def)
+                  else
+                    internalerror(200610054);
+                  end;
+                end;
+              looplist.clear;
+              templist := looplist;
+              looplist := deftowritelist;
+            end;
+          templist.free;
+        end;
+
+
+      var
+        storefilepos  : tfileposinfo;
+        lenstartlabel : tasmlabel;
+        i : longint;
+        def: tdef;
+      begin
+        storefilepos:=current_filepos;
+        current_filepos:=current_module.mainfilepos;
+
+        defnumberlist:=TFPObjectList.create(false);
+        deftowritelist:=TFPObjectList.create(false);
+
+        { not exported (FK)
+            FILEREC
+            TEXTREC
+        }
+        vardatadef:=trecorddef(search_system_type('TVARDATA').typedef);
+
+        { write all global/local variables. This will flag all required tdefs  }
+        if assigned(current_module.globalsymtable) then
+          write_symtable_syms(current_asmdata.asmlists[al_dwarf_info],current_module.globalsymtable);
+        if assigned(current_module.localsymtable) then
+          write_symtable_syms(current_asmdata.asmlists[al_dwarf_info],current_module.localsymtable);
+
+        { write all procedures and methods. This will flag all required tdefs }
+        if assigned(current_module.globalsymtable) then
+          write_symtable_procdefs(current_asmdata.asmlists[al_dwarf_info],current_module.globalsymtable);
+        if assigned(current_module.localsymtable) then
+          write_symtable_procdefs(current_asmdata.asmlists[al_dwarf_info],current_module.localsymtable);
+
+        { reset unit type info flag }
+        reset_unit_type_info;
+
+        { write used types from the used units }
+        write_used_unit_type_info(current_asmdata.asmlists[al_dwarf_info],current_module);
+
+        { last write the types from this unit }
+        if assigned(current_module.globalsymtable) then
+          write_symtable_defs(current_asmdata.asmlists[al_dwarf_info],current_module.globalsymtable);
+        if assigned(current_module.localsymtable) then
+          write_symtable_defs(current_asmdata.asmlists[al_dwarf_info],current_module.localsymtable);
+
+        { write defs not written yet }
+        write_defs_to_write;
+
+        { reset all def labels }
+        for i:=0 to defnumberlist.count-1 do
+          begin
+            def := tdef(defnumberlist[i]);
+            if assigned(def) then
+              begin
+                def.dwarf_lab:=nil;
+                def.dbg_state:=dbg_state_unused;
+              end;
+          end;
+
+        defnumberlist.free;
+        defnumberlist:=nil;
+        deftowritelist.free;
+        deftowritelist:=nil;
+
+        current_filepos:=storefilepos;
+      end;
+
+
+    procedure TLLVMDefInfo.referencesections(list:TAsmList);
+      begin
+      end;
+
+
+    function TLLVMDefInfo.symname(sym: tsym): String;
+      begin
+        if (sym.typ=paravarsym) and
+           (vo_is_self in tparavarsym(sym).varoptions) then
+          result:='this'
+        else
+          result := sym.Name;
+      end;
+
+
+
+    procedure TLLVMDefInfo.appenddef_formal(list:TAsmList;def: tformaldef);
+      begin
+        { gdb 6.4 doesn't support DW_TAG_unspecified_type so we
+          replace it with a unsigned type with size 0 (FK)
+        }
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'undef*'));
+      end;
+
+
+    procedure TLLVMDefInfo.appenddef_object(list:TAsmList;def: tobjectdef);
+      procedure doappend;
+        begin
+          appenddef_abstractrecord(list,def);
+        end;
+
+
+      begin
+        case def.objecttype of
+          odt_cppclass,
+          odt_object:
+            doappend;
+          odt_interfacecom,
+          odt_interfacecorba,
+          odt_dispinterface,
+          odt_class:
+            begin
+              { implicit pointer }
+              list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),def_llvm_class_struct_name(def).name+'*'));
+              doappend;
+            end;
+          else
+            internalerror(200602041);
+        end;
+      end;
+
+    procedure TLLVMDefInfo.appenddef_set(list:TAsmList;def: tsetdef);
+      begin
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'[ '+tostr(def.size)+ 'x i8 ]'));
+      end;
+
+    procedure TLLVMDefInfo.appenddef_undefined(list:TAsmList;def: tundefineddef);
+      begin
+        { gdb 6.4 doesn't support DW_TAG_unspecified_type so we
+          replace it with a unsigned type with size 0 (FK)
+        }
+        list.concat(tai_llvmcpu.op_ressym_string(LA_TYPE,def_llvm_name(def),'undef'));
+      end;
+
+    procedure TLLVMDefInfo.appenddef_variant(list:TAsmList;def: tvariantdef);
+      begin
+        { variants aren't known to dwarf2 but writting tvardata should be enough }
+        appenddef_record(list,trecorddef(vardatadef));
+      end;
+
+end.

+ 29 - 6
compiler/pdecvar.pas

@@ -1219,14 +1219,20 @@ implementation
          uniondef : trecorddef;
          hintsymoptions : tsymoptions;
          semicoloneaten: boolean;
+{$ifdef support_llvm}
+         is_first_field: boolean;
+{$endif support_llvm}
 {$if defined(powerpc) or defined(powerpc64)}
          tempdef: tdef;
-         is_first_field: boolean;
+         is_first_type: boolean;
 {$endif powerpc or powerpc64}
       begin
          recst:=tabstractrecordsymtable(symtablestack.top);
+{$ifdef support_llvm}
+         is_first_field:=true;
+{$endif support_llvm}
 {$if defined(powerpc) or defined(powerpc64)}
-         is_first_field := true;
+         is_first_type:=true;
 {$endif powerpc or powerpc64}
          old_current_object_option:=current_object_option;
          { all variables are public if not in a object declaration }
@@ -1280,7 +1286,7 @@ implementation
                  the alignment of the first field.  */
              }
              if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and
-                is_first_field and
+                is_first_type and
                 (symtablestack.top.symtabletype=recordsymtable) and
                 (trecordsymtable(symtablestack.top).usefieldalignment=C_alignment) then
                begin
@@ -1295,7 +1301,7 @@ implementation
                  if (maxpadalign>4) and
                     (maxpadalign>trecordsymtable(symtablestack.top).padalignment) then
                    trecordsymtable(symtablestack.top).padalignment:=maxpadalign;
-                 is_first_field:=false;
+                 is_first_type:=false;
                end;
 {$endif powerpc or powerpc64}
 
@@ -1309,6 +1315,15 @@ implementation
              hintsymoptions:=[];
              try_consume_hintdirective(hintsymoptions);
 
+{$ifdef support_llvm}
+             { mark first field }
+             if (is_first_field) then
+               begin
+                 include(tfieldvarsym(sc[0]).varoptions,vo_is_first_field);
+                 is_first_field:=false;
+               end;
+{$endif support_llvm}
+
              { update variable type and hints }
              for i:=0 to sc.count-1 do
                begin
@@ -1407,6 +1422,14 @@ implementation
               read_anon_type(casetype,true);
               if assigned(fieldvs) then
                 begin
+{$ifdef support_llvm}
+                 { mark first field if not yet marked }
+                 if (is_first_field) then
+                   begin
+                     include(fieldvs.varoptions,vo_is_first_field);
+                     is_first_field:=false;
+                   end;
+{$endif support_llvm}
                   fieldvs.vardef:=casetype;
                   recst.addfield(fieldvs);
                 end;
@@ -1469,7 +1492,7 @@ implementation
 {$if defined(powerpc) or defined(powerpc64)}
               { parent inherits the alignment padding if the variant is the first "field" of the parent record/variant }
               if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and
-                 is_first_field and
+                 is_first_type and
                  (recst.usefieldalignment=C_alignment) and
                  (maxpadalign>recst.padalignment) then
                 recst.padalignment:=maxpadalign;
@@ -1503,7 +1526,7 @@ implementation
          { free the list }
          sc.free;
 {$ifdef powerpc}
-         is_first_field := false;
+         is_first_type := false;
 {$endif powerpc}
       end;
 

+ 30 - 0
compiler/pmodules.pas

@@ -49,6 +49,9 @@ implementation
        { fix me! }
        ,cpubase
 {$endif i386}
+{$ifdef support_llvm}
+       ,llvmdef
+{$endif support_llvm}
        ;
 
 
@@ -1197,6 +1200,15 @@ implementation
          if (cs_debuginfo in current_settings.moduleswitches) then
            current_debuginfo.inserttypeinfo;
 
+{$ifdef support_llvm}
+         { insert llvm type info }
+         with tllvmdefinfo.create do
+           begin
+             inserttypeinfo;
+             free;
+           end;
+{$endif support_llvm}
+
          { generate imports }
          if current_module.ImportLibraryList.Count>0 then
            importlib.generatelib;
@@ -1740,6 +1752,15 @@ implementation
          if (cs_debuginfo in current_settings.moduleswitches) then
            current_debuginfo.inserttypeinfo;
 
+{$ifdef support_llvm}
+         { insert llvm type info }
+         with tllvmdefinfo.create do
+           begin
+             inserttypeinfo;
+             free;
+           end;
+{$endif support_llvm}
+
          exportlib.generatelib;
 
          { write all our exports to the import library,
@@ -2108,6 +2129,15 @@ implementation
          if (cs_debuginfo in current_settings.moduleswitches) then
            current_debuginfo.inserttypeinfo;
 
+{$ifdef support_llvm}
+         { insert llvm type info }
+         with tllvmdefinfo.create do
+           begin
+             inserttypeinfo;
+             free;
+           end;
+{$endif support_llvm}
+
          if islibrary or (target_info.system in system_unit_program_exports) then
            exportlib.generatelib;
 

+ 2 - 1
compiler/symconst.pas

@@ -350,7 +350,8 @@ type
     vo_is_typed_const,
     vo_is_range_check,
     vo_is_overflow_check,
-    vo_is_typinfo_para
+    vo_is_typinfo_para,
+    vo_is_first_field   { first field of a record or variant part of a record }
   );
   tvaroptions=set of tvaroption;
 

+ 87 - 0
compiler/symdef.pas

@@ -77,12 +77,21 @@ interface
           function  is_publishable : boolean;override;
           function  needs_inittable : boolean;override;
           function  rtti_mangledname(rt:trttitype):string;override;
+{$ifdef support_llvm}
+          function  llvm_mangledname:string;override;
+{$endif support_llvm}
           { regvars }
           function is_intregable : boolean;
           function is_fpuregable : boolean;
           { generics }
           procedure initgeneric;
        private
+{$ifdef support_llvm}
+          procedure set_llvm_name_syms;
+          function get_llvm_name_sym: tasmsymbol;override;
+          function get_llvm_pointer_name_sym: tasmsymbol;override;
+          function get_llvm_class_struct_name_sym: tasmsymbol;override;
+{$endif support_llvm}
           savesize  : aint;
        end;
 
@@ -103,6 +112,9 @@ interface
           function  GetTypeName:string;override;
           function  getmangledparaname:string;override;
           procedure setsize;
+{$ifdef support_llvm}
+          function  llvm_mangledname:string;override;
+{$endif support_llvm}
        end;
 
        tvariantdef = class(tstoreddef)
@@ -116,6 +128,9 @@ interface
           procedure setsize;
           function is_publishable : boolean;override;
           function needs_inittable : boolean;override;
+{$ifdef support_llvm}
+          function  llvm_mangledname:string;override;
+{$endif support_llvm}
        end;
 
        tformaldef = class(tstoreddef)
@@ -166,6 +181,9 @@ interface
           constructor ppuload(ppufile:tcompilerppufile);
           procedure ppuwrite(ppufile:tcompilerppufile);override;
           function  GetTypeName:string;override;
+{$ifdef support_llvm}
+          function  llvm_mangledname:string;override;
+{$endif support_llvm}
        end;
 
        tabstractrecorddef= class(tstoreddef)
@@ -945,6 +963,19 @@ implementation
       end;
 
 
+{$ifdef support_llvm}
+    function Tstoreddef.llvm_mangledname:string;
+      begin
+        if assigned(typesym) and
+           (owner.symtabletype in [staticsymtable,globalsymtable]) then
+          result:=make_mangledname('llvm',owner,typesym.name)
+        else
+          result:=make_mangledname('llvm',findunitsymtable(owner),'DEF'+tostr(DefId));
+        result:='%'+result;
+      end;
+{$endif support_llvm}
+
+
     procedure Tstoreddef.reset;
       begin
       end;
@@ -1100,6 +1131,40 @@ implementation
      end;
 
 
+{$ifdef support_llvm}
+    procedure tstoreddef.set_llvm_name_syms;
+      begin
+        if not assigned(fllvm_name_sym) then
+          begin
+            fllvm_name_sym:=current_asmdata.DefineAsmSymbol(llvm_mangledname,AB_LOCAL,AT_DATA);
+            if is_class_or_interface_or_dispinterface(self) then
+              fllvm_class_struct_name_sym:=current_asmdata.DefineAsmSymbol(llvm_mangledname+'$$$struct',AB_LOCAL,AT_DATA);
+          end;
+      end;
+
+
+    function tstoreddef.get_llvm_name_sym: tasmsymbol;
+      begin
+        set_llvm_name_syms;
+        result:=fllvm_name_sym;
+      end;
+
+
+    function tstoreddef.get_llvm_pointer_name_sym: tasmsymbol;
+      begin
+        set_llvm_name_syms;
+        result:=fllvm_pointer_name_sym;
+      end;
+
+
+    function tstoreddef.get_llvm_class_struct_name_sym: tasmsymbol;
+      begin
+        set_llvm_name_syms;
+        result:=fllvm_class_struct_name_sym;
+      end;
+{$endif support_llvm}
+
+
 {****************************************************************************
                                Tstringdef
 ****************************************************************************}
@@ -1833,6 +1898,13 @@ implementation
       end;
 
 
+{$ifdef support_llvm}
+    function tfiledef.llvm_mangledname:string;
+      begin
+        result:='< ['+ tostr(savesize div 4) + 'x i32] >';
+      end;
+{$endif support_llvm}
+
 {****************************************************************************
                                TVARIANTDEF
 ****************************************************************************}
@@ -1906,6 +1978,13 @@ implementation
       end;
 
 
+{$ifdef support_llvm}
+    function tvariantdef.llvm_mangledname:string;
+      begin
+        result:=search_system_type('TVARDATA').typedef.llvm_mangledname;
+      end;
+{$endif support_llvm}
+
 {****************************************************************************
                             TABSTRACtpointerdef
 ****************************************************************************}
@@ -1997,6 +2076,14 @@ implementation
       end;
 
 
+{$ifdef support_llvm}
+    function tpointerdef.llvm_mangledname:string;
+      begin
+        result:=pointeddef.llvm_mangledname+'*';
+      end;
+{$endif support_llvm}
+
+
 {****************************************************************************
                               TCLASSREFDEF
 ****************************************************************************}

+ 10 - 1
compiler/symsym.pas

@@ -151,7 +151,16 @@ interface
       end;
 
       tfieldvarsym = class(tabstractvarsym)
-          fieldoffset   : aint;   { offset in record/object }
+          fieldoffset         : aint;   { offset in record/object }
+{$ifdef support_llvm}
+          { the llvm version of the record does not support variants,   }
+          { so the llvm equivalent field may not be at the exact same   }
+          { offset -> store the difference (bits for bitpacked records, }
+          { bytes otherwise)                                            }
+          offsetfromllvmfield : aint;
+          { number of the closest field in the llvm definition }
+          llvmfieldnr         : longint;
+{$endif support_llvm}
           constructor create(const n : string;vsp:tvarspez;def:tdef;vopts:tvaroptions);
           constructor ppuload(ppufile:tcompilerppufile);
           procedure ppuwrite(ppufile:tcompilerppufile);override;

+ 316 - 0
compiler/symtable.pas

@@ -76,13 +76,31 @@ interface
           procedure testfordefaultproperty(sym:TObject;arg:pointer);
        end;
 
+{$ifdef support_llvm}
+       tllvmshadowsymtableentry = class
+         constructor create(def: tdef; fieldoffset: aint);
+        private
+         ffieldoffset: aint;
+         fdef: tdef;
+        public
+         property fieldoffset: aint read ffieldoffset;
+         property def: tdef read fdef;
+       end;
+
+       tllvmshadowsymtable = class;
+{$endif support_llvm}       
+
        tabstractrecordsymtable = class(tstoredsymtable)
        public
           usefieldalignment,     { alignment to use for fields (PACKRECORDS value), C_alignment is C style }
           recordalignment,       { alignment desired when inserting this record }
           fieldalignment,        { alignment current alignment used when fields are inserted }
           padalignment : shortint;   { size to a multiple of which the symtable has to be rounded up }
+{$ifdef support_llvm}
+          llvmst: tllvmshadowsymtable;
+{$endif}
           constructor create(const n:string;usealign:shortint);
+          destructor destroy; override;
           procedure ppuload(ppufile:tcompilerppufile);override;
           procedure ppuwrite(ppufile:tcompilerppufile);override;
           procedure alignrecord(fieldoffset:aint;varalign:shortint);
@@ -114,6 +132,31 @@ interface
           function  checkduplicate(var hashedid:THashedIDString;sym:TSymEntry):boolean;override;
        end;
 
+{$ifdef support_llvm}
+       { llvm record definitions cannot contain variant/union parts, }
+       { you have to flatten them first. the tllvmshadowsymtable     }
+       { contains a flattened version of a record/object symtable    }
+       tllvmshadowsymtable = class
+        private
+         equivst: tabstractrecordsymtable;
+         curroffset: aint;
+        public
+         symdeflist: TFPObjectList;
+
+         constructor create(st: tabstractrecordsymtable);
+         destructor destroy; override;
+        private
+         // generate the table
+         procedure generate;
+         // helpers
+         procedure appendsymdef(sym:tfieldvarsym);
+         procedure findvariantstarts(item: TObject; arg: pointer);
+         procedure addalignmentpadding(finalsize: aint);
+         procedure buildmapping(variantstarts: tfplist);
+         procedure buildtable(variantstarts: tfplist);
+       end;
+{$endif support_llvm}
+
        { tabstractlocalsymtable }
 
        tabstractlocalsymtable = class(tstoredsymtable)
@@ -745,6 +788,15 @@ implementation
       end;
 
 
+    destructor tabstractrecordsymtable.destroy;
+      begin
+{$ifdef support_llvm}
+        llvmst.free;
+{$endif suppor_llvm}
+        inherited destroy;
+      end;
+    
+    
     procedure tabstractrecordsymtable.ppuload(ppufile:tcompilerppufile);
       begin
         inherited ppuload(ppufile);
@@ -1121,6 +1173,270 @@ implementation
       end;
 
 
+
+{$ifdef support_llvm}
+
+{****************************************************************************
+                              tLlvmShadowSymtableEntry
+****************************************************************************}
+
+    constructor tllvmshadowsymtableentry.create(def: tdef; fieldoffset: aint);
+      begin
+        fdef:=def;
+        ffieldoffset:=fieldoffset;
+      end;
+
+
+{****************************************************************************
+                              TLlvmShadowSymtable
+****************************************************************************}
+
+    constructor tllvmshadowsymtable.create(st: tabstractrecordsymtable);
+      begin
+        equivst:=st;
+        curroffset:=0;
+        symdeflist:=tfpobjectlist.create(false);
+        generate;
+      end;
+      
+
+    destructor tllvmshadowsymtable.destroy;
+      begin
+        symdeflist.free;
+      end;
+
+
+    procedure tllvmshadowsymtable.appendsymdef(sym:tfieldvarsym);
+      var
+        sizectr,
+        tmpsize: aint;
+      begin
+        case equivst.usefieldalignment of
+          C_alignment:
+            { default for llvm, don't add explicit padding }
+            symdeflist.add(tllvmshadowsymtableentry.create(sym.vardef,sym.fieldoffset));
+          bit_alignment:
+            begin
+              { curoffset: bit address after the previous field.      }
+              { llvm has no special support for bitfields in records, }
+              { so we replace them with plain bytes.                  }
+              { as soon as a single bit of a byte is allocated, we    }
+              { allocate the byte in the llvm shadow record           }
+              if (sym.fieldoffset>curroffset) then
+                curroffset:=align(curroffset,8);
+              { fields in bitpacked records always start either right }
+              { after the previous one, or at the next byte boundary. }
+              if (curroffset<>sym.fieldoffset) then
+                internalerror(2008051002);
+              if is_ordinal(sym.vardef) and
+                 (sym.getpackedbitsize mod 8 <> 0) then
+                begin
+                  tmpsize:=sym.getpackedbitsize;
+                  sizectr:=tmpsize+7;
+                  repeat
+                    symdeflist.add(tllvmshadowsymtableentry.create(u8inttype,sym.fieldoffset+(tmpsize+7)-sizectr));
+                    dec(sizectr,8);
+                  until (sizectr<=0);
+                  inc(curroffset,tmpsize);
+                end
+              else
+                begin
+                   symdeflist.add(tllvmshadowsymtableentry.create(sym.vardef,sym.fieldoffset));
+                  inc(curroffset,sym.vardef.size*8);
+                end;
+            end
+          else
+            begin
+              { curoffset: address right after the previous field }
+              while (sym.fieldoffset>curroffset) do
+                begin
+                  symdeflist.add(tllvmshadowsymtableentry.create(s8inttype,curroffset));
+                  inc(curroffset);
+                end;
+              symdeflist.add(tllvmshadowsymtableentry.create(sym.vardef,sym.fieldoffset));
+              inc(curroffset,sym.vardef.size);
+            end
+        end
+      end;
+
+
+    procedure tllvmshadowsymtable.addalignmentpadding(finalsize: aint);
+      begin
+        case equivst.usefieldalignment of
+          { already correct in this case }
+          bit_alignment,
+          { handled by llvm }
+          C_alignment:
+            ;
+          else
+            begin
+              { add padding fields }
+              while (finalsize>curroffset) do
+                begin
+                  symdeflist.add(tllvmshadowsymtableentry.create(s8inttype,curroffset));
+                  inc(curroffset);
+                end;
+            end;
+        end;
+      end;
+
+
+    procedure tllvmshadowsymtable.findvariantstarts(item: TObject; arg: pointer);
+      var
+        variantstarts: tfplist absolute arg;
+        sym: tfieldvarsym absolute item;
+        lastoffset: aint;
+        newalignment: aint;
+      begin
+        if (tsym(item).typ<>fieldvarsym) then
+          exit;
+        { a "better" algorithm might be to use the largest }
+        { variant in case of (bit)packing, since then      }
+        { alignment doesn't matter                         }
+        if (vo_is_first_field in sym.varoptions) then
+          begin
+            { we assume that all fields are processed in order. }
+            { the most deeply nested variant always comes last  }
+            { in Pascal                                         }
+            if (variantstarts.count<>0) then
+              lastoffset:=tfieldvarsym(variantstarts[variantstarts.count-1]).fieldoffset
+            else
+              lastoffset:=-1;
+
+            if (lastoffset=sym.fieldoffset) then
+              begin
+                if (equivst.fieldalignment<>bit_alignment) then
+                  newalignment:=used_align(sym.vardef.alignment,current_settings.alignment.recordalignmin,equivst.fieldalignment)
+                else
+                  newalignment:=1;
+                if (newalignment>tfieldvarsym(variantstarts[variantstarts.count-1]).vardef.alignment) then
+                  tfieldvarsym(variantstarts[variantstarts.count-1]):=sym
+              end
+            else if (lastoffset<sym.fieldoffset) then
+              variantstarts.add(sym)
+            else
+              internalerror(2008051003);
+          end;
+      end;
+
+
+    procedure tllvmshadowsymtable.buildtable(variantstarts: tfplist);
+      var
+        lastvaroffsetprocessed: aint;
+        i, equivcount, varcount: longint;
+      begin
+        { if it's an object/class, the first entry is the parent (if there is one) }
+        if (equivst.symtabletype=objectsymtable) and
+           assigned(tobjectdef(equivst.defowner).childof) then
+          symdeflist.add(tllvmshadowsymtableentry.create(tobjectdef(equivst.defowner).childof,0));
+        equivcount:=equivst.symlist.count;
+        varcount:=0;
+        i:=0;
+        lastvaroffsetprocessed:=-1;
+        while (i<equivcount) do
+          begin
+            if (tsym(equivst.symlist[i]).typ<>fieldvarsym) then
+              begin
+                inc(i);
+                continue;
+              end;
+            { start of a new variant? }
+            if (vo_is_first_field in tfieldvarsym(equivst.symlist[i]).varoptions) then
+              begin
+                { if we want to process the same variant offset twice, it means that we  }
+                { got to the end and are trying to process the next variant part -> stop }
+                if (tfieldvarsym(equivst.symlist[i]).fieldoffset=lastvaroffsetprocessed) then
+                  break;
+                if (varcount>=variantstarts.count) or
+                   (tfieldvarsym(equivst.symlist[i]).fieldoffset<>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                  internalerror(2008051005);
+                { new variant part -> use the one with the biggest alignment }
+                i:=equivst.symlist.indexof(tobject(variantstarts[varcount]));
+                lastvaroffsetprocessed:=tfieldvarsym(equivst.symlist[i]).fieldoffset;
+                inc(varcount);
+                if (i<0) then
+                  internalerror(2008051004);
+              end;
+            appendsymdef(tfieldvarsym(equivst.symlist[i]));
+            inc(i);
+          end;
+        addalignmentpadding(equivst.datasize);
+      end;
+
+
+    procedure tllvmshadowsymtable.buildmapping(variantstarts: tfplist);
+      var
+        i, varcount: longint;
+        shadowindex: longint;
+        equivcount : longint;
+      begin
+        varcount:=0;
+        shadowindex:=0;
+        equivcount:=equivst.symlist.count;
+        i:=0;
+        while (i < equivcount) do
+          begin
+            if (tsym(equivst.symlist[i]).typ<>fieldvarsym) then
+              begin
+                inc(i);
+                continue;
+              end;
+            { start of a new variant? }
+            if (vo_is_first_field in tfieldvarsym(equivst.symlist[i]).varoptions) then
+              begin
+                { the variant can either come after the current one, or }
+                { be at the same level                                  }
+                if (tfieldvarsym(equivst.symlist[i]).fieldoffset<tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                  dec(varcount);
+                if (tfieldvarsym(equivst.symlist[i]).fieldoffset<>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                  internalerror(2008051006);
+                { reset the shadowindex to the start of this variant. }
+                { in case the llvmfieldnr is not (yet) set for this   }
+                { field, shadowindex will simply be reset to zero and }
+                { we'll start searching from the start of the record  }
+                shadowindex:=tfieldvarsym(variantstarts[varcount]).llvmfieldnr;
+                if (varcount<pred(variantstarts.count)) then
+                  inc(varcount);
+              end;
+
+            { find the last shadowfield whose offset <= the current field's offset }
+            while (tllvmshadowsymtableentry(symdeflist[shadowindex]).fieldoffset<tfieldvarsym(equivst.symlist[i]).fieldoffset) and
+                  (shadowindex<symdeflist.count-1) and
+                  (tllvmshadowsymtableentry(symdeflist[shadowindex+1]).fieldoffset>=tfieldvarsym(equivst.symlist[i]).fieldoffset) do
+              inc(shadowindex);
+            { set the field number and potential offset from that field (in case }
+            { of overlapping variants)                                           }
+            tfieldvarsym(equivst.symlist[i]).llvmfieldnr:=shadowindex;
+            tfieldvarsym(equivst.symlist[i]).offsetfromllvmfield:=
+              tfieldvarsym(equivst.symlist[i]).fieldoffset-tllvmshadowsymtableentry(symdeflist[shadowindex]).fieldoffset;
+            inc(i);
+          end;
+      end;
+
+
+    procedure tllvmshadowsymtable.generate;
+      var
+        variantstarts: tfplist;
+      begin
+        variantstarts:=tfplist.create;
+
+        { first go through the entire record and }
+        { store the fieldvarsyms of the variants }
+        { with the highest alignment             }
+        equivst.symlist.foreachcall(@findvariantstarts,pointer(variantstarts));
+
+        { now go through the regular fields and the selected variants, }
+        { and add them to the  llvm shadow record symtable             }
+        buildtable(variantstarts);
+        
+        { finally map all original fields to the llvm definition }
+        buildmapping(variantstarts);
+
+        variantstarts.free;        
+      end;
+
+{$endif support_llvm}
+
 {****************************************************************************
                           TAbstractLocalSymtable
 ****************************************************************************}

+ 21 - 0
compiler/symtype.pas

@@ -62,6 +62,14 @@ interface
          dbg_state   : tdefdbgstatus;
          defoptions  : tdefoptions;
          defstates   : tdefstates;
+{$ifdef support_llvm}
+        protected
+         fllvm_name_sym,
+         { so we don't have to create pointerdefs all the time }
+         fllvm_pointer_name_sym,
+         fllvm_class_struct_name_sym : tasmsymbol;
+        public
+{$endif support_llvm}
          constructor create(dt:tdeftyp);
          procedure buildderef;virtual;abstract;
          procedure buildderefimpl;virtual;abstract;
@@ -72,6 +80,9 @@ interface
          function  mangledparaname:string;
          function  getmangledparaname:string;virtual;
          function  rtti_mangledname(rt:trttitype):string;virtual;abstract;
+{$ifdef support_llvm}
+         function  llvm_mangledname:string;virtual;abstract;
+{$endif support_llvm}
          function  size:aint;virtual;abstract;
          function  packedbitsize:aint;virtual;
          function  alignment:shortint;virtual;abstract;
@@ -82,6 +93,16 @@ interface
          function  needs_inittable:boolean;virtual;abstract;
          function  is_related(def:tdef):boolean;virtual;
          procedure ChangeOwner(st:TSymtable);
+{$ifdef support_llvm}
+        protected
+         function get_llvm_name_sym: tasmsymbol;virtual;abstract;
+         function get_llvm_pointer_name_sym: tasmsymbol;virtual;abstract;
+         function get_llvm_class_struct_name_sym: tasmsymbol;virtual;abstract;
+        public
+         property llvm_name_sym: tasmsymbol read get_llvm_name_sym;
+         property llvm_pointername_sym: tasmsymbol read get_llvm_pointer_name_sym;
+         property llvm_class_struct_name_sym: tasmsymbol read get_llvm_class_struct_name_sym;
+{$endif support_llvm}
       end;
 
 {************************************************