packages feed

llvm-data-interop-0.3.0: src/c++/marshal.cpp

#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS

#include "marshal.h"

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <tr1/unordered_map>

#include <llvm/ADT/OwningPtr.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/system_error.h>

#include <llvm/Config/llvm-config.h>

#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR > 3
  #error "LLVM 4.0 and greater are not supported"
#endif

// LLVM 3.0 does not define LLVM_VERSION_MAJOR
#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 2
  // LLVM 3.2 moved the debug info header and renamed TargetData
  // to DataLayout.  LLVM 3.3 moved the DataLayout header.
  #include <llvm/DebugInfo.h>
  #if LLVM_VERSION_MINOR >= 3
    #include <llvm/IR/DataLayout.h>
  #else
    #include <llvm/DataLayout.h>
  #endif
#else
  // LLVM 3.0/3.1
  #include <llvm/Analysis/DebugInfo.h>
  #include <llvm/Target/TargetData.h>
  #define DataLayout TargetData
#endif

#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 3
  // LLVM 3.3
  #include <llvm/IR/CallingConv.h>
  #include <llvm/IR/DerivedTypes.h>
  #include <llvm/IR/InlineAsm.h>
  #include <llvm/IR/IntrinsicInst.h>
  #include <llvm/IR/Instructions.h>
  #include <llvm/IR/LLVMContext.h>
  #include <llvm/IR/Module.h>
  #include <llvm/IR/Operator.h>
  #include <llvm/IR/Type.h>
  #include <llvm/IRReader/IRReader.h>
#else
  // LLVM 3.0-3.2
  #include <llvm/CallingConv.h>
  #include <llvm/DerivedTypes.h>
  #include <llvm/InlineAsm.h>
  #include <llvm/IntrinsicInst.h>
  #include <llvm/Instructions.h>
  #include <llvm/LLVMContext.h>
  #include <llvm/Module.h>
  #include <llvm/Operator.h>
  #include <llvm/Type.h>
  #include <llvm/Support/IRReader.h>
#endif

using namespace llvm;
using std::ostringstream;
using std::string;
using std::tr1::unordered_map;

// Utility functions to hide incompatibilities between LLVM API
// versions
static int64_t getHiDISubrange(llvm::DISubrange &subrange) {
#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 3
  return subrange.getLo() + subrange.getCount();
#else
  return subrange.getHi();
#endif
}

static char* getCStrdup(StringRef str) {
  return strndup(str.data(), str.size());
}

static char* getCStrdup(std::string &str) {
  return strdup(str.c_str());
}

static char* getCStrdup(const char *str) {
  return strdup(str);
}

static char* getCStrdup(llvm::raw_string_ostream &os) {
  return getCStrdup(os.str());
}

struct PrivateData {
  LLVMContext ctxt;
  SMDiagnostic diags;
  OwningPtr<MemoryBuffer> buffer;
  // Foreign callers do not need to access below this point.
  Module* original;
  int includeLocs;
  DataLayout *dataLayout;

  // This map is actually state only for this translation code.  Since
  // types have pointer equality in LLVM, every type will just be
  // translated once to a heap-allocated CType.  On the Haskell side,
  // each CType needs to be translated once (mapping the address of
  // the CType to the translated version).
  unordered_map<const Type*, CType*> typeMap;
  unordered_map<const Value*, CValue*> valueMap;
  unordered_map<const MDNode*, CMeta*> metaMap;
  unordered_map<const DebugLoc*, CMeta*> srcLocMap;
};

static ValueTag decodeOpcode(unsigned opcode) {
  switch(opcode) {
  case Instruction::Ret: return VAL_RETINST;
  case Instruction::Br: return VAL_BRANCHINST;
  case Instruction::Switch: return VAL_SWITCHINST;
  case Instruction::IndirectBr: return VAL_INDIRECTBRINST;
  case Instruction::Invoke: return VAL_INVOKEINST;
  case Instruction::Resume: return VAL_RESUMEINST;
  case Instruction::Unreachable: return VAL_UNREACHABLEINST;
  case Instruction::Add: return VAL_ADDINST;
  case Instruction::FAdd: return VAL_FADDINST;
  case Instruction::Sub: return VAL_SUBINST;
  case Instruction::FSub: return VAL_FSUBINST;
  case Instruction::Mul: return VAL_MULINST;
  case Instruction::FMul: return VAL_FMULINST;
  case Instruction::UDiv: return VAL_UDIVINST;
  case Instruction::SDiv: return VAL_SDIVINST;
  case Instruction::FDiv: return VAL_FDIVINST;
  case Instruction::URem: return VAL_UREMINST;
  case Instruction::SRem: return VAL_SREMINST;
  case Instruction::FRem: return VAL_FREMINST;
  case Instruction::Shl: return VAL_SHLINST;
  case Instruction::LShr: return VAL_LSHRINST;
  case Instruction::AShr: return VAL_ASHRINST;
  case Instruction::And: return VAL_ANDINST;
  case Instruction::Or: return VAL_ORINST;
  case Instruction::Xor: return VAL_XORINST;
  case Instruction::Alloca: return VAL_ALLOCAINST;
  case Instruction::Load: return VAL_LOADINST;
  case Instruction::Store: return VAL_STOREINST;
  case Instruction::GetElementPtr: return VAL_GETELEMENTPTRINST;
  case Instruction::Fence: return VAL_FENCEINST;
  case Instruction::AtomicCmpXchg: return VAL_ATOMICCMPXCHGINST;
  case Instruction::AtomicRMW: return VAL_ATOMICRMWINST;
  case Instruction::Trunc: return VAL_TRUNCINST;
  case Instruction::ZExt: return VAL_ZEXTINST;
  case Instruction::SExt: return VAL_SEXTINST;
  case Instruction::FPToUI: return VAL_FPTOUIINST;
  case Instruction::FPToSI: return VAL_FPTOSIINST;
  case Instruction::UIToFP: return VAL_UITOFPINST;
  case Instruction::SIToFP: return VAL_SITOFPINST;
  case Instruction::FPTrunc: return VAL_FPTRUNCINST;
  case Instruction::FPExt: return VAL_FPEXTINST;
  case Instruction::PtrToInt: return VAL_PTRTOINTINST;
  case Instruction::IntToPtr: return VAL_INTTOPTRINST;
  case Instruction::BitCast: return VAL_BITCASTINST;
  case Instruction::ICmp: return VAL_ICMPINST;
  case Instruction::FCmp: return VAL_FCMPINST;
  case Instruction::PHI: return VAL_PHINODE;
  case Instruction::Call: return VAL_CALLINST;
  case Instruction::Select: return VAL_SELECTINST;
  case Instruction::VAArg: return VAL_VAARGINST;
  case Instruction::ExtractElement: return VAL_EXTRACTELEMENTINST;
  case Instruction::InsertElement: return VAL_INSERTELEMENTINST;
  case Instruction::ShuffleVector: return VAL_SHUFFLEVECTORINST;
  case Instruction::ExtractValue: return VAL_EXTRACTVALUEINST;
  case Instruction::InsertValue: return VAL_INSERTVALUEINST;
  case Instruction::LandingPad: return VAL_LANDINGPADINST;
  }

  ostringstream os;
  os << "Unhandled instruction type in opcode translator: " << opcode;
  throw os.str();
}

static CmpPredicate decodePredicate(CmpInst::Predicate p) {
  switch(p) {
  case CmpInst::FCMP_FALSE: return F_CMP_FALSE;
  case CmpInst::FCMP_OEQ: return F_CMP_OEQ;
  case CmpInst::FCMP_OGT: return F_CMP_OGT;
  case CmpInst::FCMP_OGE: return F_CMP_OGE;
  case CmpInst::FCMP_OLT: return F_CMP_OLT;
  case CmpInst::FCMP_OLE: return F_CMP_OLE;
  case CmpInst::FCMP_ONE: return F_CMP_ONE;
  case CmpInst::FCMP_ORD: return F_CMP_ORD;
  case CmpInst::FCMP_UNO: return F_CMP_UNO;
  case CmpInst::FCMP_UEQ: return F_CMP_UEQ;
  case CmpInst::FCMP_UGT: return F_CMP_UGT;
  case CmpInst::FCMP_UGE: return F_CMP_UGE;
  case CmpInst::FCMP_ULT: return F_CMP_ULT;
  case CmpInst::FCMP_ULE: return F_CMP_ULE;
  case CmpInst::FCMP_UNE: return F_CMP_UNE;
  case CmpInst::FCMP_TRUE: return F_CMP_TRUE;
  case CmpInst::ICMP_EQ: return I_CMP_EQ;
  case CmpInst::ICMP_NE: return I_CMP_NE;
  case CmpInst::ICMP_UGT: return I_CMP_UGT;
  case CmpInst::ICMP_UGE: return I_CMP_UGE;
  case CmpInst::ICMP_ULT: return I_CMP_ULT;
  case CmpInst::ICMP_ULE: return I_CMP_ULE;
  case CmpInst::ICMP_SGT: return I_CMP_SGT;
  case CmpInst::ICMP_SGE: return I_CMP_SGE;
  case CmpInst::ICMP_SLT: return I_CMP_SLT;
  case CmpInst::ICMP_SLE: return I_CMP_SLE;
  }

  ostringstream os;
  os << "Unhandled comparison predicate: " << p;
  throw os.str();
}

static TypeTag decodeTypeTag(Type::TypeID t) {
  switch(t) {
  case Type::VoidTyID: return TYPE_VOID;
  case Type::FloatTyID: return TYPE_FLOAT;
  case Type::DoubleTyID: return TYPE_DOUBLE;
  case Type::X86_FP80TyID: return TYPE_X86_FP80;
  case Type::FP128TyID: return TYPE_FP128;
  case Type::PPC_FP128TyID: return TYPE_PPC_FP128;
  case Type::LabelTyID: return TYPE_LABEL;
  case Type::MetadataTyID: return TYPE_METADATA;
  case Type::X86_MMXTyID: return TYPE_X86_MMX;
  case Type::IntegerTyID: return TYPE_INTEGER;
  case Type::FunctionTyID: return TYPE_FUNCTION;
  case Type::StructTyID: return TYPE_STRUCT;
  case Type::ArrayTyID: return TYPE_ARRAY;
  case Type::PointerTyID: return TYPE_POINTER;
  case Type::VectorTyID: return TYPE_VECTOR;
  }

  ostringstream os;
  os << "Unhandled type tag case: " << t;
  throw os.str();
}

static LinkageType decodeLinkage(const GlobalValue *gv) {
  switch(gv->getLinkage()) {
  case GlobalValue::ExternalLinkage: return LTExternal;
  case GlobalValue::AvailableExternallyLinkage: return LTAvailableExternally;
  case GlobalValue::LinkOnceAnyLinkage: return LTLinkOnceAny;
  case GlobalValue::LinkOnceODRLinkage: return LTLinkOnceODR;
  case GlobalValue::WeakAnyLinkage: return LTWeakAny;
  case GlobalValue::WeakODRLinkage: return LTWeakODR;
  case GlobalValue::AppendingLinkage: return LTAppending;
  case GlobalValue::InternalLinkage: return LTInternal;
  case GlobalValue::PrivateLinkage: return LTPrivate;
  case GlobalValue::LinkerPrivateLinkage: return LTLinkerPrivate;
  case GlobalValue::LinkerPrivateWeakLinkage: return LTLinkerPrivateWeak;
#if LLVM_VERSION_MINOR < 2
  case GlobalValue::LinkerPrivateWeakDefAutoLinkage: return LTLinkerPrivateWeakDefAuto;
#endif
  case GlobalValue::DLLImportLinkage: return LTDLLImport;
  case GlobalValue::DLLExportLinkage: return LTDLLExport;
  case GlobalValue::ExternalWeakLinkage: return LTExternalWeak;
  case GlobalValue::CommonLinkage: return LTCommon;
  }

  ostringstream os;
  os << "Unhandled linkage type: " << gv->getLinkage();
  throw os.str();
}

static VisibilityStyle decodeVisibility(const GlobalValue *gv) {
  switch(gv->getVisibility()) {
  case GlobalValue::DefaultVisibility: return VisibilityDefault;
  case GlobalValue::HiddenVisibility: return VisibilityHidden;
  case GlobalValue::ProtectedVisibility: return VisibilityProtected;
  }

  ostringstream os;
  os << "Unhandled visibility style: " << gv->getVisibility();
  throw os.str();
}

static CAtomicOrdering decodeOrdering(AtomicOrdering o) {
  switch(o) {
  case llvm::NotAtomic: return OrderNotAtomic;
  case llvm::Unordered: return OrderUnordered;
  case llvm::Monotonic: return OrderMonotonic;
  case llvm::Acquire: return OrderAcquire;
  case llvm::Release: return OrderRelease;
  case llvm::AcquireRelease: return OrderAcquireRelease;
  case llvm::SequentiallyConsistent: return OrderSequentiallyConsistent;
  }

  ostringstream os;
  os << "Unhandled atomic ordering: " << o;
  throw os.str();
}

static CSynchronizationScope decodeSynchScope(SynchronizationScope s) {
  switch(s) {
  case llvm::SingleThread: return SSSingleThread;
  case llvm::CrossThread: return SSCrossThread;
  }

  ostringstream os;
  os << "Unhandled synchronization scope: " << s;
  throw os.str();
}

static AtomicOperation decodeAtomicOp(AtomicRMWInst::BinOp o) {
  switch(o) {
  case AtomicRMWInst::Xchg: return AOXchg;
  case AtomicRMWInst::Add: return AOAdd;
  case AtomicRMWInst::Sub: return AOSub;
  case AtomicRMWInst::And: return AOAnd;
  case AtomicRMWInst::Nand: return AONand;
  case AtomicRMWInst::Or: return AOOr;
  case AtomicRMWInst::Xor: return AOXor;
  case AtomicRMWInst::Max: return AOMax;
  case AtomicRMWInst::Min: return AOMin;
  case AtomicRMWInst::UMax: return AOUMax;
  case AtomicRMWInst::UMin: return AOUMin;
  }

  ostringstream os;
  os << "Unhandled atomic operation: " << o;
  throw os.str();
}

static CallingConvention decodeCallingConvention(CallingConv::ID cc) {
  switch(cc) {
  case CallingConv::C: return CC_C;
  case CallingConv::Fast: return CC_FAST;
  case CallingConv::Cold: return CC_COLD;
  case CallingConv::GHC: return CC_GHC;
  case CallingConv::X86_StdCall: return CC_X86_STDCALL;
  case CallingConv::X86_FastCall: return CC_X86_FASTCALL;
  case CallingConv::ARM_APCS: return CC_ARM_APCS;
  case CallingConv::ARM_AAPCS: return CC_ARM_AAPCS;
  case CallingConv::ARM_AAPCS_VFP: return CC_ARM_AAPCS_VFP;
  case CallingConv::MSP430_INTR: return CC_MSP430_INTR;
  case CallingConv::X86_ThisCall: return CC_X86_THISCALL;
  case CallingConv::PTX_Kernel: return CC_PTX_KERNEL;
  case CallingConv::PTX_Device: return CC_PTX_DEVICE;
  case CallingConv::MBLAZE_INTR: return CC_MBLAZE_INTR;
  case CallingConv::MBLAZE_SVOL: return CC_MBLAZE_SVOL;
  }

  ostringstream os;
  os << "Unhandled calling convention: " << cc;
  throw os.str();
}

static void disposeCType(CType *ct) {
  free(ct->name);
  free(ct->typeList);
  free(ct);
}

static void disposeCMeta(CMeta *meta) {
  switch(meta->metaTag) {
  case META_LOCATION:
    free(meta->u.metaLocationInfo.filename);
    free(meta->u.metaLocationInfo.directory);
    break;

  case META_DERIVEDTYPE:
  case META_COMPOSITETYPE:
  case META_BASICTYPE:
    free(meta->u.metaTypeInfo.name);
    free(meta->u.metaTypeInfo.directory);
    free(meta->u.metaTypeInfo.filename);
    break;

  case META_VARIABLE:
    free(meta->u.metaVariableInfo.name);
    break;

  case META_SUBPROGRAM:
    free(meta->u.metaSubprogramInfo.name);
    free(meta->u.metaSubprogramInfo.displayName);
    free(meta->u.metaSubprogramInfo.linkageName);
    free(meta->u.metaSubprogramInfo.returnTypeName);
    free(meta->u.metaSubprogramInfo.filename);
    free(meta->u.metaSubprogramInfo.directory);
    break;

  case META_GLOBALVARIABLE:
    free(meta->u.metaGlobalInfo.name);
    free(meta->u.metaGlobalInfo.displayName);
    free(meta->u.metaGlobalInfo.linkageName);
    break;

  case META_FILE:
    free(meta->u.metaFileInfo.filename);
    free(meta->u.metaFileInfo.directory);
    break;

  case META_COMPILEUNIT:
    free(meta->u.metaCompileUnitInfo.filename);
    free(meta->u.metaCompileUnitInfo.directory);
    free(meta->u.metaCompileUnitInfo.producer);
    free(meta->u.metaCompileUnitInfo.flags);
    break;

  case META_NAMESPACE:
    free(meta->u.metaNamespaceInfo.name);
    free(meta->u.metaNamespaceInfo.directory);
    free(meta->u.metaNamespaceInfo.filename);
    break;

  case META_LEXICALBLOCK:
    free(meta->u.metaLexicalBlockInfo.directory);
    free(meta->u.metaLexicalBlockInfo.filename);
    break;

  case META_SUBRANGE:
    break;

  case META_ENUMERATOR:
    free(meta->u.metaEnumeratorInfo.enumName);
    break;

  case META_ARRAY:
    free(meta->u.metaArrayInfo.arrayElts);
    break;

  case META_TEMPLATETYPEPARAMETER:
    free(meta->u.metaTemplateTypeInfo.name);
    free(meta->u.metaTemplateTypeInfo.filename);
    free(meta->u.metaTemplateTypeInfo.directory);
    break;

  case META_TEMPLATEVALUEPARAMETER:
    free(meta->u.metaTemplateValueInfo.name);
    free(meta->u.metaTemplateValueInfo.filename);
    free(meta->u.metaTemplateValueInfo.directory);
    break;

  case META_UNKNOWN:
    free(meta->u.metaUnknownInfo.repr);
    break;
  }


  free(meta);
}

// Have to do the delete in this function since the pointer must be
// cast to the correct type.
static void disposeData(ValueTag t, void* data) {
  switch(t) {
  case VAL_ARGUMENT:
  {
    CArgumentInfo *ai = (CArgumentInfo*)data;
    free(ai);
    return;
  }

  case VAL_BASICBLOCK:
  {
    CBasicBlockInfo *bbi = (CBasicBlockInfo*)data;

    // The actual values are deleted from the valueMap
    free(bbi->instructions);

    free(bbi);
    return;
  }

  case VAL_INLINEASM:
  {
    CInlineAsmInfo *ii = (CInlineAsmInfo*)data;
    free(ii->asmString);
    free(ii->constraintString);
    free(ii);
    return;
  }

  case VAL_ALIAS:
  case VAL_GLOBALVARIABLE:
  {
    CGlobalInfo *gi = (CGlobalInfo*)data;

    free(gi->section);

    free(gi);
    return;
  }

  case VAL_FUNCTION:
  {
    CFunctionInfo *fi = (CFunctionInfo*)data;

    free(fi->section);
    free(fi->gcName);

    free(fi->arguments);
    free(fi->body);

    free(fi);
    return;
  }

  case VAL_UNREACHABLEINST:
  {
    // No data
    return;
  }

  case VAL_INVOKEINST:
  case VAL_CALLINST:
  {
    CCallInfo *ci = (CCallInfo*)data;

    free(ci->arguments);
    free(ci);
    return;
  }

  case VAL_PHINODE:
  {
    CPHIInfo *pi = (CPHIInfo*)data;
    free(pi->incomingValues);
    free(pi->valueBlocks);
    free(pi);
    return;
  }

  case VAL_FENCEINST:
  case VAL_ATOMICCMPXCHGINST:
  case VAL_ATOMICRMWINST:
  {
    CAtomicInfo *ai = (CAtomicInfo*)data;
    free(ai);
    return;
  }

  case VAL_LANDINGPADINST:
  {
    CLandingPadInfo *li = (CLandingPadInfo*)data;
    free(li->clauses);
    free(li->clauseTypes);
    return;
  }

  case VAL_RESUMEINST:
  case VAL_RETINST:
  case VAL_BRANCHINST:
  case VAL_SWITCHINST:
  case VAL_INDIRECTBRINST:
  case VAL_GETELEMENTPTRINST:
  case VAL_STOREINST:
  case VAL_ALLOCAINST:
  case VAL_LOADINST:
  case VAL_ADDINST:
  case VAL_FADDINST:
  case VAL_SUBINST:
  case VAL_FSUBINST:
  case VAL_MULINST:
  case VAL_FMULINST:
  case VAL_UDIVINST:
  case VAL_SDIVINST:
  case VAL_FDIVINST:
  case VAL_UREMINST:
  case VAL_SREMINST:
  case VAL_FREMINST:
  case VAL_SHLINST:
  case VAL_LSHRINST:
  case VAL_ASHRINST:
  case VAL_ANDINST:
  case VAL_ORINST:
  case VAL_XORINST:
  case VAL_TRUNCINST:
  case VAL_ZEXTINST:
  case VAL_SEXTINST:
  case VAL_FPTOUIINST:
  case VAL_FPTOSIINST:
  case VAL_UITOFPINST:
  case VAL_SITOFPINST:
  case VAL_FPTRUNCINST:
  case VAL_FPEXTINST:
  case VAL_PTRTOINTINST:
  case VAL_INTTOPTRINST:
  case VAL_BITCASTINST:
  case VAL_ICMPINST:
  case VAL_FCMPINST:
  case VAL_VAARGINST:
  case VAL_SELECTINST:
  case VAL_EXTRACTELEMENTINST:
  case VAL_INSERTELEMENTINST:
  case VAL_SHUFFLEVECTORINST:
  case VAL_EXTRACTVALUEINST:
  case VAL_INSERTVALUEINST:
  {
    CInstructionInfo *ii = (CInstructionInfo*)data;
    free(ii->operands);
    free(ii->indices);
    free(ii);
    return;
  }

  case VAL_BLOCKADDRESS:
  {
    CBlockAddrInfo *bi = (CBlockAddrInfo*)data;
    free(bi);
    return;
  }

  case VAL_CONSTANTINT:
  {
    CConstInt *d = (CConstInt*)data;
    free(d->hugeVal);
    free(d);
    return;
  }

  case VAL_CONSTANTFP:
  {
    CConstFP *d = (CConstFP*)data;
    free(d);
    return;
  }

  case VAL_CONSTANTPOINTERNULL:
  case VAL_CONSTANTAGGREGATEZERO:
  case VAL_UNDEFVALUE:
  {
    // No data
    return;
  }

  case VAL_CONSTANTSTRUCT:
  case VAL_CONSTANTVECTOR:
  case VAL_CONSTANTARRAY:
  {
    CConstAggregate *c = (CConstAggregate*)data;
    free(c->constants);
    free(c);
    return;
  }

  case VAL_CONSTANTEXPR:
  {
    CConstExprInfo *ce = (CConstExprInfo*)data;
    free(ce->ii->operands);
    free(ce->ii->indices);
    free(ce->ii);
    free(ce);
    return;
  }

  }

  ostringstream os;
  os << "Unhandled cleanup case for value tag: " << t;
  throw os.str();
}

static void disposeCValue(CValue *v) {
  // Do not dispose the type - that is taken care of in bulk in the
  // CModule disposal.  Same for MD.
  free(v->name);
  free(v->md);

  disposeData(v->valueTag, v->data);

  free(v);
}

static MetaTag extractMetaTag(const MDNode *md) {
  DIDescriptor desc(md);
  // Ranked roughly by frequency.
  if(desc.isLexicalBlock()) return META_LEXICALBLOCK;
  // This variant of lexical block has an extra file argument that is
  // not currently translated.  This might be used for code inserted
  // by the preprocessor from headers?
  if(desc.isLexicalBlockFile()) return META_LEXICALBLOCK;
  if(desc.isVariable()) return META_VARIABLE;
  if(desc.isSubprogram()) return META_SUBPROGRAM;
  if(desc.isGlobalVariable()) return META_GLOBALVARIABLE;
  if(desc.isCompositeType()) return META_COMPOSITETYPE;
  if(desc.isDerivedType()) return META_DERIVEDTYPE;
  if(desc.isBasicType()) return META_BASICTYPE;
  if(desc.isFile()) return META_FILE;
  if(desc.isCompileUnit()) return META_COMPILEUNIT;
  if(desc.isNameSpace()) return META_NAMESPACE;
  if(desc.isSubrange()) return META_SUBRANGE;
  if(desc.isEnumerator()) return META_ENUMERATOR;
  if(desc.isTemplateTypeParameter()) return META_TEMPLATETYPEPARAMETER;
  if(desc.isTemplateValueParameter()) return META_TEMPLATEVALUEPARAMETER;

  DILocation loc(md);
  if(loc.Verify()) return META_LOCATION;

  // Otherwise we have no idea what to do with this.  One type of odd
  // metadata is the inline assembly srcloc metadata, which has a
  // strange format.  Right now we don't bother to translate this.  It
  // could probably be done if required... we don't know what it
  // really is at this stage, though, so it might need to be
  // serialized generically as an MDNode
  return META_UNKNOWN;
}

static CValue* translateConstant(CModule *m, const Constant *c);
static CValue* translateValue(CModule *m, const Value *v);
static CValue* translateBasicBlock(CModule *m, const BasicBlock *bb);
static CMeta* translateMetadata(CModule *m, const MDNode *md);
static CMeta* translateMetadataArray(CModule *m, const MDNode *md);

static void makeMetaSrcLocation(CModule *m, const DebugLoc &loc, CMeta *meta) {
  meta->u.metaLocationInfo.lineNumber = loc.getLine();
  meta->u.metaLocationInfo.columnNumber = loc.getCol();
}

static void makeMetaLocation(CModule *m, const MDNode *md, CMeta *meta) {
  DILocation loc(md);
  meta->u.metaLocationInfo.lineNumber = loc.getLineNumber();
  meta->u.metaLocationInfo.columnNumber = loc.getColumnNumber();
}

static void makeMetaDerivedType(CModule *m, const MDNode *md, CMeta *meta) {
  DIDerivedType dt(md);
  meta->u.metaTypeInfo.context = translateMetadata(m, dt.getContext());
  meta->u.metaTypeInfo.name = getCStrdup(dt.getName());
  meta->u.metaTypeInfo.lineNumber = dt.getLineNumber();
  meta->u.metaTypeInfo.sizeInBits = dt.getSizeInBits();
  meta->u.metaTypeInfo.alignInBits = dt.getAlignInBits();
  meta->u.metaTypeInfo.offsetInBits = dt.getOffsetInBits();
  meta->u.metaTypeInfo.flags = dt.getFlags();
  meta->u.metaTypeInfo.isPrivate = dt.isPrivate();
  meta->u.metaTypeInfo.isProtected = dt.isProtected();
  meta->u.metaTypeInfo.isForward = dt.isForwardDecl();
  meta->u.metaTypeInfo.isByRefStruct = dt.isBlockByrefStruct();
  meta->u.metaTypeInfo.isVirtual = dt.isVirtual();
  meta->u.metaTypeInfo.isArtificial = dt.isArtificial();
  meta->u.metaTypeInfo.directory = getCStrdup(dt.getDirectory());
  meta->u.metaTypeInfo.filename = getCStrdup(dt.getFilename());

  meta->u.metaTypeInfo.typeDerivedFrom = translateMetadata(m, dt.getTypeDerivedFrom());
  meta->u.metaTypeInfo.originalTypeSize = dt.getOriginalTypeSize();
}

static void makeMetaCompositeType(CModule *m, const MDNode *md, CMeta *meta) {
  DICompositeType dt(md);
  meta->u.metaTypeInfo.context = translateMetadata(m, dt.getContext());
  meta->u.metaTypeInfo.name = getCStrdup(dt.getName());
  meta->u.metaTypeInfo.lineNumber = dt.getLineNumber();
  meta->u.metaTypeInfo.sizeInBits = dt.getSizeInBits();
  meta->u.metaTypeInfo.alignInBits = dt.getAlignInBits();
  meta->u.metaTypeInfo.offsetInBits = dt.getOffsetInBits();
  meta->u.metaTypeInfo.flags = dt.getFlags();
  meta->u.metaTypeInfo.isPrivate = dt.isPrivate();
  meta->u.metaTypeInfo.isProtected = dt.isProtected();
  meta->u.metaTypeInfo.isForward = dt.isForwardDecl();
  meta->u.metaTypeInfo.isByRefStruct = dt.isBlockByrefStruct();
  meta->u.metaTypeInfo.isVirtual = dt.isVirtual();
  meta->u.metaTypeInfo.isArtificial = dt.isArtificial();
  meta->u.metaTypeInfo.directory = getCStrdup(dt.getDirectory());
  meta->u.metaTypeInfo.filename = getCStrdup(dt.getFilename());

  meta->u.metaTypeInfo.typeDerivedFrom = translateMetadata(m, dt.getTypeDerivedFrom());
  meta->u.metaTypeInfo.originalTypeSize = dt.getOriginalTypeSize();

  meta->u.metaTypeInfo.typeArray = translateMetadataArray(m, dt.getTypeArray());
  meta->u.metaTypeInfo.runTimeLang = dt.getRunTimeLang();
  meta->u.metaTypeInfo.containingType = translateMetadata(m, dt.getContainingType());
  meta->u.metaTypeInfo.templateParams = translateMetadata(m, dt.getTemplateParams());
}

static void makeMetaBasicType(CModule *m, const MDNode *md, CMeta *meta) {
  DIBasicType dt(md);
  meta->u.metaTypeInfo.context = translateMetadata(m, dt.getContext());
  meta->u.metaTypeInfo.name = getCStrdup(dt.getName());
  meta->u.metaTypeInfo.lineNumber = dt.getLineNumber();
  meta->u.metaTypeInfo.sizeInBits = dt.getSizeInBits();
  meta->u.metaTypeInfo.alignInBits = dt.getAlignInBits();
  meta->u.metaTypeInfo.offsetInBits = dt.getOffsetInBits();
  meta->u.metaTypeInfo.flags = dt.getFlags();
  meta->u.metaTypeInfo.isPrivate = dt.isPrivate();
  meta->u.metaTypeInfo.isProtected = dt.isProtected();
  meta->u.metaTypeInfo.isForward = dt.isForwardDecl();
  meta->u.metaTypeInfo.isByRefStruct = dt.isBlockByrefStruct();
  meta->u.metaTypeInfo.isVirtual = dt.isVirtual();
  meta->u.metaTypeInfo.isArtificial = dt.isArtificial();
  meta->u.metaTypeInfo.directory = getCStrdup(dt.getDirectory());
  meta->u.metaTypeInfo.filename = getCStrdup(dt.getFilename());

  meta->u.metaTypeInfo.encoding = dt.getEncoding();
}

static void makeMetaVariable(CModule *m, const MDNode *md, CMeta *meta) {
  DIVariable dv(md);
  meta->u.metaVariableInfo.context = translateMetadata(m, dv.getContext());
  meta->u.metaVariableInfo.name = getCStrdup(dv.getName());
  meta->u.metaVariableInfo.lineNumber = dv.getLineNumber();
  meta->u.metaVariableInfo.argNumber = dv.getArgNumber();
  meta->u.metaVariableInfo.type = translateMetadata(m, dv.getType());
  meta->u.metaVariableInfo.isArtificial = dv.isArtificial();
  meta->u.metaVariableInfo.hasComplexAddress = dv.hasComplexAddress();
  meta->u.metaVariableInfo.numAddrElements = dv.getNumAddrElements();
  if(meta->u.metaVariableInfo.numAddrElements > 0) {
    meta->u.metaVariableInfo.addrElements =
      (uint64_t*)calloc(meta->u.metaVariableInfo.numAddrElements, sizeof(uint64_t));

    for(unsigned int i = 0; i < meta->u.metaVariableInfo.numAddrElements; ++i) {
      meta->u.metaVariableInfo.addrElements[i] = dv.getAddrElement(i);
    }
  }

  meta->u.metaVariableInfo.isBlockByRefVar = dv.isBlockByrefVariable();
}

static void makeMetaSubprogram(CModule *m, const MDNode *md, CMeta *meta) {
  DISubprogram ds(md);
  meta->u.metaSubprogramInfo.context = translateMetadata(m, ds.getContext());
  meta->u.metaSubprogramInfo.name = getCStrdup(ds.getName());
  meta->u.metaSubprogramInfo.displayName = getCStrdup(ds.getDisplayName());
  meta->u.metaSubprogramInfo.linkageName = getCStrdup(ds.getLinkageName());
  meta->u.metaSubprogramInfo.lineNumber = ds.getLineNumber();
  meta->u.metaSubprogramInfo.type = translateMetadata(m, ds.getType());
  meta->u.metaSubprogramInfo.returnTypeName = getCStrdup(ds.getReturnTypeName());
  meta->u.metaSubprogramInfo.isLocalToUnit = ds.isLocalToUnit();
  meta->u.metaSubprogramInfo.isDefinition = ds.isDefinition();
  meta->u.metaSubprogramInfo.virtuality = ds.getVirtuality();
  meta->u.metaSubprogramInfo.virtualIndex = ds.getVirtualIndex();
  meta->u.metaSubprogramInfo.containingType = translateMetadata(m, ds.getContainingType());
  meta->u.metaSubprogramInfo.isArtificial = ds.isArtificial();
  meta->u.metaSubprogramInfo.isPrivate = ds.isPrivate();
  meta->u.metaSubprogramInfo.isProtected = ds.isProtected();
  meta->u.metaSubprogramInfo.isExplicit = ds.isExplicit();
  meta->u.metaSubprogramInfo.isPrototyped = ds.isPrototyped();
  meta->u.metaSubprogramInfo.isOptimized = ds.isOptimized();
  meta->u.metaSubprogramInfo.filename = getCStrdup(ds.getFilename());
  meta->u.metaSubprogramInfo.directory = getCStrdup(ds.getDirectory());
  const Value *func = ds.getFunction();
  if(func)
    meta->u.metaSubprogramInfo.function = translateValue(m, func);
}

static void makeMetaGlobalVariable(CModule *m, const MDNode *md, CMeta *meta) {
  DIGlobalVariable dg(md);
  meta->u.metaGlobalInfo.context = translateMetadata(m, dg.getContext());
  meta->u.metaGlobalInfo.name = getCStrdup(dg.getName());
  meta->u.metaGlobalInfo.displayName = getCStrdup(dg.getDisplayName());
  meta->u.metaGlobalInfo.linkageName = getCStrdup(dg.getLinkageName());
  meta->u.metaGlobalInfo.lineNumber = dg.getLineNumber();
  meta->u.metaGlobalInfo.globalType = translateMetadata(m, dg.getType());
  meta->u.metaGlobalInfo.isLocalToUnit = dg.isLocalToUnit();
  meta->u.metaGlobalInfo.isDefinition = dg.isDefinition();
  const Value *global = dg.getConstant();
  if(global)
    meta->u.metaGlobalInfo.global = translateValue(m, global);
}

static void makeMetaFile(CModule *m, const MDNode *md, CMeta *meta) {
  DIFile df(md);
  meta->u.metaFileInfo.filename = getCStrdup(df.getFilename());
  meta->u.metaFileInfo.directory = getCStrdup(df.getDirectory());
}

static void makeMetaCompileUnit(CModule *m, const MDNode *md, CMeta *meta) {
  DICompileUnit dc(md);
  meta->u.metaCompileUnitInfo.language = dc.getLanguage();
  meta->u.metaCompileUnitInfo.filename = getCStrdup(dc.getFilename());
  meta->u.metaCompileUnitInfo.directory = getCStrdup(dc.getDirectory());
  meta->u.metaCompileUnitInfo.producer = getCStrdup(dc.getProducer());
#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 3
#else
  meta->u.metaCompileUnitInfo.isMain = dc.isMain();
#endif
  meta->u.metaCompileUnitInfo.isOptimized = dc.isOptimized();
  meta->u.metaCompileUnitInfo.flags = getCStrdup(dc.getFlags());
  meta->u.metaCompileUnitInfo.runtimeVersion = dc.getRunTimeVersion();
  meta->u.metaCompileUnitInfo.enumTypes = translateMetadata(m, dc.getEnumTypes());
  meta->u.metaCompileUnitInfo.retainedTypes = translateMetadata(m, dc.getRetainedTypes());
  meta->u.metaCompileUnitInfo.subprograms = translateMetadata(m, dc.getSubprograms());
  meta->u.metaCompileUnitInfo.globalVariables = translateMetadata(m, dc.getGlobalVariables());
}

static void makeMetaNamespace(CModule *m, const MDNode *md, CMeta *meta) {
  DINameSpace dn(md);
  meta->u.metaNamespaceInfo.context = translateMetadata(m, dn.getContext());
  meta->u.metaNamespaceInfo.name = getCStrdup(dn.getName());
  meta->u.metaNamespaceInfo.directory = getCStrdup(dn.getDirectory());
  meta->u.metaNamespaceInfo.filename = getCStrdup(dn.getFilename());
  meta->u.metaNamespaceInfo.lineNumber = dn.getLineNumber();
}

static void makeMetaLexicalBlock(CModule *m, const MDNode *md, CMeta *meta) {
  DILexicalBlock dl(md);
  meta->u.metaLexicalBlockInfo.context = translateMetadata(m, dl.getContext());
  meta->u.metaLexicalBlockInfo.lineNumber = dl.getLineNumber();
  meta->u.metaLexicalBlockInfo.columnNumber = dl.getColumnNumber();
  meta->u.metaLexicalBlockInfo.directory = getCStrdup(dl.getDirectory());
  meta->u.metaLexicalBlockInfo.filename = getCStrdup(dl.getFilename());
}

static void makeMetaSubrange(CModule *, const MDNode *md, CMeta *meta) {
  DISubrange ds(md);
  meta->u.metaSubrangeInfo.lo = ds.getLo();
  meta->u.metaSubrangeInfo.hi = getHiDISubrange(ds);
}

static void makeMetaEnumerator(CModule *, const MDNode *md, CMeta *meta) {
  DIEnumerator de(md);
  meta->u.metaEnumeratorInfo.enumName = getCStrdup(de.getName());
  meta->u.metaEnumeratorInfo.enumValue = de.getEnumValue();
}

static void makeMetaArray(CModule *m, const MDNode *md, CMeta *meta) {
  DIArray da(md);
  meta->u.metaArrayInfo.arrayLen = da.getNumElements();
  if(meta->u.metaArrayInfo.arrayLen == 0) return;

  meta->u.metaArrayInfo.arrayElts =
    (CMeta**)calloc(meta->u.metaArrayInfo.arrayLen, sizeof(CMeta*));
  for(int i = 0; i < meta->u.metaArrayInfo.arrayLen; ++i) {
    meta->u.metaArrayInfo.arrayElts[i] = translateMetadata(m, da.getElement(i));
  }
}

static void makeMetaTemplateTypeParameter(CModule *m, const MDNode *md, CMeta *meta) {
  DITemplateTypeParameter dt(md);
  meta->u.metaTemplateTypeInfo.context = translateMetadata(m, dt.getContext());
  meta->u.metaTemplateTypeInfo.name = getCStrdup(dt.getName());
  meta->u.metaTemplateTypeInfo.type = translateMetadata(m, dt.getType());
  meta->u.metaTemplateTypeInfo.filename = getCStrdup(dt.getFilename());
  meta->u.metaTemplateTypeInfo.directory = getCStrdup(dt.getDirectory());
  meta->u.metaTemplateTypeInfo.lineNumber = dt.getLineNumber();
  meta->u.metaTemplateTypeInfo.columnNumber = dt.getColumnNumber();
}

static void makeMetaTemplateValueParameter(CModule *m, const MDNode *md, CMeta *meta) {
  DITemplateValueParameter dt(md);
  meta->u.metaTemplateValueInfo.context = translateMetadata(m, dt.getContext());
  meta->u.metaTemplateValueInfo.name = getCStrdup(dt.getName());
  meta->u.metaTemplateValueInfo.type = translateMetadata(m, dt.getType());
  meta->u.metaTemplateValueInfo.value = dt.getValue();
  meta->u.metaTemplateValueInfo.filename = getCStrdup(dt.getFilename());
  meta->u.metaTemplateValueInfo.directory = getCStrdup(dt.getDirectory());
  meta->u.metaTemplateValueInfo.lineNumber = dt.getLineNumber();
  meta->u.metaTemplateValueInfo.columnNumber = dt.getColumnNumber();
}

// Treat source locations specially; keeping them in the general case
// was causing crashes that I never managed to track down.
static CMeta* translateSrcLoc(CModule *m, const DebugLoc& loc) {
  if(loc.isUnknown()) return NULL;

  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const DebugLoc*,CMeta*>::const_iterator it = pd->srcLocMap.find(&loc);
  if(it != pd->srcLocMap.end()) {
    return it->second;
  }
  CMeta *meta = (CMeta*)calloc(1, sizeof(CMeta));
  pd->srcLocMap[&loc] = meta;
  meta->metaTag = META_LOCATION;
  // There is no DWARF tag for these source locations.  Just use -1
  // and be sure not to try to convert it to a DWARF tag later.
  meta->tag = -1;

  makeMetaSrcLocation(m, loc, meta);

  return meta;
}

static CMeta* translateMetadata(CModule *m, const MDNode *md) {
  // I expect some metadata fields to be empty (e.g., templateParams).
  // Just propagate nulls.
  if(md == NULL) return NULL;

  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const MDNode*,CMeta*>::const_iterator it = pd->metaMap.find(md);
  if(it != pd->metaMap.end()) {
    return it->second;
  }
  CMeta *meta = (CMeta*)calloc(1, sizeof(CMeta));
  pd->metaMap[md] = meta;
  meta->metaTag = extractMetaTag(md);
  DIDescriptor desc(md);
  meta->tag = desc.getTag();

  switch(meta->metaTag) {
  case META_LOCATION: makeMetaLocation(m, md, meta); break;
  case META_DERIVEDTYPE: makeMetaDerivedType(m, md, meta); break;
  case META_COMPOSITETYPE: makeMetaCompositeType(m, md, meta); break;
  case META_BASICTYPE: makeMetaBasicType(m, md, meta); break;
  case META_VARIABLE: makeMetaVariable(m, md, meta); break;
  case META_SUBPROGRAM: makeMetaSubprogram(m, md, meta); break;
  case META_GLOBALVARIABLE: makeMetaGlobalVariable(m, md, meta); break;
  case META_COMPILEUNIT: makeMetaCompileUnit(m, md, meta); break;
  case META_NAMESPACE: makeMetaNamespace(m, md, meta); break;
  case META_LEXICALBLOCK: makeMetaLexicalBlock(m, md, meta); break;
  case META_SUBRANGE: makeMetaSubrange(m, md, meta); break;
  case META_ENUMERATOR: makeMetaEnumerator(m, md, meta); break;
//  case META_ARRAY: makeMetaArray(m, md, meta); break;
  case META_TEMPLATETYPEPARAMETER: makeMetaTemplateTypeParameter(m, md, meta); break;
  case META_TEMPLATEVALUEPARAMETER: makeMetaTemplateValueParameter(m, md, meta); break;
  case META_UNKNOWN:
  {
    // Just dump unknown metadata to a string... it might be more
    // appropriate to make a generic MDNode, but that is low priority.
    string msg;
    raw_string_ostream os(msg);
    os << "Unhandled metadata node type: ";
    md->print(os);

    meta->u.metaUnknownInfo.repr = getCStrdup(os);
    break;
  }
  }
  return meta;
}

static CMeta* translateMetadataArray(CModule *m, const MDNode *md) {
  // I expect some metadata fields to be empty (e.g., templateParams).
  // Just propagate nulls.
  if(md == NULL) return NULL;

  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const MDNode*,CMeta*>::const_iterator it = pd->metaMap.find(md);
  if(it != pd->metaMap.end()) {
    return it->second;
  }
  CMeta *meta = (CMeta*)calloc(1, sizeof(CMeta));
  pd->metaMap[md] = meta;
  meta->metaTag = META_ARRAY;
  meta->tag = 0;

  makeMetaArray(m, md, meta);

  return meta;
}

// The Type parameter would be const, except
// DataLayout::getTypeSizeInBits() is not const for some reason.
static CType* translateType(CModule *m, Type *t) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Type*,CType*>::const_iterator it = pd->typeMap.find(t);
  if(it != pd->typeMap.end())
    return it->second;

  CType *ret = (CType*)calloc(1, sizeof(CType));
  ret->typeTag = decodeTypeTag(t->getTypeID());
  ret->sizeInBytes = 0;
  if(t->isSized())
    ret->sizeInBytes = std::ceil(pd->dataLayout->getTypeSizeInBits(t) / 8.0);

  // Need to put this in the table before making any recursive calls,
  // otherwise it might never terminate.
  pd->typeMap[t] = ret;

  switch(ret->typeTag) {
    // Primitives don't require any work
  case TYPE_VOID:
  case TYPE_FLOAT:
  case TYPE_DOUBLE:
  case TYPE_X86_FP80:
  case TYPE_FP128:
  case TYPE_PPC_FP128:
  case TYPE_LABEL:
  case TYPE_METADATA:
  case TYPE_X86_MMX:
    break;

  case TYPE_INTEGER:
    ret->size = t->getPrimitiveSizeInBits();
    break;

  case TYPE_FUNCTION:
  {
    const FunctionType *ft = dyn_cast<const FunctionType>(t);
    ret->isVarArg = ft->isVarArg();
    ret->innerType = translateType(m, ft->getReturnType());
    ret->typeListLen = ft->getNumParams();
    ret->typeList = (CType**)calloc(ret->typeListLen, sizeof(CType*));
    for(int i = 0; i < ret->typeListLen; ++i) {
      ret->typeList[i] = translateType(m, ft->getParamType(i));
    }

    break;
  }

  case TYPE_STRUCT:
  {
    const StructType *st = dyn_cast<const StructType>(t);
    if(st->hasName())
      ret->name = getCStrdup(st->getName());
    else
      ret->name = NULL;

    ret->isPacked = st->isPacked();
    ret->typeListLen = st->getNumElements();
    ret->typeList = (CType**)calloc(ret->typeListLen, sizeof(CType*));
    for(int i = 0; i < ret->typeListLen; ++i) {
      ret->typeList[i] = translateType(m, st->getElementType(i));
    }
    break;
  }

  case TYPE_ARRAY:
  {
    const ArrayType *at = dyn_cast<const ArrayType>(t);
    ret->size = at->getNumElements();
    ret->innerType = translateType(m, at->getElementType());
    break;
  }

  case TYPE_POINTER:
  {
    const PointerType *pt = dyn_cast<const PointerType>(t);
    ret->innerType = translateType(m, pt->getElementType());
    ret->addrSpace = pt->getAddressSpace();
    break;
  }

  case TYPE_VECTOR:
  {
    const VectorType *vt = dyn_cast<const VectorType>(t);
    ret->size = vt->getNumElements();
    ret->innerType = translateType(m, vt->getElementType());
    break;
  }
  }

  return ret;
}

static CValue* translateGlobalAlias(CModule *m, const GlobalAlias *ga) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(ga);
  if(it != pd->valueMap.end())
    return it->second;

  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[ga] = v;

  v->valueTag = VAL_ALIAS;
  v->valueType = translateType(m, ga->getType());
  v->name = getCStrdup(ga->getName());

  CGlobalInfo *gi = (CGlobalInfo*)calloc(1, sizeof(CGlobalInfo));
  v->data = (void*)gi;

  gi->isExternal = ga->isDeclaration();
  gi->alignment = ga->getAlignment();
  gi->visibility = decodeVisibility(ga);
  gi->linkage = decodeLinkage(ga);
  if(ga->hasSection())
    gi->section = getCStrdup(ga->getSection());

  gi->aliasee = translateConstant(m, ga->getAliasee());

  return v;
}

static CValue* translateArgument(CModule *m, const Argument *a) {
  PrivateData *pd = (PrivateData*)m->privateData;
  // Arguments are translated before instructions, so we don't really
  // need to check to see if the argument exists already (it won't).
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[a] = v;

  v->valueTag = VAL_ARGUMENT;
  v->valueType = translateType(m, a->getType());
  v->name = getCStrdup(a->getName());

  // Metadata will be attached as instructions are processed (calls to
  // the Debug intrinsics)

  CArgumentInfo *ai = (CArgumentInfo*)calloc(1, sizeof(CArgumentInfo));
  v->data = (void*)ai;

  ai->hasSRet = a->hasStructRetAttr();
  ai->hasByVal = a->hasByValAttr();
  ai->hasNest = a->hasNestAttr();
  ai->hasNoAlias = a->hasNoAliasAttr();
  ai->hasNoCapture = a->hasNoCaptureAttr();

  return v;
}

static void buildRetInst(CModule *m, CValue *v, const ReturnInst *ri) {
  v->valueTag = VAL_RETINST;
  v->valueType = translateType(m, ri->getType());
  // Never has a name

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  if(Value* rv = ri->getReturnValue())
  {
    ii->numOperands = 1;
    ii->operands = (CValue**)calloc(1, sizeof(CValue*));
    ii->operands[0] = translateValue(m, rv);
  }

  // Otherwise, the data fields default to 0 as intended
}

static void buildSimpleInst(CModule *m, CValue *v, ValueTag t, const Instruction *inst) {
  v->valueTag = t;
  v->valueType = translateType(m, inst->getType());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = inst->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));

  for(size_t i = 0; i < inst->getNumOperands(); ++i) {
    ii->operands[i] = translateValue(m, inst->getOperand(i));
  }
}

static void buildBinaryInst(CModule *m, CValue *v, ValueTag t, const Instruction *inst) {
  const BinaryOperator *bi = dyn_cast<const BinaryOperator>(inst);
  assert(bi);

  v->valueTag = t;
  v->valueType = translateType(m, bi->getType());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = inst->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, inst->getOperand(i));
  }

  ii->flags = ArithNone;
  // If the operator isn't *really* an overflowing binary operator,
  // calling hasNoUnsignedWrap causes an assertion failure.  Guard
  // against leaky abstractions here.
  if(isa<const OverflowingBinaryOperator>(bi))
  {
    if(bi->hasNoUnsignedWrap() && bi->hasNoSignedWrap())
      ii->flags = ArithBoth;
    else if(bi->hasNoUnsignedWrap())
      ii->flags = ArithNUW;
    else if(bi->hasNoSignedWrap())
      ii->flags = ArithNSW;
  }
}

static void buildInvokeInst(CModule *m, CValue *v, const InvokeInst *ii) {
  v->valueTag = VAL_INVOKEINST;
  v->valueType = translateType(m, ii->getType());
  if(ii->hasName())
    v->name = getCStrdup(ii->getName());

  CCallInfo *ci = (CCallInfo*)calloc(1, sizeof(CCallInfo));
  v->data = (void*)ci;

  ci->calledValue = translateValue(m, ii->getCalledValue());
  ci->callingConvention = decodeCallingConvention(ii->getCallingConv());
  ci->hasSRet = ii->hasStructRetAttr();
  ci->normalDest = translateBasicBlock(m, ii->getNormalDest());
  ci->unwindDest = translateBasicBlock(m, ii->getUnwindDest());
  ci->argListLen = ii->getNumArgOperands();
  ci->arguments = (CValue**)calloc(ci->argListLen, sizeof(CValue*));

  for(unsigned i = 0; i < ii->getNumArgOperands(); ++i) {
    ci->arguments[i] = translateValue(m, ii->getArgOperand(i));
  }
}

static bool buildCallInst(CModule *m, CValue *v, const CallInst *ii) {

  /*
    I wanted to use the Intrinsics directly here, but it didn't seem
    to work.  I didn't look into the matter too closely, but these
    instructions insisted that they were simply calls and I didn't
    know how to convert them to intrinsics.
   */

  if(ii->getCalledValue()->getName().str() == "llvm.dbg.declare") {
    CValue *addr = NULL;
    if(const MDNode *addrWrapper = dyn_cast<const MDNode>(ii->getArgOperand(0))) {
      const Value* realAddr = addrWrapper->getOperand(0);
      // If the alloca was completely eliminated, this debug
      // information can't be attached to anything as far as I can
      // tell.
      if(realAddr == NULL || dyn_cast<const ConstantPointerNull>(realAddr))
        return false;

      addr = translateValue(m, realAddr);
    }
    CMeta *md = NULL;
    if(const MDNode *variableVal = dyn_cast<const MDNode>(ii->getArgOperand(1))) {
      md = translateMetadata(m, variableVal);
    }

    if(!md) return false;

    // CValue *addr = translateValue(m, di->getAddress());
    // CMeta *md = translateMetadata(m, di->getVariable());

    // It should be the case that there should be exactly one of these
    // per alloca, and allocas should not have location info of their
    // own.
    if(addr->md) {
      return false;
    } // throw "Address of MD already has metadata";

    addr->numMetadata = 1;
    addr->md = (CMeta**)calloc(1, sizeof(CMeta*));
    addr->md[0] = md;

    return false;
  }

  if(ii->getCalledValue()->getName().str() == "llvm.dbg.value") {
    // In this case, we could see llvm.dbg.value "calls" for updates
    // to parameters.  We should only attach the *first* one we
    // encounter, which will be the one describing parameters or
    // locals.  This is an important case when the bitcode has been
    // run through the mem2reg optimization pass and most allocas are
    // eliminated.  I don't care about when the value of a variable
    // changes (that is apparent from the instruction stream).  I
    // could be convinced to change the behavior here if there is a
    // good use case.

    CValue *val = NULL;
    if(const MDNode *valWrapper = dyn_cast<const MDNode>(ii->getArgOperand(0))) {
      const Value *realAddr = valWrapper->getOperand(0);
      if(realAddr == NULL || dyn_cast<const ConstantPointerNull>(realAddr))
        return false;

      val = translateValue(m, realAddr);
    }

    if(val->numMetadata == 0) {
      CMeta *md = NULL;
      if(const MDNode *variable = dyn_cast<const MDNode>(ii->getArgOperand(2))) {
        md = translateMetadata(m, variable);
      }

      if(!md) return false;

      val->numMetadata = 1;
      val->md = (CMeta**)calloc(1, sizeof(CMeta*));
      val->md[0] = md;
    }

    return false;
  }

  v->valueTag = VAL_CALLINST;
  v->valueType = translateType(m, ii->getType());
  if(ii->hasName())
    v->name = getCStrdup(ii->getName());

  CCallInfo *ci = (CCallInfo*)calloc(1, sizeof(CCallInfo));
  v->data = (void*)ci;

  ci->calledValue = translateValue(m, ii->getCalledValue());
  ci->callingConvention = decodeCallingConvention(ii->getCallingConv());
  ci->hasSRet = ii->hasStructRetAttr();
  ci->isTail = ii->isTailCall();
  ci->argListLen = ii->getNumArgOperands();
  ci->arguments = (CValue**)calloc(ci->argListLen, sizeof(CValue*));

  for(unsigned i = 0; i < ii->getNumArgOperands(); ++i) {
    ci->arguments[i] = translateValue(m, ii->getArgOperand(i));
  }

  return true;
}

static void buildAllocaInst(CModule *m, CValue *v, const AllocaInst *ai) {
  v->valueTag = VAL_ALLOCAINST;
  v->valueType = translateType(m, ai->getType());
  if(ai->hasName())
    v->name = getCStrdup(ai->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = ai->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, ai->getOperand(i));
  }

  ii->align = ai->getAlignment();
}

static void buildLoadInst(CModule *m, CValue *v, const LoadInst *li) {
  v->valueTag = VAL_LOADINST;
  v->valueType = translateType(m, li->getType());
  if(li->hasName())
    v->name = getCStrdup(li->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = li->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, li->getOperand(i));
  }

  ii->isVolatile = li->isVolatile();
  ii->align = li->getAlignment();
  ii->addrSpace = li->getPointerAddressSpace();
}

static void buildStoreInst(CModule *m, CValue *v, const StoreInst *si) {
  v->valueTag = VAL_STOREINST;
  v->valueType = translateType(m, si->getType());
  if(si->hasName())
    v->name = getCStrdup(si->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;


  ii->numOperands = si->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, si->getOperand(i));
  }

  ii->addrSpace = si->getPointerAddressSpace();
  ii->align = si->getAlignment();
  ii->isVolatile = si->isVolatile();
}

static void buildGEPInst(CModule *m, CValue *v, const GetElementPtrInst *gi) {
  v->valueTag = VAL_GETELEMENTPTRINST;
  v->valueType = translateType(m, gi->getType());
  if(gi->hasName())
    v->name = getCStrdup(gi->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;


  ii->numOperands = gi->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, gi->getOperand(i));
  }

  ii->inBounds = gi->isInBounds();
  ii->addrSpace = gi->getPointerAddressSpace();
}

static void buildCastInst(CModule *m, CValue *v, ValueTag t, const Instruction *inst) {
  const CastInst *ci = dyn_cast<const CastInst>(inst);
  v->valueTag = t;
  v->valueType = translateType(m, ci->getType());
  if(ci->hasName())
    v->name = getCStrdup(ci->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;


  ii->numOperands = ci->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, ci->getOperand(i));
  }
}

static void buildCmpInst(CModule *m, CValue *v, ValueTag t, const Instruction *inst) {
  const CmpInst *ci = dyn_cast<const CmpInst>(inst);
  v->valueTag = t;
  v->valueType = translateType(m, ci->getType());
  if(ci->hasName())
    v->name = getCStrdup(ci->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = ci->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, ci->getOperand(i));
  }

  ii->cmpPred = decodePredicate(ci->getPredicate());
}

static void buildPHINode(CModule *m, CValue *v, const PHINode* n) {
  v->valueTag = VAL_PHINODE;
  v->valueType = translateType(m, n->getType());
  if(n->hasName())
    v->name = getCStrdup(n->getName());

  CPHIInfo *pi = (CPHIInfo*)calloc(1, sizeof(CPHIInfo));
  v->data = (void*)pi;

  pi->numIncomingValues = n->getNumIncomingValues();
  pi->incomingValues = (CValue**)calloc(pi->numIncomingValues, sizeof(CValue*));
  pi->valueBlocks = (CValue**)calloc(pi->numIncomingValues, sizeof(CValue*));

  for(int i = 0; i < pi->numIncomingValues; ++i) {
    pi->incomingValues[i] = translateValue(m, n->getIncomingValue(i));
    pi->valueBlocks[i] = translateValue(m, n->getIncomingBlock(i));
  }
}

static void buildAtomicRMWInst(CModule *m, CValue *v, const AtomicRMWInst *I) {
  v->valueTag = VAL_ATOMICRMWINST;
  v->valueType = translateType(m, I->getType());
  // Should not have a name

  CAtomicInfo *ai = (CAtomicInfo*)calloc(1, sizeof(CAtomicInfo));
  v->data = (void*)ai;

  ai->ordering = decodeOrdering(I->getOrdering());
  ai->scope = decodeSynchScope(I->getSynchScope());
  ai->operation = decodeAtomicOp(I->getOperation());
  ai->isVolatile = I->isVolatile();
  ai->addrSpace = I->getPointerAddressSpace();
  ai->pointerOperand = translateValue(m, I->getPointerOperand());
  ai->valueOperand = translateValue(m, I->getValOperand());
}

static void buildAtomicCmpXchgInst(CModule *m, CValue *v, const AtomicCmpXchgInst *I) {
  v->valueTag = VAL_ATOMICCMPXCHGINST;
  v->valueType = translateType(m, I->getType());
  // Should not have a name

  CAtomicInfo *ai = (CAtomicInfo*)calloc(1, sizeof(CAtomicInfo));
  v->data = (void*)ai;

  ai->ordering = decodeOrdering(I->getOrdering());
  ai->scope = decodeSynchScope(I->getSynchScope());
  ai->isVolatile = I->isVolatile();
  ai->addrSpace = I->getPointerAddressSpace();
  ai->pointerOperand = translateValue(m, I->getPointerOperand());
  ai->compareOperand = translateValue(m, I->getCompareOperand());
  ai->valueOperand = translateValue(m, I->getNewValOperand());
}

static void buildFenceInst(CModule *m, CValue *v, const FenceInst *I) {
  v->valueTag = VAL_FENCEINST;
  v->valueType = translateType(m, I->getType());
  // Should not have a name

  CAtomicInfo *ai = (CAtomicInfo*)calloc(1, sizeof(CAtomicInfo));
  v->data = (void*)ai;

  ai->ordering = decodeOrdering(I->getOrdering());
  ai->scope = decodeSynchScope(I->getSynchScope());
}

static void buildVAArgInst(CModule *m, CValue *v, const VAArgInst *vi) {
  v->valueTag = VAL_VAARGINST;
  v->valueType = translateType(m, vi->getType());
  if(vi->hasName())
    v->name = getCStrdup(vi->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = vi->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, vi->getOperand(i));
  }
}

static void buildLandingPadInst(CModule *m, CValue *v, const LandingPadInst *li) {
  v->valueTag = VAL_LANDINGPADINST;
  v->valueType = translateType(m, li->getType());

  if(li->hasName())
    v->name = getCStrdup(li->getName());

  CLandingPadInfo *ii = (CLandingPadInfo*)calloc(1, sizeof(CLandingPadInfo));
  v->data = (void*)ii;

  ii->personality = translateValue(m, li->getPersonalityFn());
  ii->isCleanup = li->isCleanup();
  ii->numClauses = li->getNumClauses();
  ii->clauses = (CValue**)calloc(ii->numClauses, sizeof(CValue*));
  ii->clauseTypes = (LandingPadClause*)calloc(ii->numClauses, sizeof(LandingPadClause));

  for(int i = 0; i < ii->numClauses; ++i) {
    ii->clauses[i] = translateValue(m, li->getClause(i));
    ii->clauseTypes[i] = li->isCatch(i) ? LPCatch : LPFilter;
  }
}

static void buildExtractValueInst(CModule *m, CValue *v, const ExtractValueInst *ei) {
  v->valueTag = VAL_EXTRACTVALUEINST;
  v->valueType = translateType(m, ei->getType());
  if(ei->hasName())
    v->name = getCStrdup(ei->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;


  ii->numOperands = ei->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, ei->getOperand(i));
  }

  ii->numIndices = ei->getNumIndices();
  ii->indices = (int*)calloc(ii->numIndices, sizeof(int));

  std::copy(ei->idx_begin(), ei->idx_end(), ii->indices);
}

static void buildInsertValueInst(CModule *m, CValue *v, const InsertValueInst *ei) {
  v->valueTag = VAL_INSERTVALUEINST;
  v->valueType = translateType(m, ei->getType());
  if(ei->hasName())
    v->name = getCStrdup(ei->getName());

  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ii;

  ii->numOperands = ei->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));
  for(int i = 0; i < ii->numOperands; ++i) {
    ii->operands[i] = translateValue(m, ei->getOperand(i));
  }

  ii->numIndices = ei->getNumIndices();
  ii->indices = (int*)calloc(ii->numIndices, sizeof(int));

  std::copy(ei->idx_begin(), ei->idx_end(), ii->indices);
}

namespace {
  class TinyVector : public SmallVectorImpl<std::pair<unsigned, MDNode*> > {
  public:
    TinyVector(unsigned int i)
    :SmallVectorImpl<std::pair<unsigned, MDNode*> >(i)
    {
    }
  };
}

static CValue* translateInstruction(CModule *m, const Instruction *i) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(i);
  if(it != pd->valueMap.end())
    return it->second;

  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[i] = v;

  TinyVector md(0);
  i->getAllMetadataOtherThanDebugLoc(md);

  v->numMetadata = md.size();
  v->md = (CMeta**)calloc(v->numMetadata, sizeof(CMeta*));
  for(int ix = 0; ix < v->numMetadata; ++ix) {
    v->md[ix] = translateMetadata(m, md[ix].second);
  }
  if(pd->includeLocs)
    v->srcLoc = translateSrcLoc(m, i->getDebugLoc());

  switch(i->getOpcode()) {
    // Terminator instructions
  case Instruction::Ret:
    buildRetInst(m, v, dyn_cast<const ReturnInst>(i));
    break;
  case Instruction::Br:
    buildSimpleInst(m, v, VAL_BRANCHINST, i);
    break;
  case Instruction::Switch:
    buildSimpleInst(m, v, VAL_SWITCHINST, i);
    break;
  case Instruction::IndirectBr:
    buildSimpleInst(m, v, VAL_INDIRECTBRINST, i);
    break;
  case Instruction::Invoke:
    buildInvokeInst(m, v, dyn_cast<const InvokeInst>(i));
    break;
  case Instruction::Unreachable:
    buildSimpleInst(m, v, VAL_UNREACHABLEINST, i);
    break;

    // Binary instructions
  case Instruction::Add:
    buildBinaryInst(m, v, VAL_ADDINST, i);
    break;
  case Instruction::FAdd:
    buildBinaryInst(m, v, VAL_FADDINST, i);
    break;
  case Instruction::Sub:
    buildBinaryInst(m, v, VAL_SUBINST, i);
    break;
  case Instruction::FSub:
    buildBinaryInst(m, v, VAL_FSUBINST, i);
    break;
  case Instruction::Mul:
    buildBinaryInst(m, v, VAL_MULINST, i);
    break;
  case Instruction::FMul:
    buildBinaryInst(m, v, VAL_FMULINST, i);
    break;
  case Instruction::UDiv:
    buildBinaryInst(m, v, VAL_UDIVINST, i);
    break;
  case Instruction::SDiv:
    buildBinaryInst(m, v, VAL_SDIVINST, i);
    break;
  case Instruction::FDiv:
    buildBinaryInst(m, v, VAL_FDIVINST, i);
    break;
  case Instruction::URem:
    buildBinaryInst(m, v, VAL_UREMINST, i);
    break;
  case Instruction::SRem:
    buildBinaryInst(m, v, VAL_SREMINST, i);
    break;
  case Instruction::FRem:
    buildBinaryInst(m, v, VAL_FREMINST, i);
    break;
  case Instruction::Shl:
    buildBinaryInst(m, v, VAL_SHLINST, i);
    break;
  case Instruction::LShr:
    buildBinaryInst(m, v, VAL_LSHRINST, i);
    break;
  case Instruction::AShr:
    buildBinaryInst(m, v, VAL_ASHRINST, i);
    break;
  case Instruction::And:
    buildBinaryInst(m, v, VAL_ANDINST, i);
    break;
  case Instruction::Or:
    buildBinaryInst(m, v, VAL_ORINST, i);
    break;
  case Instruction::Xor:
    buildBinaryInst(m, v, VAL_XORINST, i);
    break;

    // Memory operations
  case Instruction::Alloca:
    buildAllocaInst(m, v, dyn_cast<const AllocaInst>(i));
    break;

  case Instruction::Load:
    buildLoadInst(m, v, dyn_cast<const LoadInst>(i));
    break;

  case Instruction::Store:
    buildStoreInst(m, v, dyn_cast<const StoreInst>(i));
    break;

  case Instruction::GetElementPtr:
    buildGEPInst(m, v, dyn_cast<const GetElementPtrInst>(i));
    break;

  case Instruction::Fence:
    buildFenceInst(m, v, dyn_cast<const FenceInst>(i));
    break;

  case Instruction::AtomicRMW:
    buildAtomicRMWInst(m, v, dyn_cast<const AtomicRMWInst>(i));
    break;

  case Instruction::AtomicCmpXchg:
    buildAtomicCmpXchgInst(m, v, dyn_cast<const AtomicCmpXchgInst>(i));
    break;

    // Casts
  case Instruction::Trunc:
    buildCastInst(m, v, VAL_TRUNCINST, i);
    break;

  case Instruction::ZExt:
    buildCastInst(m, v, VAL_ZEXTINST, i);
    break;

  case Instruction::SExt:
    buildCastInst(m, v, VAL_SEXTINST, i);
    break;

  case Instruction::FPToUI:
    buildCastInst(m, v, VAL_FPTOUIINST, i);
    break;

  case Instruction::FPToSI:
    buildCastInst(m, v, VAL_FPTOSIINST, i);
    break;

  case Instruction::UIToFP:
    buildCastInst(m, v, VAL_UITOFPINST, i);
    break;

  case Instruction::SIToFP:
    buildCastInst(m, v, VAL_SITOFPINST, i);
    break;

  case Instruction::FPTrunc:
    buildCastInst(m, v, VAL_FPTRUNCINST, i);
    break;

  case Instruction::FPExt:
    buildCastInst(m, v, VAL_FPEXTINST, i);
    break;

  case Instruction::PtrToInt:
    buildCastInst(m, v, VAL_PTRTOINTINST, i);
    break;

  case Instruction::IntToPtr:
    buildCastInst(m, v, VAL_INTTOPTRINST, i);
    break;

  case Instruction::BitCast:
    buildCastInst(m, v, VAL_BITCASTINST, i);
    break;

    // Other instructions
  case Instruction::ICmp:
    buildCmpInst(m, v, VAL_ICMPINST, i);
    break;

  case Instruction::FCmp:
    buildCmpInst(m, v, VAL_FCMPINST, i);
    break;

  case Instruction::PHI:
    buildPHINode(m, v, dyn_cast<const PHINode>(i));
    break;

  case Instruction::Call:
    // If this is a call to llvm.dbg.*, return NULL and delete what we
    // made so far.  We don't want these in the instruction stream
    // (the builder will attach the debug information to the relevant
    // entities)
    if(!buildCallInst(m, v, dyn_cast<const CallInst>(i))) {
      pd->valueMap.erase(i);
      free(v);
      return NULL;
    }
    break;

  case Instruction::Select:
    buildSimpleInst(m, v, VAL_SELECTINST, i);
    break;

  case Instruction::Resume:
    buildSimpleInst(m, v, VAL_RESUMEINST, i);
    break;

  case Instruction::VAArg:
    buildVAArgInst(m, v, dyn_cast<const VAArgInst>(i));
    break;

  case Instruction::ExtractElement:
    buildSimpleInst(m, v, VAL_EXTRACTELEMENTINST, i);
    break;

  case Instruction::InsertElement:
    buildSimpleInst(m, v, VAL_INSERTELEMENTINST, i);
    break;

  case Instruction::ShuffleVector:
    buildSimpleInst(m, v, VAL_SHUFFLEVECTORINST, i);
    break;

  case Instruction::ExtractValue:
    buildExtractValueInst(m, v, dyn_cast<const ExtractValueInst>(i));
    break;

  case Instruction::InsertValue:
    buildInsertValueInst(m, v, dyn_cast<const InsertValueInst>(i));
    break;

  case Instruction::LandingPad:
    buildLandingPadInst(m, v, dyn_cast<const LandingPadInst>(i));
    break;

  default:
  {
    ostringstream os;
    os << "Unhandled instruction type: " << i->getOpcode();
    throw os.str();
  }
  }

  return v;
}

static CValue* translateBasicBlock(CModule *m, const BasicBlock *bb) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(bb);
  if(it != pd->valueMap.end())
    return it->second;

  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[bb] = v;

  v->valueTag = VAL_BASICBLOCK;
  v->valueType = translateType(m, bb->getType());
  if(bb->hasName())
    v->name = getCStrdup(bb->getName());

  // No metadata for these

  CBasicBlockInfo* bbi = (CBasicBlockInfo*)calloc(1, sizeof(CBasicBlockInfo));
  v->data = (void*)bbi;

  bbi->blockLen = bb->size();
  bbi->instructions = (CValue**)calloc(bbi->blockLen, sizeof(CValue*));

  int idx = 0;
  for(BasicBlock::const_iterator it = bb->begin(),
        ed = bb->end(); it != ed; ++it)
  {
    CValue *tr = translateInstruction(m, &*it);
    if(!tr) {
      // This was a metadata call, so do not insert it into the
      // instruction stream
      --bbi->blockLen;
      continue;
    }

    bbi->instructions[idx++] = tr;
  }

  return v;
}

static CValue* translateFunction(CModule *m, const Function *f) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(f);
  if(it != pd->valueMap.end())
    return it->second;

  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[f] = v;

  v->valueTag = VAL_FUNCTION;
  v->valueType = translateType(m, f->getFunctionType());
  v->name = getCStrdup(f->getName());

  CFunctionInfo *fi = (CFunctionInfo*)calloc(1, sizeof(CFunctionInfo));
  v->data = (void*)fi;

  if(f->hasSection())
    fi->section = getCStrdup(f->getSection());

  fi->visibility = decodeVisibility(f);
  fi->linkage = decodeLinkage(f);
  fi->isExternal = f->isDeclaration();
  fi->callingConvention = decodeCallingConvention(f->getCallingConv());
  fi->isVarArg = f->isVarArg();
  if(f->hasGC())
    fi->gcName = getCStrdup(f->getGC());

  fi->argListLen = f->arg_size();
  fi->arguments = (CValue**)calloc(fi->argListLen, sizeof(CValue*));
  int idx = 0;
  for(Function::const_arg_iterator it = f->arg_begin(),
        ed = f->arg_end(); it != ed; ++it)
  {
    fi->arguments[idx++] = translateArgument(m, &*it);
  }

  fi->blockListLen = f->size();
  fi->body = (CValue**)calloc(fi->blockListLen, sizeof(CValue*));
  idx = 0;
  for(Function::const_iterator it = f->begin(),
        ed = f->end(); it != ed; ++it)
  {
    fi->body[idx++] = translateBasicBlock(m, &*it);
  }

  return v;
}

static CValue* translateGlobalVariable(CModule *m, const GlobalVariable *gv) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(gv);
  if(it != pd->valueMap.end())
    return it->second;

  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[gv] = v;

  v->valueTag = VAL_GLOBALVARIABLE;
  v->valueType = translateType(m, gv->getType());
  if(gv->hasName())
    v->name = getCStrdup(gv->getName());

  CGlobalInfo *gi = (CGlobalInfo*)calloc(1, sizeof(CGlobalInfo));
  v->data = (void*)gi;

  if(gv->hasSection())
    gi->section = getCStrdup(gv->getSection());

  gi->visibility = decodeVisibility(gv);
  gi->linkage = decodeLinkage(gv);
  gi->isExternal = gv->isDeclaration();
  gi->isThreadLocal = gv->isThreadLocal();
  gi->isConstant = gv->isConstant();

  if(gv->hasInitializer())
    gi->initializer = translateConstant(m, gv->getInitializer());

  return v;
}

static CValue* translateInlineAsm(CModule *m, const InlineAsm* a) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[a] = v;

  v->valueTag = VAL_INLINEASM;
  v->valueType = translateType(m, a->getType());
  if(a->hasName())
    v->name = getCStrdup(a->getName());

  CInlineAsmInfo *ii = (CInlineAsmInfo*)calloc(1, sizeof(CInlineAsmInfo));
  v->data = (void*)ii;

  ii->asmString = getCStrdup(a->getAsmString());
  ii->constraintString = getCStrdup(a->getConstraintString());

  return v;
}

static CValue* translateGlobalValue(CModule *m, const GlobalValue *gv) {
  if(const Function *f = dyn_cast<const Function>(gv)) {
    return translateFunction(m, f);
  }

  if(const GlobalVariable *v = dyn_cast<const GlobalVariable>(gv)) {
    return translateGlobalVariable(m, v);
  }

  if(const GlobalAlias *a = dyn_cast<const GlobalAlias>(gv)) {
    return translateGlobalAlias(m, a);
  }

  string msg;
  raw_string_ostream os(msg);
  os << "Non-global constant: ";
  gv->print(os);
  throw os.str();
}

static CValue* translateEmptyConstant(CModule *m, ValueTag t, const Constant *p) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[p] = v;

  v->valueTag = t;
  v->valueType = translateType(m, p->getType());

  // No data or metadata

  return v;
}

static CValue* translateConstantInt(CModule *m, const ConstantInt* i) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[i] = v;

  v->valueTag = VAL_CONSTANTINT;
  v->valueType = translateType(m, i->getType());

  // No name

  CConstInt *d = (CConstInt*)calloc(1, sizeof(CConstInt));
  v->data = (void*)d;

  const APInt& apint = i->getValue();
  d->hugeVal = NULL;
  if(apint.getMinSignedBits() <= 64)
    d->val = i->getSExtValue();
  else
    d->hugeVal = getCStrdup(apint.toString(10, true));
  return v;
}

static CValue* translateConstantFP(CModule *m, const ConstantFP *fp) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[fp] = v;

  v->valueTag = VAL_CONSTANTFP;
  v->valueType = translateType(m, fp->getType());

  // No name

  CConstFP *d = (CConstFP*)calloc(1, sizeof(CConstFP));
  v->data = (void*)d;

  APFloat apf = fp->getValueAPF();
  bool b;
  apf.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &b);
  d->val = apf.convertToDouble();

  return v;
}

static CValue* translateBlockAddress(CModule *m, const BlockAddress *ba) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[ba] = v;

  v->valueTag = VAL_BLOCKADDRESS;
  v->valueType = translateType(m, ba->getType());
  if(ba->hasName())
    v->name = getCStrdup(ba->getName());

  CBlockAddrInfo *i = (CBlockAddrInfo*)calloc(1, sizeof(CBlockAddrInfo));
  v->data = (void*)i;

  i->func = translateValue(m, ba->getFunction());
  i->block = translateValue(m, ba->getBasicBlock());

  return v;
}

static CValue* translateConstantAggregate(CModule *m, ValueTag t, const Constant *ca) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[ca] = v;

  v->valueTag = t;
  v->valueType = translateType(m, ca->getType());
  if(ca->hasName())
    v->name = getCStrdup(ca->getName());

  CConstAggregate *a = (CConstAggregate*)calloc(1, sizeof(CConstAggregate));
  v->data = (void*)a;

  a->numElements = ca->getNumOperands();
  a->constants = (CValue**)calloc(a->numElements, sizeof(CValue*));

  int idx = 0;
  for(User::const_op_iterator it = ca->op_begin(),
        ed = ca->op_end(); it != ed; ++it)
  {
    a->constants[idx++] = translateValue(m, it->get());
  }

  return v;
}

#if defined(LLVM_VERSION_MAJOR)
static CValue* translateConstantData(CModule *m, const ConstantDataSequential *cd) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[cd] = v;

  v->valueTag = VAL_CONSTANTARRAY;
  v->valueType = translateType(m, cd->getType());
  if(cd->hasName())
    v->name = getCStrdup(cd->getName());

  CConstAggregate *a = (CConstAggregate*)calloc(1, sizeof(CConstAggregate));
  v->data = (void*)a;

  a->numElements = cd->getNumElements();
  a->constants = (CValue**)calloc(a->numElements, sizeof(CValue*));

  for(int idx = 0; idx < a->numElements; ++idx) {
    a->constants[idx] = translateConstant(m, cd->getElementAsConstant(idx));
  }

  return v;
}
#endif // LLVM_VERSION_MAJOR

static CValue* translateConstantExpr(CModule *m, const ConstantExpr *ce) {
  PrivateData *pd = (PrivateData*)m->privateData;
  CValue *v = (CValue*)calloc(1, sizeof(CValue));
  pd->valueMap[ce] = v;

  v->valueTag = VAL_CONSTANTEXPR;
  v->valueType = translateType(m, ce->getType());
  if(ce->hasName())
    v->name = getCStrdup(ce->getName());

  CConstExprInfo *ci = (CConstExprInfo*)calloc(1, sizeof(CConstExprInfo));
  CInstructionInfo *ii = (CInstructionInfo*)calloc(1, sizeof(CInstructionInfo));
  v->data = (void*)ci;
  ci->ii = ii;

  ci->instrType = decodeOpcode(ce->getOpcode());
  ii->numOperands = ce->getNumOperands();
  ii->operands = (CValue**)calloc(ii->numOperands, sizeof(CValue*));

  int idx = 0;
  for(User::const_op_iterator it = ce->op_begin(),
        ed = ce->op_end(); it != ed; ++it)
  {
    ii->operands[idx++] = translateValue(m, it->get());
  }

  if(ce->isCompare()) {
    ii->cmpPred = decodePredicate((CmpInst::Predicate)ce->getPredicate());
  }
  else if(ce->hasIndices()) {
    ii->numIndices = ce->getIndices().size();
    ii->indices = (int*)calloc(ii->numIndices, sizeof(int));
    std::copy(ce->getIndices().begin(), ce->getIndices().end(), ii->indices);
  }

  return v;
}

static CValue* translateConstant(CModule *m, const Constant *c) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(c);
  if(it != pd->valueMap.end())
    return it->second;

  // Order these in order of frequency
  if(const ConstantInt *ci = dyn_cast<const ConstantInt>(c)) {
    return translateConstantInt(m, ci);
  }

  if(const ConstantPointerNull *pn = dyn_cast<const ConstantPointerNull>(c)) {
    return translateEmptyConstant(m, VAL_CONSTANTPOINTERNULL, pn);
  }

  if(const ConstantExpr *ce = dyn_cast<const ConstantExpr>(c)) {
    return translateConstantExpr(m, ce);
  }

  if(const GlobalValue *gv = dyn_cast<const GlobalValue>(c)) {
    return translateGlobalValue(m, gv);
  }

  if(const ConstantArray *ca = dyn_cast<const ConstantArray>(c)) {
    return translateConstantAggregate(m, VAL_CONSTANTARRAY, ca);
  }
#if defined(LLVM_VERSION_MAJOR)
  // The ConstantDataSequential type was introduced with LLVM 3.1 (3.0
  // did not define LLVM_VERSION_*)
  if(const ConstantDataSequential *cd = dyn_cast<const ConstantDataSequential>(c)) {
    return translateConstantData(m, cd);
  }
#endif
  if(const ConstantVector *cv = dyn_cast<const ConstantVector>(c)) {
    return translateConstantAggregate(m, VAL_CONSTANTVECTOR, cv);
  }

  if(const ConstantStruct *cs = dyn_cast<const ConstantStruct>(c)) {
    return translateConstantAggregate(m, VAL_CONSTANTSTRUCT, cs);
  }

  if(const ConstantFP *fp = dyn_cast<const ConstantFP>(c)) {
    return translateConstantFP(m, fp);
  }

  if(const ConstantAggregateZero *az = dyn_cast<const ConstantAggregateZero>(c)) {
    return translateEmptyConstant(m, VAL_CONSTANTAGGREGATEZERO, az);
  }

  if(const UndefValue *uv = dyn_cast<const UndefValue>(c)) {
    return translateEmptyConstant(m, VAL_UNDEFVALUE, uv);
  }

  if(const BlockAddress *ba = dyn_cast<const BlockAddress>(c)) {
    return translateBlockAddress(m, ba);
  }


  string msg;
  raw_string_ostream os(msg);
  os << "Unhandled constant type: ";
  c->print(os);
  throw os.str();
}

static CValue* translateValue(CModule *m, const Value *v) {
  PrivateData *pd = (PrivateData*)m->privateData;
  unordered_map<const Value*, CValue*>::iterator it = pd->valueMap.find(v);
  if(it != pd->valueMap.end())
    return it->second;

  // This order is pretty reasonable since constants will be the most
  // frequent un-cached values.
  if(const Constant *c = dyn_cast<const Constant>(v)) {
    return translateConstant(m, c);
  }

  if(const Instruction *i = dyn_cast<const Instruction>(v)) {
    return translateInstruction(m, i);
  }

  if(const BasicBlock *bb = dyn_cast<const BasicBlock>(v)) {
    return translateBasicBlock(m, bb);
  }

  if(const InlineAsm *a = dyn_cast<const InlineAsm>(v)) {
    return translateInlineAsm(m, a);
  }

  if(dyn_cast<const Argument>(v)) {
    string msg = "Un-cached Argument passed to translateValue";
    throw msg;
  }

  string msg;
  raw_string_ostream os(msg);
  os << "Unhandled value type: ";
  v->print(os);
  throw os.str();
}

static void decodeAndAttachSubprogram(CModule *m, DISubprogram sp) {
  if(sp.getFunction() == NULL)
    return;

  CMeta *md = translateMetadata(m, sp);
  if(!md)
    throw "No translation for subprogram metadata";

  int currentCapacity = md->u.metaSubprogramInfo.function->metaCapacity;
  int metaCount = md->u.metaSubprogramInfo.function->numMetadata;
  if(metaCount == 0) {
    currentCapacity = 10;
    md->u.metaSubprogramInfo.function->metaCapacity = currentCapacity;
    md->u.metaSubprogramInfo.function->md =
      (CMeta**)calloc(currentCapacity, sizeof(CMeta*));
  }
  else if(metaCount == currentCapacity - 1) {
    int newCapacity = 2 * currentCapacity;
    CMeta **newMeta = (CMeta**)calloc(newCapacity, sizeof(CMeta*));
    memcpy(newMeta, md->u.metaSubprogramInfo.function->md, currentCapacity * sizeof(CMeta*));
    free(md->u.metaSubprogramInfo.function->md);
    md->u.metaSubprogramInfo.function->md = newMeta;
    md->u.metaSubprogramInfo.function->metaCapacity = newCapacity;
  }

  md->u.metaSubprogramInfo.function->md[metaCount] = md;
  md->u.metaSubprogramInfo.function->numMetadata++;
}

static void attachFunctionMetadata(CModule *m, Module *M) {
  // dragonegg format
  if(NamedMDNode *sp = M->getNamedMetadata("llvm.dbg.sp")) {
    for(unsigned int i = 0; i < sp->getNumOperands(); ++i) {
      DISubprogram dsp(sp->getOperand(i));
      decodeAndAttachSubprogram(m, dsp);
    }
  }
  // clang format
  else if(NamedMDNode *cu = M->getNamedMetadata("llvm.dbg.cu")) {
    for(unsigned int i = 0; i < cu->getNumOperands(); ++i) {
      DIDescriptor cudesc(cu->getOperand(i));
      if(!cudesc.isCompileUnit())
        throw "llvm.dbg.cu contains a something that isn't a CompileUnit";
      DICompileUnit dicu(cu->getOperand(i));
      DIArray sps = dicu.getSubprograms();
      for(unsigned int j = 0; j < sps.getNumElements(); ++j) {
        DIDescriptor spdesc = sps.getElement(j);
        // It looks like there can be NULL entries in subprogram
        // lists.  Just ignore them.  Debug info is best-effort so
        // this should be fine.
        if(!spdesc.isSubprogram()) {
          continue;
        }

        DISubprogram dsp(spdesc);
        decodeAndAttachSubprogram(m, dsp);
      }
    }
  }
}

static void attachGlobalMetadata(CModule *m, Module *M) {
  NamedMDNode *gv = M->getNamedMetadata("llvm.dbg.gv");
  // No debug information
  if(!gv) return;

  for(unsigned int i = 0; i < gv->getNumOperands(); ++i) {
    CMeta *md = translateMetadata(m, gv->getOperand(i));
    if(md->metaTag != META_GLOBALVARIABLE) {
      throw "Non-global in llvm.dbg.gv";
    }

    if(md->u.metaGlobalInfo.global == NULL)
      continue;

    int currentCapacity = md->u.metaGlobalInfo.global->metaCapacity;
    int metaCount = md->u.metaGlobalInfo.global->numMetadata;
    if(metaCount == 0) {
      currentCapacity = 10;
      md->u.metaGlobalInfo.global->metaCapacity = currentCapacity;
      md->u.metaGlobalInfo.global->md = (CMeta**)calloc(currentCapacity, sizeof(CMeta*));
    }
    else if(metaCount == currentCapacity - 1) {
      int newCapacity = 2 * currentCapacity;
      CMeta **newMeta = (CMeta**)calloc(newCapacity, sizeof(CMeta*));
      memcpy(newMeta, md->u.metaGlobalInfo.global->md, currentCapacity * sizeof(CMeta*));
      free(md->u.metaGlobalInfo.global->md);
      md->u.metaGlobalInfo.global->md = newMeta;
      md->u.metaGlobalInfo.global->metaCapacity = newCapacity;
    }

    md->u.metaGlobalInfo.global->md[metaCount] = md;
    md->u.metaGlobalInfo.global->numMetadata++;
  }
}

static void attachEnumMetadata(CModule *m, Module *M) {
  // First, try to deal with the old method used by dragonegg 3.0
  NamedMDNode *enums = M->getNamedMetadata("llvm.dbg.enum");
  std::set<CMeta*> enumMeta;

  if(enums) {
    for(unsigned int i = 0; i < enums->getNumOperands(); ++i) {
      CMeta *md = translateMetadata(m, enums->getOperand(i));
      if(md)
        enumMeta.insert(md);
    }

    m->enumMetadata = (CMeta**)calloc(enumMeta.size(), sizeof(CMeta*));
    m->numEnumMetadata = enumMeta.size();
    std::copy(enumMeta.begin(), enumMeta.end(), m->enumMetadata);
    return;
  }

  // Otherwise, try the newer format used by clang (and hopefully
  // newer dragoneggs).
  NamedMDNode *compUnits = M->getNamedMetadata("llvm.dbg.cu");
  if(compUnits) {
    for(unsigned int i = 0; i < compUnits->getNumOperands(); ++i) {
      DICompileUnit CU(compUnits->getOperand(i));
      DIArray unitEnums(CU.getEnumTypes());
      for(unsigned int e = 0; e < unitEnums.getNumElements(); ++e) {
        CMeta *md = translateMetadata(m, unitEnums.getElement(e));
        if(md)
          enumMeta.insert(md);
      }
    }

    m->enumMetadata = (CMeta**)calloc(enumMeta.size(), sizeof(CMeta*));
    m->numEnumMetadata = enumMeta.size();
    std::copy(enumMeta.begin(), enumMeta.end(), m->enumMetadata);
    return;
  }
}

static void attachRetainedTypeMetadata(CModule *m, Module *M) {
  // This information is not present in dragonegg, so we just use the
  // new clang style.
  NamedMDNode *compUnits = M->getNamedMetadata("llvm.dbg.cu");
  if(!compUnits) return;
  std::set<CMeta*> typeMeta;

  for(unsigned int i = 0; i < compUnits->getNumOperands(); ++i) {
    DICompileUnit CU(compUnits->getOperand(i));
    DIArray unitTypes(CU.getRetainedTypes());
    for(unsigned int t = 0; t < unitTypes.getNumElements(); ++t) {
      CMeta *md = translateMetadata(m, unitTypes.getElement(t));
      if(md)
        typeMeta.insert(md);
    }
  }

  m->retainedTypeMetadata = (CMeta**)calloc(typeMeta.size(), sizeof(CMeta*));
  m->numRetainedTypes = typeMeta.size();
  std::copy(typeMeta.begin(), typeMeta.end(), m->retainedTypeMetadata);
}

static CModule* marshal(CModule * module) {
  PrivateData *pd = (PrivateData*)module->privateData;
  Module *m = pd->original;

  module->moduleIdentifier = getCStrdup(m->getModuleIdentifier());
  module->moduleDataLayout = getCStrdup(m->getDataLayout());
  module->targetTriple = getCStrdup(m->getTargetTriple());
  module->moduleInlineAsm = getCStrdup(m->getModuleInlineAsm());


  try
  {
    std::vector<CValue*> globalVariables;
    for(Module::const_global_iterator it = m->global_begin(),
          ed = m->global_end(); it != ed; ++it)
    {
      const GlobalVariable *globalVar = dyn_cast<const GlobalVariable>(&*it);
      if(!globalVar) throw "Not a global";

      CValue *gv = translateGlobalVariable(module, globalVar);
      globalVariables.push_back(gv);
    }

    module->numGlobalVariables = globalVariables.size();
    module->globalVariables = (CValue**)calloc(module->numGlobalVariables, sizeof(CValue*));
    std::copy(globalVariables.begin(), globalVariables.end(), module->globalVariables);


    std::vector<CValue*> functions;
    for(Module::const_iterator it = m->begin(),
          ed = m->end(); it != ed; ++it)
    {
      const Function *func = dyn_cast<const Function>(&*it);
      if(!func) throw "Not a function";

      CValue *f = translateFunction(module, func);
      functions.push_back(f);
    }

    module->numFunctions = functions.size();
    module->functions = (CValue**)calloc(module->numFunctions, sizeof(CValue*));
    std::copy(functions.begin(), functions.end(), module->functions);


    std::vector<CValue*> globalAliases;
    for(Module::const_alias_iterator it = m->alias_begin(),
          ed = m->alias_end(); it != ed; ++it)
    {
      const GlobalAlias *globalAlias = dyn_cast<const GlobalAlias>(&*it);
      if(!globalAlias) throw "Not a global alias";

      CValue *ga = translateGlobalAlias(module, globalAlias);
      globalAliases.push_back(ga);
    }

    module->numGlobalAliases = globalAliases.size();
    module->globalAliases = (CValue**)calloc(module->numGlobalAliases, sizeof(CValue*));
    std::copy(globalAliases.begin(), globalAliases.end(), module->globalAliases);

    std::vector<CType*> typeVec;
    for(unordered_map<const Type*, CType*>::const_iterator it = pd->typeMap.begin(),
          ed = pd->typeMap.end(); it != ed; ++it)
    {
      typeVec.push_back(it->second);
    }
    module->numTypes = typeVec.size();
    module->types = (CType**)calloc(module->numTypes, sizeof(CType*));

    std::copy(typeVec.begin(), typeVec.end(), module->types);

    // Now process the global metadata to attach metadata to global
    // variables and functions.
    attachFunctionMetadata(module, m);
    attachGlobalMetadata(module, m);
    attachEnumMetadata(module, m);
    attachRetainedTypeMetadata(module, m);
  }
  catch(const string &msg) {
    module->hasError = 1;
    module->errMsg = getCStrdup(msg);
  }
  catch(const char *msg) {
    module->hasError = 1;
    module->errMsg = getCStrdup(msg);
  }
  catch(...) {
    module->hasError = 1;
    module->errMsg = getCStrdup("Unknown error");
  }

  return module;
}

extern "C" {

  /*!
    Free all of the resources allocated by the exposed module,
    including the underlying C++ LLVM Module.
   */
  void disposeCModule(CModule *m) {
    free(m->errMsg);
    free(m->moduleIdentifier);
    free(m->moduleDataLayout);
    free(m->targetTriple);
    free(m->moduleInlineAsm);

    // The actual variables are deleted with disposeCValue from the
    // valueMap.
    free(m->globalVariables);
    free(m->globalAliases);
    free(m->functions);
    free(m->enumMetadata);
    free(m->retainedTypeMetadata);

    PrivateData *pd = (PrivateData*)m->privateData;

    for(unordered_map<const Type*,CType*>::iterator it = pd->typeMap.begin(),
          ed = pd->typeMap.end(); it != ed; ++it)
    {
      disposeCType(it->second);
    }

    for(unordered_map<const Value*,CValue*>::iterator it = pd->valueMap.begin(),
          ed = pd->valueMap.end(); it != ed; ++it)
    {
      disposeCValue(it->second);
    }

    for(unordered_map<const MDNode*,CMeta*>::iterator it = pd->metaMap.begin(),
          ed = pd->metaMap.end(); it != ed; ++it)
    {
      disposeCMeta(it->second);
    }

    for(unordered_map<const DebugLoc*,CMeta*>::iterator it = pd->srcLocMap.begin(),
          ed = pd->srcLocMap.end(); it != ed; ++it)
    {
      disposeCMeta(it->second);
    }


    // These are actually allocated with new
    delete pd->dataLayout;
    delete pd->original;
    delete pd;

    free(m);
  }

  CModule* marshalLLVMFile(const char * filename, int includeLocs) {
    CModule *module = (CModule*)calloc(1, sizeof(CModule));
    PrivateData *pd = new PrivateData;
    module->privateData = (void*)pd;

    Module *m = ParseIRFile(filename, pd->diags, pd->ctxt);
    pd->dataLayout = new DataLayout(m);

    if(m == NULL) {
      module->hasError = 1;
      module->errMsg = getCStrdup(pd->diags.getMessage());
      return module;
    }

    pd->original = m;
    pd->includeLocs = includeLocs;

    return marshal(module);
  }

  CModule* marshalLLVM(const char * buffer, int bufLen, int includeLocs) {
    CModule *module = (CModule*)calloc(1, sizeof(CModule));
    PrivateData *pd = new PrivateData;
    module->privateData = (void*)pd;

    StringRef bref(buffer, bufLen);
    pd->buffer.reset(MemoryBuffer::getMemBuffer(bref, "", false));

    if(pd->buffer.get() == NULL){
      module->hasError = 1;
      module->errMsg = getCStrdup("Could not create memory buffer");
      return module;
    }

    Module *m = ParseIR(pd->buffer.get(), pd->diags, pd->ctxt);

    if(m == NULL) {
      module->hasError = 1;
      module->errMsg = getCStrdup(pd->diags.getMessage());
      return module;
    }

    pd->original = m;
    pd->includeLocs = includeLocs;

    return marshal(module);
  }
}