/* APPLE LOCAL begin LLVM (ENTIRE FILE!)  */
/* High-level LLVM backend interface 
Copyright (C) 2005 Free Software Foundation, Inc.
Contributed by Jim Laskey (jlaskey@apple.com)

This file is part of GCC.

GCC 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, or (at your option) any later
version.

GCC 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 GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

//===----------------------------------------------------------------------===//
// This is a C++ source file that implements the debug information gathering.
//===----------------------------------------------------------------------===//

#include "llvm-debug.h"

#include "llvm-abi.h"
#include "llvm-internal.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineModuleInfo.h"

#include <iostream>

extern "C" {
#include "langhooks.h"
#include "toplev.h"
#include "tree.h"
#include "version.h"
}

using namespace llvm;
using namespace llvm::dwarf;

#ifndef LLVMTESTDEBUG
#define DEBUGASSERT(S) ((void)0)
#else
#define DEBUGASSERT(S) assert(S)
#endif


/// DirectoryAndFile - Extract the directory and file name from a path.  If no
/// directory is specified, then use the source working directory.
static void DirectoryAndFile(const std::string &FullPath,
                             std::string &Directory, std::string &FileName) {
  // Look for the directory slash.
  size_t Slash = FullPath.rfind('/');
  
  // If no slash
  if (Slash == std::string::npos) {
    // The entire path is the file name.
    Directory = "";
    FileName = FullPath;
  } else {
    // Separate the directory from the file name.
    Directory = FullPath.substr(0, Slash);
    FileName = FullPath.substr(Slash + 1);
  }
  
  // If no directory present then use source working directory.
  if (Directory.empty() || Directory[0] != '/') {
    Directory = std::string(get_src_pwd()) + "/" + Directory;
  }
}

/// NodeSizeInBits - Returns the size in bits stored in a tree node regardless
/// of whether the node is a TYPE or DECL.
static uint64_t NodeSizeInBits(tree Node) {
  if (TREE_CODE(Node) == ERROR_MARK) {
    return BITS_PER_WORD;
  } else if (TYPE_P(Node)) {
    if (TYPE_SIZE(Node) == NULL_TREE)
      return 0;
    else if (host_integerp (TYPE_SIZE(Node), 1))
      return tree_low_cst (TYPE_SIZE(Node), 1);
    else
      return TYPE_ALIGN(Node);
  } else if (DECL_P(Node)) {
    if (DECL_SIZE(Node) == NULL_TREE)
      return 0;
    else if (host_integerp (DECL_SIZE(Node), 1))
      return tree_low_cst (DECL_SIZE(Node), 1);
    else
      return DECL_ALIGN(Node);
  }
  
  return 0;
}

/// NodeAlignInBits - Returns the alignment in bits stored in a tree node
/// regardless of whether the node is a TYPE or DECL.
static uint64_t NodeAlignInBits(tree Node) {
  if (TREE_CODE(Node) == ERROR_MARK) return BITS_PER_WORD;
  if (TYPE_P(Node)) return TYPE_ALIGN(Node);
  if (DECL_P(Node)) return DECL_ALIGN(Node);
  return BITS_PER_WORD;
}

/// FieldType - Returns the type node of a structure member field.
///
static tree FieldType(tree Field) {
  if (TREE_CODE (Field) == ERROR_MARK) return integer_type_node;

  tree type = DECL_BIT_FIELD_TYPE (Field);
  if (type == NULL_TREE)
    type = TREE_TYPE (Field);

  return type;
}

/// GetNodeName - Returns the name stored in a node regardless of whether the
/// node is a TYPE or DECL.
static const char *GetNodeName(tree Node) {
  tree Name = NULL;
  
  if (DECL_P(Node)) {
    Name = DECL_NAME(Node);
  } else if (TYPE_P(Node)) {
    Name = TYPE_NAME(Node);
  }

  if (Name) {
    if (TREE_CODE(Name) == IDENTIFIER_NODE) {
      return IDENTIFIER_POINTER(Name);
    } else if (TREE_CODE(Name) == TYPE_DECL && !DECL_IGNORED_P(Name)) {
      return IDENTIFIER_POINTER(DECL_NAME(Name));
    }
  }
  
  return "";
}

/// GetNodeLocation - Returns the location stored in a node  regardless of
/// whether the node is a TYPE or DECL.  UseStub is true if we should consider
/// the type stub as the actually location (ignored in struct/unions/enums.)
static expanded_location GetNodeLocation(tree Node, bool UseStub = true) {
  expanded_location Location = { NULL, 0 };

  tree Name = NULL;
  
  if (DECL_P(Node)) {
    Name = DECL_NAME(Node);
  } else if (TYPE_P(Node)) {
    Name = TYPE_NAME(Node);
  }
  
  if (Name) {
    if (TYPE_STUB_DECL(Name)) {
      tree Stub = TYPE_STUB_DECL(Name);
      Location = expand_location(DECL_SOURCE_LOCATION(Stub));
    } else if (DECL_P(Name)) {
      Location = expand_location(DECL_SOURCE_LOCATION(Name));
    }
  }
  
  if (!Location.line) {
    if (UseStub && TYPE_STUB_DECL(Node)) {
      tree Stub = TYPE_STUB_DECL(Node);
      Location = expand_location(DECL_SOURCE_LOCATION(Stub));
    } else if (DECL_P(Node)) {
      Location = expand_location(DECL_SOURCE_LOCATION(Node));
    }
  }
  
  return Location;
}

/// GetGlobalNames - Sets the names for a global descriptor.
///
static void GetGlobalNames(tree Node, GlobalDesc *Global) {
  tree decl_name = DECL_NAME(Node);
  if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) {
    Global->setName(lang_hooks.decl_printable_name (Node, 0));
    Global->setFullName(lang_hooks.decl_printable_name (Node, 1));
    
    if (TREE_PUBLIC(Node) &&
        DECL_ASSEMBLER_NAME(Node) != DECL_NAME(Node) && 
        !DECL_ABSTRACT(Node)) {
        Global->setLinkageName(IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(Node)));
    }
  }
}  

DebugInfo::DebugInfo(Module *m)
: M(m)
, SR()
, CurFullPath("")
, CurLineNo(0)
, PrevFullPath("")
, PrevLineNo(0)
, PrevBB(NULL)
, CompileUnitCache()
, StopPointFn(NULL)
, FuncStartFn(NULL)
, RegionStartFn(NULL)
, RegionEndFn(NULL)
, DeclareFn(NULL)
, CompileUnitAnchor(NULL)
, GlobalVariableAnchor(NULL)
, SubprogramAnchor(NULL)
, RegionStack()
, Subprogram(NULL)
{
  // uint64_t and int64_t are used in the debug descriptors for sizes and
  // offsets.  So, we should make sure we don't lose any accuracy. 
  DEBUGASSERT(sizeof(HOST_WIDE_INT) <= sizeof(int64_t) &&
              "Bit size exceeds values stored in debug descriptors");
         
  // Let the debug serializer know where the module lives.
  SR.setModule(M);
}

/// getValueFor - Return a llvm representation for a given debug information
/// descriptor.
Value *DebugInfo::getValueFor(DebugInfoDesc *DD) {
  return SR.Serialize(DD);
}

/// getCastValueFor - Return a llvm representation for a given debug information
/// descriptor cast to an empty struct pointer.
Value *DebugInfo::getCastValueFor(DebugInfoDesc *DD) {
  return ConstantExpr::getBitCast(SR.Serialize(DD), SR.getEmptyStructPtrType());
}

/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start."
void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn,
                                  BasicBlock *CurBB) {
  PrevFullPath = "";
  PrevLineNo = 0;
  PrevBB = NULL;
  
  // Create subprogram descriptor.
  Subprogram = new SubprogramDesc();
  
  // Make sure we have an anchor.
  if (!SubprogramAnchor) {
    SubprogramAnchor = new AnchorDesc(Subprogram);
  }

  // Get name information.
  GetGlobalNames(FnDecl, Subprogram);
  
  // Gather location information.
  CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath);
  
  // Get function type.
  TypeDesc *SPTy = getOrCreateType(TREE_TYPE(TREE_TYPE(FnDecl)), Unit);

  Subprogram->setAnchor(SubprogramAnchor);
  Subprogram->setContext(Unit);
  Subprogram->setFile(Unit);
  Subprogram->setLine(CurLineNo);
  Subprogram->setType(SPTy);
  Subprogram->setIsStatic(Fn->hasInternalLinkage());
  Subprogram->setIsDefinition(true);
  
  // Lazily construct llvm.dbg.func.start.
  if (!FuncStartFn)
    FuncStartFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_func_start);

  // Call llvm.dbg.func.start.
  new CallInst(FuncStartFn, getCastValueFor(Subprogram), "", CurBB);
  
  // Provide an entry stop point.
  EmitStopPoint(Fn, CurBB);
  
  // Push function on region stack.
  RegionStack.push_back(Subprogram);
}

/// EmitRegionStart- Constructs the debug code for entering a declarative
/// region - "llvm.dbg.region.start."
void DebugInfo::EmitRegionStart(Function *Fn, BasicBlock *CurBB) {
  BlockDesc *Block = new BlockDesc();
  Block->setContext(RegionStack.back());
  RegionStack.push_back(Block);

  // Lazily construct llvm.dbg.region.start function.
  if (!RegionStartFn)
    RegionStartFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_region_start);
  
  // Call llvm.dbg.func.start.
  new CallInst(RegionStartFn, getCastValueFor(Block), "", CurBB);
}

/// EmitRegionEnd - Constructs the debug code for exiting a declarative
/// region - "llvm.dbg.region.end."
void DebugInfo::EmitRegionEnd(Function *Fn, BasicBlock *CurBB) {
  // Lazily construct llvm.dbg.region.end function.
  if (!RegionEndFn)
    RegionEndFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_region_end);
  
  // Provide an region stop point.
  EmitStopPoint(Fn, CurBB);
  
  // Call llvm.dbg.func.end.
  new CallInst(RegionEndFn, getCastValueFor(RegionStack.back()), "", CurBB);
  RegionStack.pop_back();
}

/// EmitDeclare - Constructs the debug code for allocation of a new variable.
/// region - "llvm.dbg.declare."
void DebugInfo::EmitDeclare(tree decl, unsigned Tag, const char *Name,
                            tree type, Value *AI, BasicBlock *CurBB) {
  // Lazily construct llvm.dbg.declare function.
  const PointerType *EmpPtr = SR.getEmptyStructPtrType();
  if (!DeclareFn)
    DeclareFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_declare);
  
  // Get type information.
  CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath);
  TypeDesc *TyDesc = getOrCreateType(type, Unit);

  expanded_location Loc = GetNodeLocation(decl, false);
  CompileUnitDesc *File = Loc.line ? getOrCreateCompileUnit(Loc.file) : NULL;
  
  // Construct variable.
  VariableDesc *Variable = new VariableDesc(Tag);
  Variable->setContext(RegionStack.back());
  Variable->setName(Name);
  Variable->setFile(File);
  Variable->setLine(Loc.line);
  Variable->setType(TyDesc);

  // Cast the AllocA result to a {}* for the call to llvm.dbg.declare. Since
  // only pointer types are involved, this is always a BitCast
  Value *AllocACast = new BitCastInst(AI, EmpPtr, Name, CurBB);

  // Call llvm.dbg.declare.
  SmallVector<Value *, 2> Args;
  Args.push_back(AllocACast);
  Args.push_back(getCastValueFor(Variable));
  new CallInst(DeclareFn, Args.begin(), Args.end(), "", CurBB);
}

/// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of 
/// source line - "llvm.dbg.stoppoint."
void DebugInfo::EmitStopPoint(Function *Fn, BasicBlock *CurBB) {
  // Don't bother if things are the same as last time.
  if (PrevLineNo == CurLineNo &&
      PrevBB == CurBB &&
      (PrevFullPath == CurFullPath ||
       !strcmp(PrevFullPath, CurFullPath))) return;
  if (!CurFullPath[0] || CurLineNo == 0) return;
  
  // Update last state.
  PrevFullPath = CurFullPath;
  PrevLineNo = CurLineNo;
  PrevBB = CurBB;
  
  // Get the appropriate compile unit.
  CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath);
  
  // Lazily construct llvm.dbg.stoppoint function.
  if (!StopPointFn)
    StopPointFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_stoppoint);
  
  // Invoke llvm.dbg.stoppoint
  Value *Args[3] = {
    ConstantInt::get(Type::Int32Ty, CurLineNo),
    ConstantInt::get(Type::Int32Ty, 0),
    getCastValueFor(Unit)
  };
  new CallInst(StopPointFn, Args, Args+3, "", CurBB);
}

/// EmitGlobalVariable - Emit information about a global variable.
///
void DebugInfo::EmitGlobalVariable(GlobalVariable *GV, tree decl) {
  // FIXME - lots to do here.
  // Create global variable debug descriptor.
  GlobalVariableDesc *Global = new GlobalVariableDesc();

  // Make sure we have an anchor.
  if (!GlobalVariableAnchor) {
    GlobalVariableAnchor = new AnchorDesc(Global);
  }
  
  // Get name information.
  GetGlobalNames(decl, Global);

  // Gather location information.
  expanded_location location = expand_location(DECL_SOURCE_LOCATION(decl));
  CompileUnitDesc *Unit = getOrCreateCompileUnit(location.file);
  
  TypeDesc *TyD = getOrCreateType(TREE_TYPE(decl), Unit);
  
  // Fill in the blanks.
  Global->setAnchor(GlobalVariableAnchor);
  Global->setContext(Unit);
  Global->setFile(Unit);
  Global->setLine(location.line);
  Global->setType(TyD);
  Global->setIsDefinition(true);
  Global->setIsStatic(GV->hasInternalLinkage());
  Global->setGlobalVariable(GV);
  
  // Make sure global is created if needed.
  getValueFor(Global);
}

/// AddTypeQualifiers - Add const/volatile qualifiers prior to the type
/// descriptor.
static TypeDesc *AddTypeQualifiers(tree_node *type, CompileUnitDesc *Unit,
                                   TypeDesc *TyDesc) {
  if (TYPE_READONLY(type)) {
    DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_const_type);
    DerivedTy->setContext(Unit);
    DerivedTy->setFromType(TyDesc);
    TyDesc = DerivedTy;
  }
  if (TYPE_VOLATILE(type)) {
    DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_volatile_type);
    DerivedTy->setContext(Unit);
    DerivedTy->setFromType(TyDesc);
    TyDesc = DerivedTy;
  }
  
  // FIXME - Add private/public/protected.
  
  return TyDesc;
}

/// getOrCreateType - Get the type from the cache or create a new type if
/// necessary.
/// FIXME - I hate jumbo methods - split up.
TypeDesc *DebugInfo::getOrCreateType(tree_node *type, CompileUnitDesc *Unit) {
  DEBUGASSERT(type != NULL_TREE && type != error_mark_node &&
              "Not a type.");
  if (type == NULL_TREE || type == error_mark_node) return NULL;
  
  // Should only be void if a pointer/reference/return type.  Returning NULL
  // allows the caller to produce a non-derived type.
  if (TREE_CODE(type) == VOID_TYPE) return NULL;
  
  // Check to see if the compile unit already has created this type.
  TypeDesc *&Slot = TypeCache[type];
  if (Slot) return Slot;
  
  // Ty will have contain the resulting type.
  TypeDesc *Ty = NULL;
  
  // Get the name and location early to assist debugging.
  const char *TypeName = GetNodeName(type);
  expanded_location Loc = GetNodeLocation(type);
  
  // Bit size, align and offset of the type.
  uint64_t Size = NodeSizeInBits(type);
  uint64_t Align = NodeAlignInBits(type);
  uint64_t Offset = 0;
  
  // Do we have a typedef?
  if (tree Name = TYPE_NAME(type)) {
    if (TREE_CODE(Name) == TYPE_DECL &&  DECL_ORIGINAL_TYPE(Name)) {
      // typedefs are derived from some other type.
      DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_typedef);
      // Set the slot early to prevent recursion difficulties.
      Slot = Ty = DerivedTy;
      // Handle derived type.
      TypeDesc *FromTy = getOrCreateType(DECL_ORIGINAL_TYPE(Name), Unit);
      DerivedTy->setFromType(FromTy);
      // typedefs size should be fetched from the derived type.
      Size = Align = 0;
    }
  }
  
  // If no result so far.
  if (!Ty) {
    // Work out details of type.
    switch (TREE_CODE(type)) {
    case FILE_TYPE:
    case ERROR_MARK:
    case LANG_TYPE:
    default: {
      DEBUGASSERT(0 && "Unsupported type");
      return NULL;
    }

    case POINTER_TYPE:
    case REFERENCE_TYPE: {
      // type* and type&
      unsigned T = TREE_CODE(type) == POINTER_TYPE ? DW_TAG_pointer_type :
                                                     DW_TAG_reference_type;
      DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(T);
      Ty = DerivedTy;
      // Set the slot early to prevent recursion difficulties.
      // Any other use of the type should include the qualifiers.
      Slot = AddTypeQualifiers(type, Unit, DerivedTy);
      // Handle the derived type.
      TypeDesc *FromTy = getOrCreateType(TREE_TYPE(type), Unit);
      DerivedTy->setFromType(FromTy);
      break;
    }
    
    case OFFSET_TYPE: {
      // gen_type_die(TYPE_OFFSET_BASETYPE(type), context_die);
      
      // gen_type_die(TREE_TYPE(type), context_die);
      
      // gen_ptr_to_mbr_type_die(type, context_die);
      break;
    }

    case FUNCTION_TYPE:
    case METHOD_TYPE: {
      CompositeTypeDesc *SubrTy = new CompositeTypeDesc(DW_TAG_subroutine_type);
      Ty = SubrTy;
      // Set the slot early to prevent recursion difficulties.
      // Any other use of the type should include the qualifiers.
      Slot = AddTypeQualifiers(type, Unit, SubrTy);
      
      // Prepare to add the arguments for the subroutine.
      std::vector<DebugInfoDesc *> &Elements = SubrTy->getElements();
      // Get result type.
      TypeDesc *ArgTy = getOrCreateType(TREE_TYPE(type), Unit);
      Elements.push_back(ArgTy);

      // Set up remainder of arguments.
      for (tree arg = TYPE_ARG_TYPES(type); arg; arg = TREE_CHAIN(arg)) {
        tree formal_type = TREE_VALUE(arg);
        
        if (formal_type == void_type_node) break;
        
        ArgTy = getOrCreateType(formal_type, Unit);
        Elements.push_back(ArgTy);
      }
      
      break;
    }
      
    case VECTOR_TYPE:
    case ARRAY_TYPE: {
      // type[n][m]...[p]
      if (TYPE_STRING_FLAG(type) && TREE_CODE(TREE_TYPE(type)) == CHAR_TYPE) {
        DEBUGASSERT(0 && "Don't support pascal strings");
        return NULL;
      }
      
      CompositeTypeDesc *ArrayTy;
      
      if (TREE_CODE(type) == VECTOR_TYPE) {
        Ty = ArrayTy = new CompositeTypeDesc(DW_TAG_vector_type);
        // Set the slot early to prevent recursion difficulties.
        // Any other use of the type should include the qualifiers.
        Slot = AddTypeQualifiers(type, Unit, ArrayTy);
        // Use the element type of the from this point.
        type = TREE_TYPE(TYPE_FIELDS(TYPE_DEBUG_REPRESENTATION_TYPE(type)));
      } else {
        Ty = ArrayTy = new CompositeTypeDesc(DW_TAG_array_type);
        // Set the slot early to prevent recursion difficulties.
        // Any other use of the type should include the qualifiers.
        Slot = AddTypeQualifiers(type, Unit, ArrayTy);
      }

      // Prepare to add the dimensions of the array.
      std::vector<DebugInfoDesc *> &Elements = ArrayTy->getElements();

      // There will be ARRAY_TYPE nodes for each rank.  Followed by the derived
      // type.
      for (; TREE_CODE(type) == ARRAY_TYPE; type = TREE_TYPE(type)) {
        tree Domain = TYPE_DOMAIN(type);
        SubrangeDesc *Subrange = new SubrangeDesc();

        if (Domain) {
          // FIXME - handle dynamic ranges
          tree MinValue = TYPE_MIN_VALUE(Domain);
          tree MaxValue = TYPE_MAX_VALUE(Domain);
          if (MinValue && MaxValue &&
              host_integerp(MinValue, 0) &&
              host_integerp(MaxValue, 0)) {
            Subrange->setLo(tree_low_cst(MinValue, 0));
            Subrange->setHi(tree_low_cst(MaxValue, 0));
          }
        }
        
        Elements.push_back(Subrange);
      }
      
      // Now handle the derived type.
      ArrayTy->setFromType(getOrCreateType(type, Unit));
      break;
    }
    
    case ENUMERAL_TYPE: {
      // enum { a, b, ..., z };
      CompositeTypeDesc *Enum = new CompositeTypeDesc(DW_TAG_enumeration_type);
      Ty = Enum;
      // Any other use of the type should include the qualifiers.
      Slot = AddTypeQualifiers(type, Unit, Enum);
      // Prepare to add the enumeration values.
      std::vector<DebugInfoDesc *> &Elements = Enum->getElements();

      if (TYPE_SIZE(type)) {
        for (tree Link = TYPE_VALUES(type); Link; Link = TREE_CHAIN(Link)) {
          EnumeratorDesc *EnumDesc = new EnumeratorDesc();

          tree EnumValue = TREE_VALUE(Link);
          int64_t Value = tree_low_cst(EnumValue,
                                       tree_int_cst_sgn(EnumValue) > 0);
          const char *EnumName = IDENTIFIER_POINTER(TREE_PURPOSE(Link));
          EnumDesc->setName(EnumName);
          EnumDesc->setValue(Value);
        
          Elements.push_back(EnumDesc);
        }
      }
      break;
    }
    
    case RECORD_TYPE:
    case UNION_TYPE:
    case QUAL_UNION_TYPE: {
      // struct { a; b; ... z; }; | union { a; b; ... z; };
      unsigned Tag = TREE_CODE(type) == RECORD_TYPE ? DW_TAG_structure_type :
                                                      DW_TAG_union_type;
      CompositeTypeDesc *StructTy = new CompositeTypeDesc(Tag);
      Ty = StructTy;
      // Set the slot early to prevent recursion difficulties.
      // Any other use of the type should include the qualifiers.
      Slot = AddTypeQualifiers(type, Unit, StructTy);
      // Prepare to add the fields.
      std::vector<DebugInfoDesc *> &Elements = StructTy->getElements();
      
      if (tree binfo = TYPE_BINFO(type)) {
        VEC (tree) *accesses = BINFO_BASE_ACCESSES (binfo);
        
        for (unsigned i = 0, e = BINFO_N_BASE_BINFOS(binfo); i != e; ++i) {
          tree BInfo = BINFO_BASE_BINFO(binfo, i);
          tree BInfoType = BINFO_TYPE (BInfo);
          TypeDesc *BaseClass = getOrCreateType(BInfoType, Unit);
          DerivedTypeDesc *MemberDesc = new DerivedTypeDesc(DW_TAG_inheritance);
          MemberDesc->setFromType(BaseClass);
          
          if (accesses) {
            tree access = VEC_index(tree, accesses, i);
            if (access == access_protected_node) {
              MemberDesc->setIsProtected();
            } else if (access == access_private_node) {
              MemberDesc->setIsPrivate();
            }
          }
          
          MemberDesc->setOffset(tree_low_cst(BINFO_OFFSET(BInfo), 0));
          Elements.push_back(MemberDesc);
        }
      }

      // Now add members of this class.
      for (tree Member = TYPE_FIELDS(type); Member;
                Member = TREE_CHAIN(Member)) {
        // Should we skip.
        if (DECL_P(Member) && DECL_IGNORED_P(Member)) continue;

        // Get the location of the member.
        expanded_location MemLoc = GetNodeLocation(Member, false);
        CompileUnitDesc *MemFile = MemLoc.line ?
                                   getOrCreateCompileUnit(MemLoc.file) :
                                   NULL;

        if (TREE_CODE(Member) == FIELD_DECL) {
          if (DECL_FIELD_OFFSET(Member) == 0 ||
              TREE_CODE(DECL_FIELD_OFFSET(Member)) != INTEGER_CST)
            // FIXME: field with variable position, skip it for now.
            continue;

          DerivedTypeDesc *MemberDesc = new DerivedTypeDesc(DW_TAG_member);
          // Field type is the declared type of the field.
          tree FieldNodeType = FieldType(Member);
          TypeDesc *MemberType = getOrCreateType(FieldNodeType, Unit);
          const char *MemberName = GetNodeName(Member);
          
          MemberDesc->setName(MemberName);
          MemberDesc->setFile(MemFile);
          MemberDesc->setLine(MemLoc.line);
          MemberDesc->setFromType(MemberType);
          MemberDesc->setSize(NodeSizeInBits(Member));
          MemberDesc->setAlign(NodeAlignInBits(FieldNodeType));
          MemberDesc->setOffset(int_bit_position(Member));
          
          if (TREE_PROTECTED(Member)) {
            MemberDesc->setIsProtected();
          } else if (TREE_PRIVATE(Member)) {
            MemberDesc->setIsPrivate();
          }

          Elements.push_back(MemberDesc);
        } else if (TREE_CODE(Member) == VAR_DECL) {
          GlobalVariableDesc *Static = new GlobalVariableDesc();

          // Get name information.
          GetGlobalNames(Member, Static);

          TypeDesc *TyD = getOrCreateType(TREE_TYPE(Member), Unit);
          
          // Fill in the blanks.
          Static->setContext(Unit);
          Static->setFile(MemFile);
          Static->setLine(MemLoc.line);
          Static->setType(TyD);
          Static->setIsDefinition(false);
          Static->setIsStatic(!TREE_PUBLIC(Member));

          Elements.push_back(Static);
        } else {
          // FIXME - ignoring others for the time being.
        }
      }
      for (tree Member = TYPE_METHODS(type); Member;
                Member = TREE_CHAIN(Member)) {
                
        if (DECL_ABSTRACT_ORIGIN (Member)) continue;
                
        // Create subprogram descriptor.
        Subprogram = new SubprogramDesc();
        
        // Get name information.
        GetGlobalNames(Member, Subprogram);
        
        // Get function type.
        TypeDesc *SPTy = getOrCreateType(TREE_TYPE(Member), Unit);

        if (TREE_PROTECTED(Member)) {
          SPTy->setIsProtected();
        } else if (TREE_PRIVATE(Member)) {
          SPTy->setIsPrivate();
        }

        Subprogram->setContext(Unit);
        Subprogram->setFile(Unit);
        Subprogram->setLine(CurLineNo);
        Subprogram->setType(SPTy);
        Subprogram->setIsStatic(!TREE_PUBLIC(Member));
        Subprogram->setIsDefinition(false);

        Elements.push_back(Subprogram);
      }
      
      break;
    }

    case INTEGER_TYPE:
    case CHAR_TYPE:
    case REAL_TYPE:   
    case COMPLEX_TYPE:
    case BOOLEAN_TYPE: {
      // char, short, int, long long, bool, float, double.
      BasicTypeDesc *BTy = new BasicTypeDesc();
      Ty = BTy;
      // Any other use of the type should include the qualifiers.
      Slot = AddTypeQualifiers(type, Unit, BTy);
      // The encoding specific to the type.
      unsigned Encoding = 0;

      switch (TREE_CODE(type)) {
      case INTEGER_TYPE:
        // Unless is smells like a char use integer,
        if (!(TYPE_PRECISION(type) == CHAR_TYPE_SIZE && 
             (type == char_type_node ||
              !strcmp (TypeName, "signed char") ||
              !strcmp (TypeName, "unsigned char")))) {
          Encoding = TYPE_UNSIGNED(type) ? DW_ATE_unsigned : DW_ATE_signed;
          break;
        }
        // fall through
      case CHAR_TYPE:
        Encoding = TYPE_UNSIGNED(type) ? DW_ATE_unsigned_char :
                                         DW_ATE_signed_char;
        break;
      case REAL_TYPE:
        Encoding = DW_ATE_float;
        break;
      case COMPLEX_TYPE:
        Encoding = TREE_CODE(TREE_TYPE(type)) == REAL_TYPE ?
                             DW_ATE_complex_float : DW_ATE_lo_user;
        break;
      case BOOLEAN_TYPE:
        Encoding = DW_ATE_boolean;
        break;
      default: { 
        DEBUGASSERT(0 && "Basic type case missing");
        Encoding = DW_ATE_signed;
        Size = BITS_PER_WORD;
        Align = BITS_PER_WORD;
        break;
      }
      }
      
      BTy->setEncoding(Encoding);
      // Don't associate basic type with a location.
      Loc.line = 0;
    }
    }
  }

  // If the type is defined, fill in teh details.
  if (Ty) {
    CompileUnitDesc *File = Loc.line ? getOrCreateCompileUnit(Loc.file) : NULL;
 
    Ty->setContext(Unit);
    Ty->setName(TypeName);
    Ty->setFile(File);
    Ty->setLine(Loc.line);
    Ty->setSize(Size);
    Ty->setAlign(Align);
    Ty->setOffset(Offset);
  }

  DEBUGASSERT(Slot && "Unimplemented type");
  
  return Slot;
}

/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
/// one if necessary.
CompileUnitDesc *DebugInfo::getOrCreateCompileUnit(const std::string &FullPath){
  // See if this compile unit has been used before.
  CompileUnitDesc *&Slot = CompileUnitCache[FullPath];
  if (Slot) return Slot;

  // Create new compile unit.
  CompileUnitDesc *Unit = new CompileUnitDesc();

  // Make sure we have an anchor.
  if (!CompileUnitAnchor) {
    CompileUnitAnchor = new AnchorDesc(Unit);
  }

  // Get source file information.
  std::string Directory;
  std::string FileName;
  DirectoryAndFile(FullPath, Directory, FileName);
  
  Unit->setAnchor(CompileUnitAnchor);
  Unit->setFileName(FileName);
  Unit->setDirectory(Directory);
  
  // Set up producer name.
  Unit->setProducer(version_string);

  // Set up Language number.
  unsigned Language;
  const std::string LanguageName(lang_hooks.name);
  if (LanguageName == "GNU C")
    Unit->setLanguage(DW_LANG_C89);
  else if (LanguageName == "GNU C++")
    Unit->setLanguage(DW_LANG_C_plus_plus);
  else if (LanguageName == "GNU Ada")
    Unit->setLanguage(DW_LANG_Ada95);
  else if (LanguageName == "GNU F77")
    Unit->setLanguage(DW_LANG_Fortran77);
  else if (LanguageName == "GNU Pascal")
    Unit->setLanguage(DW_LANG_Pascal83);
  else if (LanguageName == "GNU Java")
    Unit->setLanguage(DW_LANG_Java);
  else
    Unit->setLanguage(DW_LANG_C89);
    
  // Update cache.
  Slot = Unit;
  
  return Unit;
}


/* APPLE LOCAL end LLVM (ENTIRE FILE!)  */



syntax highlighted by Code2HTML, v. 0.9.1