<div dir="ltr">fputs(Str, cout) ends up making files with DOS line endings on Windows, causing the test to fail on the 'diff' step. I'll add -w to make it pass. I'm assuming you don't care about whitespace changes?</div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Feb 4, 2016 at 3:26 PM, Amaury Sechet via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: deadalnix<br>
Date: Thu Feb  4 17:26:19 2016<br>
New Revision: 259844<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=259844&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=259844&view=rev</a><br>
Log:<br>
Improve testing for the C API<br>
<br>
Summary:<br>
This basically add an echo test case in C. The support is limited right now, but full support would just be too much to review at once.<br>
<br>
The echo test case simply get a module as input and try to output the same exact module. This allow to check the both reading and writing API are working as expected.<br>
<br>
I want to improve this test over time to support more and more of the API, in order to improve coverage (coverage is quite poor right now).<br>
<br>
Test Plan: Run the test.<br>
<br>
Reviewers: chandlerc, bogner<br>
<br>
Subscribers: llvm-commits<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D10725" rel="noreferrer" target="_blank">http://reviews.llvm.org/D10725</a><br>
<br>
Added:<br>
    llvm/trunk/test/Bindings/llvm-c/echo.ll<br>
    llvm/trunk/tools/llvm-c-test/echo.cpp<br>
Modified:<br>
    llvm/trunk/tools/llvm-c-test/CMakeLists.txt<br>
    llvm/trunk/tools/llvm-c-test/calc.c<br>
    llvm/trunk/tools/llvm-c-test/llvm-c-test.h<br>
    llvm/trunk/tools/llvm-c-test/main.c<br>
    llvm/trunk/tools/llvm-c-test/metadata.c<br>
    llvm/trunk/tools/llvm-c-test/module.c<br>
    llvm/trunk/tools/llvm-c-test/object.c<br>
<br>
Added: llvm/trunk/test/Bindings/llvm-c/echo.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bindings/llvm-c/echo.ll?rev=259844&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bindings/llvm-c/echo.ll?rev=259844&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Bindings/llvm-c/echo.ll (added)<br>
+++ llvm/trunk/test/Bindings/llvm-c/echo.ll Thu Feb  4 17:26:19 2016<br>
@@ -0,0 +1,32 @@<br>
+; RUN: llvm-as < %s | llvm-dis > %t.orig<br>
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo<br>
+; RUN: diff %t.orig %t.echo<br>
+<br>
+declare void @decl()<br>
+<br>
+; TODO: label, struct and metadata types<br>
+define void @types() {<br>
+  %1 = alloca half<br>
+  %2 = alloca float<br>
+  %3 = alloca double<br>
+  %4 = alloca x86_fp80<br>
+  %5 = alloca fp128<br>
+  %6 = alloca ppc_fp128<br>
+  %7 = alloca i7<br>
+  %8 = alloca void (i1)*<br>
+  %9 = alloca [3 x i22]<br>
+  %10 = alloca i328 addrspace(5)*<br>
+  %11 = alloca <5 x i23*><br>
+  %12 = alloca x86_mmx<br>
+  ret void<br>
+}<br>
+<br>
+define i32 @add(i32 %a, i32 %b) {<br>
+  %1 = add i32 %a, %b<br>
+  ret i32 %1<br>
+}<br>
+<br>
+define i32 @call() {<br>
+  %1 = call i32 @add(i32 23, i32 19)<br>
+  ret i32 %1<br>
+}<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/CMakeLists.txt?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/CMakeLists.txt?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/CMakeLists.txt (original)<br>
+++ llvm/trunk/tools/llvm-c-test/CMakeLists.txt Thu Feb  4 17:26:19 2016<br>
@@ -37,6 +37,7 @@ endif ()<br>
 add_llvm_tool(llvm-c-test<br>
   calc.c<br>
   disassemble.c<br>
+  echo.cpp<br>
   helpers.c<br>
   include-all.c<br>
   main.c<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/calc.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/calc.c?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/calc.c?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/calc.c (original)<br>
+++ llvm/trunk/tools/llvm-c-test/calc.c Thu Feb  4 17:26:19 2016<br>
@@ -14,7 +14,6 @@<br>
 \*===----------------------------------------------------------------------===*/<br>
<br>
 #include "llvm-c-test.h"<br>
-#include "llvm-c/Core.h"<br>
 #include <stdio.h><br>
 #include <stdlib.h><br>
 #include <string.h><br>
<br>
Added: llvm/trunk/tools/llvm-c-test/echo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/echo.cpp?rev=259844&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/echo.cpp?rev=259844&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/echo.cpp (added)<br>
+++ llvm/trunk/tools/llvm-c-test/echo.cpp Thu Feb  4 17:26:19 2016<br>
@@ -0,0 +1,468 @@<br>
+//===-- echo.cpp - tool for testing libLLVM and llvm-c API ----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file implements the --echo commands in llvm-c-test.<br>
+//<br>
+// This command uses the C API to read a module and output an exact copy of it<br>
+// as output. It is used to check that the resulting module matches the input<br>
+// to validate that the C API can read and write modules properly.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm-c-test.h"<br>
+#include "llvm/ADT/DenseMap.h"<br>
+<br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+<br>
+using namespace llvm;<br>
+<br>
+// Provide DenseMapInfo for C API opaque types.<br>
+template<typename T><br>
+struct CAPIDenseMap {};<br>
+<br>
+// The default DenseMapInfo require to know about pointer alignement.<br>
+// Because the C API uses opaques pointer types, their alignement is unknown.<br>
+// As a result, we need to roll out our own implementation.<br>
+template<typename T><br>
+struct CAPIDenseMap<T*> {<br>
+  struct CAPIDenseMapInfo {<br>
+    static inline T* getEmptyKey() {<br>
+      uintptr_t Val = static_cast<uintptr_t>(-1);<br>
+      return reinterpret_cast<T*>(Val);<br>
+    }<br>
+    static inline T* getTombstoneKey() {<br>
+      uintptr_t Val = static_cast<uintptr_t>(-2);<br>
+      return reinterpret_cast<T*>(Val);<br>
+    }<br>
+    static unsigned getHashValue(const T *PtrVal) {<br>
+      return hash_value(PtrVal);<br>
+    }<br>
+    static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }<br>
+  };<br>
+<br>
+  typedef DenseMap<T*, T*, CAPIDenseMapInfo> Map;<br>
+};<br>
+<br>
+typedef CAPIDenseMap<LLVMValueRef>::Map ValueMap;<br>
+<br>
+static LLVMTypeRef clone_type(LLVMTypeRef Src, LLVMContextRef Ctx) {<br>
+  LLVMTypeKind Kind = LLVMGetTypeKind(Src);<br>
+  switch (Kind) {<br>
+    case LLVMVoidTypeKind:<br>
+      return LLVMVoidTypeInContext(Ctx);<br>
+    case LLVMHalfTypeKind:<br>
+      return LLVMHalfTypeInContext(Ctx);<br>
+    case LLVMFloatTypeKind:<br>
+      return LLVMFloatTypeInContext(Ctx);<br>
+    case LLVMDoubleTypeKind:<br>
+      return LLVMDoubleTypeInContext(Ctx);<br>
+    case LLVMX86_FP80TypeKind:<br>
+      return LLVMX86FP80TypeInContext(Ctx);<br>
+    case LLVMFP128TypeKind:<br>
+      return LLVMFP128TypeInContext(Ctx);<br>
+    case LLVMPPC_FP128TypeKind:<br>
+      return LLVMPPCFP128TypeInContext(Ctx);<br>
+    case LLVMLabelTypeKind:<br>
+      return LLVMLabelTypeInContext(Ctx);<br>
+    case LLVMIntegerTypeKind:<br>
+      return LLVMIntTypeInContext(Ctx, LLVMGetIntTypeWidth(Src));<br>
+    case LLVMFunctionTypeKind: {<br>
+      unsigned ParamCount = LLVMCountParamTypes(Src);<br>
+      LLVMTypeRef* Params = nullptr;<br>
+      if (ParamCount > 0) {<br>
+        Params = (LLVMTypeRef*) malloc(ParamCount * sizeof(LLVMTypeRef));<br>
+        LLVMGetParamTypes(Src, Params);<br>
+        for (unsigned i = 0; i < ParamCount; i++) {<br>
+          Params[i] = clone_type(Params[i], Ctx);<br>
+        }<br>
+      }<br>
+<br>
+      LLVMTypeRef FunTy = LLVMFunctionType(<br>
+        clone_type(LLVMGetReturnType(Src), Ctx),<br>
+        Params, ParamCount,<br>
+        LLVMIsFunctionVarArg(Src)<br>
+      );<br>
+<br>
+      if (ParamCount > 0)<br>
+        free(Params);<br>
+<br>
+      return FunTy;<br>
+    }<br>
+    case LLVMStructTypeKind:<br>
+      break;<br>
+    case LLVMArrayTypeKind:<br>
+      return LLVMArrayType(<br>
+        clone_type(LLVMGetElementType(Src), Ctx),<br>
+        LLVMGetArrayLength(Src)<br>
+      );<br>
+    case LLVMPointerTypeKind:<br>
+      return LLVMPointerType(<br>
+        clone_type(LLVMGetElementType(Src), Ctx),<br>
+        LLVMGetPointerAddressSpace(Src)<br>
+      );<br>
+    case LLVMVectorTypeKind:<br>
+      return LLVMVectorType(<br>
+        clone_type(LLVMGetElementType(Src), Ctx),<br>
+        LLVMGetVectorSize(Src)<br>
+      );<br>
+    case LLVMMetadataTypeKind:<br>
+      break;<br>
+    case LLVMX86_MMXTypeKind:<br>
+      return LLVMX86MMXTypeInContext(Ctx);<br>
+    default:<br>
+      break;<br>
+  }<br>
+<br>
+  fprintf(stderr, "%d is not a supported typekind\n", Kind);<br>
+  exit(-1);<br>
+}<br>
+<br>
+static LLVMValueRef clone_literal(LLVMValueRef Src, LLVMContextRef Ctx) {<br>
+  LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);<br>
+<br>
+  LLVMTypeKind Kind = LLVMGetTypeKind(Ty);<br>
+  switch (Kind) {<br>
+    case LLVMIntegerTypeKind:<br>
+      return LLVMConstInt(Ty, LLVMConstIntGetZExtValue(Src), false);<br>
+    default:<br>
+      break;<br>
+  }<br>
+<br>
+  fprintf(stderr, "%d is not a supported constant typekind\n", Kind);<br>
+  exit(-1);<br>
+}<br>
+<br>
+static LLVMModuleRef get_module(LLVMBuilderRef Builder) {<br>
+  LLVMBasicBlockRef BB = LLVMGetInsertBlock(Builder);<br>
+  LLVMValueRef Fn = LLVMGetBasicBlockParent(BB);<br>
+  return LLVMGetGlobalParent(Fn);<br>
+}<br>
+<br>
+// Try to clone everything in the llvm::Value hierarchy.<br>
+static LLVMValueRef clone_value(LLVMValueRef Src, LLVMBuilderRef Builder, ValueMap &VMap) {<br>
+  const char *Name = LLVMGetValueName(Src);<br>
+<br>
+  // First, the value may be constant.<br>
+  if (LLVMIsAConstant(Src)) {<br>
+    LLVMModuleRef M = get_module(Builder);<br>
+<br>
+    // Maybe it is a symbol<br>
+    if (LLVMIsAGlobalValue(Src)) {<br>
+      // Try function<br>
+      LLVMValueRef Dst = LLVMGetNamedFunction(M, Name);<br>
+      if (Dst != nullptr)<br>
+        return Dst;<br>
+<br>
+      // Try global variable<br>
+      Dst = LLVMGetNamedGlobal(M, Name);<br>
+      if (Dst != nullptr)<br>
+        return Dst;<br>
+<br>
+      fprintf(stderr, "Could not find @%s\n", Name);<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    // Try literal<br>
+    LLVMContextRef Ctx = LLVMGetModuleContext(M);<br>
+    return clone_literal(Src, Ctx);<br>
+  }<br>
+<br>
+  // Try undef<br>
+  if (LLVMIsUndef(Src)) {<br>
+    LLVMContextRef Ctx = LLVMGetModuleContext(get_module(Builder));<br>
+    LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);<br>
+    return LLVMGetUndef(Ty);<br>
+  }<br>
+<br>
+  // Check if this is something we already computed.<br>
+  {<br>
+    auto i = VMap.find(Src);<br>
+    if (i != VMap.end())<br>
+      return i->second;<br>
+  }<br>
+<br>
+  // We tried everything, it must be an instruction<br>
+  // that hasn't been generated already.<br>
+  LLVMValueRef Dst = nullptr;<br>
+<br>
+  LLVMOpcode Op = LLVMGetInstructionOpcode(Src);<br>
+  switch(Op) {<br>
+    case LLVMRet: {<br>
+      int OpCount = LLVMGetNumOperands(Src);<br>
+      if (OpCount == 0)<br>
+        Dst = LLVMBuildRetVoid(Builder);<br>
+      else<br>
+        Dst = LLVMBuildRet(Builder, clone_value(LLVMGetOperand(Src, 0),<br>
+                                                Builder, VMap));<br>
+      break;<br>
+    }<br>
+    case LLVMBr:<br>
+    case LLVMSwitch:<br>
+    case LLVMIndirectBr:<br>
+    case LLVMInvoke:<br>
+    case LLVMUnreachable:<br>
+      break;<br>
+    case LLVMAdd: {<br>
+      LLVMValueRef LHS = clone_value(LLVMGetOperand(Src, 0), Builder, VMap);<br>
+      LLVMValueRef RHS = clone_value(LLVMGetOperand(Src, 1), Builder, VMap);<br>
+      Dst = LLVMBuildAdd(Builder, LHS, RHS, Name);<br>
+      break;<br>
+    }<br>
+    case LLVMAlloca: {<br>
+      LLVMTypeRef Ty = LLVMGetElementType(LLVMTypeOf(Src));<br>
+      Dst = LLVMBuildAlloca(Builder, Ty, Name);<br>
+      break;<br>
+    }<br>
+    case LLVMCall: {<br>
+      int ArgCount = LLVMGetNumOperands(Src) - 1;<br>
+      SmallVector<LLVMValueRef, 8> Args;<br>
+      for (int i = 0; i < ArgCount; i++)<br>
+        Args.push_back(clone_value(LLVMGetOperand(Src, i), Builder, VMap));<br>
+      LLVMValueRef Fn = clone_value(LLVMGetOperand(Src, ArgCount), Builder, VMap);<br>
+      Dst = LLVMBuildCall(Builder, Fn, Args.data(), ArgCount, Name);<br>
+      break;<br>
+    }<br>
+    default:<br>
+      break;<br>
+  }<br>
+<br>
+  if (Dst == nullptr) {<br>
+    fprintf(stderr, "%d is not a supported opcode\n", Op);<br>
+    exit(-1);<br>
+  }<br>
+<br>
+  return VMap[Src] = Dst;<br>
+}<br>
+<br>
+static LLVMBasicBlockRef clone_bb(LLVMBasicBlockRef Src, LLVMValueRef Dst, ValueMap &VMap) {<br>
+  LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Dst, "");<br>
+<br>
+  LLVMValueRef First = LLVMGetFirstInstruction(Src);<br>
+  LLVMValueRef Last = LLVMGetLastInstruction(Src);<br>
+<br>
+  if (First == nullptr) {<br>
+    if (Last != nullptr) {<br>
+      fprintf(stderr, "Has no first instruction, but last one\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    return BB;<br>
+  }<br>
+<br>
+  LLVMContextRef Ctx = LLVMGetModuleContext(LLVMGetGlobalParent(Dst));<br>
+  LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx);<br>
+  LLVMPositionBuilderAtEnd(Builder, BB);<br>
+<br>
+  LLVMValueRef Cur = First;<br>
+  LLVMValueRef Next = nullptr;<br>
+  while(true) {<br>
+    clone_value(Cur, Builder, VMap);<br>
+    Next = LLVMGetNextInstruction(Cur);<br>
+    if (Next == nullptr) {<br>
+      if (Cur != Last) {<br>
+        fprintf(stderr, "Final instruction does not match Last\n");<br>
+        exit(-1);<br>
+      }<br>
+<br>
+      break;<br>
+    }<br>
+<br>
+    LLVMValueRef Prev = LLVMGetPreviousInstruction(Next);<br>
+    if (Prev != Cur) {<br>
+      fprintf(stderr, "Next.Previous instruction is not Current\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    Cur = Next;<br>
+  }<br>
+<br>
+  LLVMDisposeBuilder(Builder);<br>
+  return BB;<br>
+}<br>
+<br>
+static void clone_bbs(LLVMValueRef Src, LLVMValueRef Dst, ValueMap &VMap) {<br>
+  unsigned Count = LLVMCountBasicBlocks(Src);<br>
+  if (Count == 0)<br>
+    return;<br>
+<br>
+  LLVMBasicBlockRef First = LLVMGetFirstBasicBlock(Src);<br>
+  LLVMBasicBlockRef Last = LLVMGetLastBasicBlock(Src);<br>
+<br>
+  LLVMBasicBlockRef Cur = First;<br>
+  LLVMBasicBlockRef Next = nullptr;<br>
+  while(true) {<br>
+    clone_bb(Cur, Dst, VMap);<br>
+    Count--;<br>
+    Next = LLVMGetNextBasicBlock(Cur);<br>
+    if (Next == nullptr) {<br>
+      if (Cur != Last) {<br>
+        fprintf(stderr, "Final basic block does not match Last\n");<br>
+        exit(-1);<br>
+      }<br>
+<br>
+      break;<br>
+    }<br>
+<br>
+    LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Next);<br>
+    if (Prev != Cur) {<br>
+      fprintf(stderr, "Next.Previous basic bloc is not Current\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    Cur = Next;<br>
+  }<br>
+<br>
+  if (Count != 0) {<br>
+    fprintf(stderr, "Basic block count does not match iterration\n");<br>
+    exit(-1);<br>
+  }<br>
+}<br>
+<br>
+static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) {<br>
+  unsigned Count = LLVMCountParams(Src);<br>
+  if (Count != LLVMCountParams(Dst)) {<br>
+    fprintf(stderr, "Parameter count mismatch\n");<br>
+    exit(-1);<br>
+  }<br>
+<br>
+  ValueMap VMap;<br>
+  if (Count == 0)<br>
+    return VMap;<br>
+<br>
+  LLVMValueRef SrcFirst = LLVMGetFirstParam(Src);<br>
+  LLVMValueRef DstFirst = LLVMGetFirstParam(Dst);<br>
+  LLVMValueRef SrcLast = LLVMGetLastParam(Src);<br>
+  LLVMValueRef DstLast = LLVMGetLastParam(Dst);<br>
+<br>
+  LLVMValueRef SrcCur = SrcFirst;<br>
+  LLVMValueRef DstCur = DstFirst;<br>
+  LLVMValueRef SrcNext = nullptr;<br>
+  LLVMValueRef DstNext = nullptr;<br>
+  while (true) {<br>
+    const char *Name = LLVMGetValueName(SrcCur);<br>
+    LLVMSetValueName(DstCur, Name);<br>
+<br>
+    VMap[SrcCur] = DstCur;<br>
+<br>
+    Count--;<br>
+    SrcNext = LLVMGetNextParam(SrcCur);<br>
+    DstNext = LLVMGetNextParam(DstCur);<br>
+    if (SrcNext == nullptr && DstNext == nullptr) {<br>
+      if (SrcCur != SrcLast) {<br>
+        fprintf(stderr, "SrcLast param does not match End\n");<br>
+        exit(-1);<br>
+      }<br>
+<br>
+      if (DstCur != DstLast) {<br>
+        fprintf(stderr, "DstLast param does not match End\n");<br>
+        exit(-1);<br>
+      }<br>
+<br>
+      break;<br>
+    }<br>
+<br>
+    if (SrcNext == nullptr) {<br>
+      fprintf(stderr, "SrcNext was unexpectedly null\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    if (DstNext == nullptr) {<br>
+      fprintf(stderr, "DstNext was unexpectedly null\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    LLVMValueRef SrcPrev = LLVMGetPreviousParam(SrcNext);<br>
+    if (SrcPrev != SrcCur) {<br>
+      fprintf(stderr, "SrcNext.Previous param is not Current\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    LLVMValueRef DstPrev = LLVMGetPreviousParam(DstNext);<br>
+    if (DstPrev != DstCur) {<br>
+      fprintf(stderr, "DstNext.Previous param is not Current\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    SrcCur = SrcNext;<br>
+    DstCur = DstNext;<br>
+  }<br>
+<br>
+  if (Count != 0) {<br>
+    fprintf(stderr, "Parameter count does not match iteration\n");<br>
+    exit(-1);<br>
+  }<br>
+<br>
+  return VMap;<br>
+}<br>
+<br>
+static LLVMValueRef clone_function(LLVMValueRef Src, LLVMModuleRef Dst) {<br>
+  const char *Name = LLVMGetValueName(Src);<br>
+  LLVMValueRef Fun = LLVMGetNamedFunction(Dst, Name);<br>
+  if (Fun != nullptr)<br>
+    return Fun;<br>
+<br>
+  LLVMTypeRef SrcTy = LLVMTypeOf(Src);<br>
+  LLVMTypeRef DstTy = clone_type(SrcTy, LLVMGetModuleContext(Dst));<br>
+  LLVMTypeRef FunTy = LLVMGetElementType(DstTy);<br>
+<br>
+  Fun = LLVMAddFunction(Dst, Name, FunTy);<br>
+<br>
+  ValueMap VMap = clone_params(Src, Fun);<br>
+  clone_bbs(Src, Fun, VMap);<br>
+<br>
+  return Fun;<br>
+}<br>
+<br>
+static void clone_functions(LLVMModuleRef Src, LLVMModuleRef Dst) {<br>
+  LLVMValueRef Begin = LLVMGetFirstFunction(Src);<br>
+  LLVMValueRef End = LLVMGetLastFunction(Src);<br>
+<br>
+  LLVMValueRef Cur = Begin;<br>
+  LLVMValueRef Next = nullptr;<br>
+  while (true) {<br>
+    clone_function(Cur, Dst);<br>
+    Next = LLVMGetNextFunction(Cur);<br>
+    if (Next == nullptr) {<br>
+      if (Cur != End) {<br>
+        fprintf(stderr, "Last function does not match End\n");<br>
+        exit(-1);<br>
+      }<br>
+<br>
+      break;<br>
+    }<br>
+<br>
+    LLVMValueRef Prev = LLVMGetPreviousFunction(Next);<br>
+    if (Prev != Cur) {<br>
+      fprintf(stderr, "Next.Previous function is not Current\n");<br>
+      exit(-1);<br>
+    }<br>
+<br>
+    Cur = Next;<br>
+  }<br>
+}<br>
+<br>
+int echo(void) {<br>
+  LLVMEnablePrettyStackTrace();<br>
+<br>
+  LLVMModuleRef Src = load_module(false, true);<br>
+<br>
+  LLVMContextRef Ctx = LLVMContextCreate();<br>
+  LLVMModuleRef Dst = LLVMModuleCreateWithNameInContext("<stdin>", Ctx);<br>
+<br>
+  clone_functions(Src, Dst);<br>
+  char *Str = LLVMPrintModuleToString(Dst);<br>
+  fputs(Str, stdout);<br>
+<br>
+  LLVMDisposeMessage(Str);<br>
+  LLVMDisposeModule(Dst);<br>
+  LLVMContextDispose(Ctx);<br>
+<br>
+  return 0;<br>
+}<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/llvm-c-test.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/llvm-c-test.h?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/llvm-c-test.h?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/llvm-c-test.h (original)<br>
+++ llvm/trunk/tools/llvm-c-test/llvm-c-test.h Thu Feb  4 17:26:19 2016<br>
@@ -14,11 +14,17 @@<br>
 #define LLVM_C_TEST_H<br>
<br>
 #include <stdbool.h><br>
+#include "llvm-c/Core.h"<br>
+<br>
+#ifdef __cplusplus<br>
+extern "C" {<br>
+#endif<br>
<br>
 // helpers.c<br>
 void tokenize_stdin(void (*cb)(char **tokens, int ntokens));<br>
<br>
 // module.c<br>
+LLVMModuleRef load_module(bool Lazy, bool New);<br>
 int module_dump(bool Lazy, bool New);<br>
 int module_list_functions(void);<br>
 int module_list_globals(void);<br>
@@ -40,4 +46,11 @@ int object_list_symbols(void);<br>
 // targets.c<br>
 int targets_list(void);<br>
<br>
+// echo.c<br>
+int echo(void);<br>
+<br>
+#ifdef __cplusplus<br>
+}<br>
+#endif /* !defined(__cplusplus) */<br>
+<br>
 #endif<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/main.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/main.c?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/main.c?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/main.c (original)<br>
+++ llvm/trunk/tools/llvm-c-test/main.c Thu Feb  4 17:26:19 2016<br>
@@ -13,7 +13,6 @@<br>
<br>
 #include "llvm-c-test.h"<br>
 #include "llvm-c/BitReader.h"<br>
-#include "llvm-c/Core.h"<br>
 #include <stdio.h><br>
 #include <stdlib.h><br>
 #include <string.h><br>
@@ -47,6 +46,9 @@ static void print_usage(void) {<br>
   fprintf(stderr, "    Read lines of triple, hex ascii machine code from stdin "<br>
                   "- print disassembly\n\n");<br>
   fprintf(stderr, "  * --calc\n");<br>
+  fprintf(stderr, "  * --echo\n");<br>
+  fprintf(stderr,<br>
+          "    Read object file form stdin - and print it back out\n\n");<br>
   fprintf(<br>
       stderr,<br>
       "    Read lines of name, rpn from stdin - print generated module\n\n");<br>
@@ -83,6 +85,8 @@ int main(int argc, char **argv) {<br>
     return add_named_metadata_operand();<br>
   } else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) {<br>
     return set_metadata();<br>
+  } else if (argc == 2 && !strcmp(argv[1], "--echo")) {<br>
+    return echo();<br>
   } else {<br>
     print_usage();<br>
   }<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/metadata.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/metadata.c?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/metadata.c?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/metadata.c (original)<br>
+++ llvm/trunk/tools/llvm-c-test/metadata.c Thu Feb  4 17:26:19 2016<br>
@@ -13,7 +13,6 @@<br>
 \*===----------------------------------------------------------------------===*/<br>
<br>
 #include "llvm-c-test.h"<br>
-#include "llvm-c/Core.h"<br>
<br>
 int add_named_metadata_operand(void) {<br>
   LLVMModuleRef m = LLVMModuleCreateWithName("Mod");<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/module.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/module.c?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/module.c?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/module.c (original)<br>
+++ llvm/trunk/tools/llvm-c-test/module.c Thu Feb  4 17:26:19 2016<br>
@@ -14,7 +14,6 @@<br>
<br>
 #include "llvm-c-test.h"<br>
 #include "llvm-c/BitReader.h"<br>
-#include "llvm-c/Core.h"<br>
 #include <stdio.h><br>
 #include <stdlib.h><br>
 #include <string.h><br>
@@ -26,7 +25,7 @@ static void diagnosticHandler(LLVMDiagno<br>
   exit(1);<br>
 }<br>
<br>
-static LLVMModuleRef load_module(bool Lazy, bool New) {<br>
+LLVMModuleRef load_module(bool Lazy, bool New) {<br>
   LLVMMemoryBufferRef MB;<br>
   LLVMModuleRef M;<br>
   char *msg = NULL;<br>
<br>
Modified: llvm/trunk/tools/llvm-c-test/object.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/object.c?rev=259844&r1=259843&r2=259844&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-c-test/object.c?rev=259844&r1=259843&r2=259844&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-c-test/object.c (original)<br>
+++ llvm/trunk/tools/llvm-c-test/object.c Thu Feb  4 17:26:19 2016<br>
@@ -13,7 +13,6 @@<br>
 \*===----------------------------------------------------------------------===*/<br>
<br>
 #include "llvm-c-test.h"<br>
-#include "llvm-c/Core.h"<br>
 #include "llvm-c/Object.h"<br>
 #include <stdio.h><br>
 #include <stdlib.h><br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>