summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/test/Bindings/llvm-c/echo.ll32
-rw-r--r--llvm/tools/llvm-c-test/CMakeLists.txt1
-rw-r--r--llvm/tools/llvm-c-test/calc.c1
-rw-r--r--llvm/tools/llvm-c-test/echo.cpp468
-rw-r--r--llvm/tools/llvm-c-test/llvm-c-test.h13
-rw-r--r--llvm/tools/llvm-c-test/main.c6
-rw-r--r--llvm/tools/llvm-c-test/metadata.c1
-rw-r--r--llvm/tools/llvm-c-test/module.c3
-rw-r--r--llvm/tools/llvm-c-test/object.c1
9 files changed, 520 insertions, 6 deletions
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
new file mode 100644
index 00000000000..f5729320369
--- /dev/null
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -0,0 +1,32 @@
+; RUN: llvm-as < %s | llvm-dis > %t.orig
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
+; RUN: diff %t.orig %t.echo
+
+declare void @decl()
+
+; TODO: label, struct and metadata types
+define void @types() {
+ %1 = alloca half
+ %2 = alloca float
+ %3 = alloca double
+ %4 = alloca x86_fp80
+ %5 = alloca fp128
+ %6 = alloca ppc_fp128
+ %7 = alloca i7
+ %8 = alloca void (i1)*
+ %9 = alloca [3 x i22]
+ %10 = alloca i328 addrspace(5)*
+ %11 = alloca <5 x i23*>
+ %12 = alloca x86_mmx
+ ret void
+}
+
+define i32 @add(i32 %a, i32 %b) {
+ %1 = add i32 %a, %b
+ ret i32 %1
+}
+
+define i32 @call() {
+ %1 = call i32 @add(i32 23, i32 19)
+ ret i32 %1
+}
diff --git a/llvm/tools/llvm-c-test/CMakeLists.txt b/llvm/tools/llvm-c-test/CMakeLists.txt
index f22dffb30e8..405dc3df4ee 100644
--- a/llvm/tools/llvm-c-test/CMakeLists.txt
+++ b/llvm/tools/llvm-c-test/CMakeLists.txt
@@ -37,6 +37,7 @@ endif ()
add_llvm_tool(llvm-c-test
calc.c
disassemble.c
+ echo.cpp
helpers.c
include-all.c
main.c
diff --git a/llvm/tools/llvm-c-test/calc.c b/llvm/tools/llvm-c-test/calc.c
index 3119ccf8e9a..646b5b056ac 100644
--- a/llvm/tools/llvm-c-test/calc.c
+++ b/llvm/tools/llvm-c-test/calc.c
@@ -14,7 +14,6 @@
\*===----------------------------------------------------------------------===*/
#include "llvm-c-test.h"
-#include "llvm-c/Core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
new file mode 100644
index 00000000000..bb1a50a4675
--- /dev/null
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -0,0 +1,468 @@
+//===-- echo.cpp - tool for testing libLLVM and llvm-c API ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the --echo commands in llvm-c-test.
+//
+// This command uses the C API to read a module and output an exact copy of it
+// as output. It is used to check that the resulting module matches the input
+// to validate that the C API can read and write modules properly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c-test.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace llvm;
+
+// Provide DenseMapInfo for C API opaque types.
+template<typename T>
+struct CAPIDenseMap {};
+
+// The default DenseMapInfo require to know about pointer alignement.
+// Because the C API uses opaques pointer types, their alignement is unknown.
+// As a result, we need to roll out our own implementation.
+template<typename T>
+struct CAPIDenseMap<T*> {
+ struct CAPIDenseMapInfo {
+ static inline T* getEmptyKey() {
+ uintptr_t Val = static_cast<uintptr_t>(-1);
+ return reinterpret_cast<T*>(Val);
+ }
+ static inline T* getTombstoneKey() {
+ uintptr_t Val = static_cast<uintptr_t>(-2);
+ return reinterpret_cast<T*>(Val);
+ }
+ static unsigned getHashValue(const T *PtrVal) {
+ return hash_value(PtrVal);
+ }
+ static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
+ };
+
+ typedef DenseMap<T*, T*, CAPIDenseMapInfo> Map;
+};
+
+typedef CAPIDenseMap<LLVMValueRef>::Map ValueMap;
+
+static LLVMTypeRef clone_type(LLVMTypeRef Src, LLVMContextRef Ctx) {
+ LLVMTypeKind Kind = LLVMGetTypeKind(Src);
+ switch (Kind) {
+ case LLVMVoidTypeKind:
+ return LLVMVoidTypeInContext(Ctx);
+ case LLVMHalfTypeKind:
+ return LLVMHalfTypeInContext(Ctx);
+ case LLVMFloatTypeKind:
+ return LLVMFloatTypeInContext(Ctx);
+ case LLVMDoubleTypeKind:
+ return LLVMDoubleTypeInContext(Ctx);
+ case LLVMX86_FP80TypeKind:
+ return LLVMX86FP80TypeInContext(Ctx);
+ case LLVMFP128TypeKind:
+ return LLVMFP128TypeInContext(Ctx);
+ case LLVMPPC_FP128TypeKind:
+ return LLVMPPCFP128TypeInContext(Ctx);
+ case LLVMLabelTypeKind:
+ return LLVMLabelTypeInContext(Ctx);
+ case LLVMIntegerTypeKind:
+ return LLVMIntTypeInContext(Ctx, LLVMGetIntTypeWidth(Src));
+ case LLVMFunctionTypeKind: {
+ unsigned ParamCount = LLVMCountParamTypes(Src);
+ LLVMTypeRef* Params = nullptr;
+ if (ParamCount > 0) {
+ Params = (LLVMTypeRef*) malloc(ParamCount * sizeof(LLVMTypeRef));
+ LLVMGetParamTypes(Src, Params);
+ for (unsigned i = 0; i < ParamCount; i++) {
+ Params[i] = clone_type(Params[i], Ctx);
+ }
+ }
+
+ LLVMTypeRef FunTy = LLVMFunctionType(
+ clone_type(LLVMGetReturnType(Src), Ctx),
+ Params, ParamCount,
+ LLVMIsFunctionVarArg(Src)
+ );
+
+ if (ParamCount > 0)
+ free(Params);
+
+ return FunTy;
+ }
+ case LLVMStructTypeKind:
+ break;
+ case LLVMArrayTypeKind:
+ return LLVMArrayType(
+ clone_type(LLVMGetElementType(Src), Ctx),
+ LLVMGetArrayLength(Src)
+ );
+ case LLVMPointerTypeKind:
+ return LLVMPointerType(
+ clone_type(LLVMGetElementType(Src), Ctx),
+ LLVMGetPointerAddressSpace(Src)
+ );
+ case LLVMVectorTypeKind:
+ return LLVMVectorType(
+ clone_type(LLVMGetElementType(Src), Ctx),
+ LLVMGetVectorSize(Src)
+ );
+ case LLVMMetadataTypeKind:
+ break;
+ case LLVMX86_MMXTypeKind:
+ return LLVMX86MMXTypeInContext(Ctx);
+ default:
+ break;
+ }
+
+ fprintf(stderr, "%d is not a supported typekind\n", Kind);
+ exit(-1);
+}
+
+static LLVMValueRef clone_literal(LLVMValueRef Src, LLVMContextRef Ctx) {
+ LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
+
+ LLVMTypeKind Kind = LLVMGetTypeKind(Ty);
+ switch (Kind) {
+ case LLVMIntegerTypeKind:
+ return LLVMConstInt(Ty, LLVMConstIntGetZExtValue(Src), false);
+ default:
+ break;
+ }
+
+ fprintf(stderr, "%d is not a supported constant typekind\n", Kind);
+ exit(-1);
+}
+
+static LLVMModuleRef get_module(LLVMBuilderRef Builder) {
+ LLVMBasicBlockRef BB = LLVMGetInsertBlock(Builder);
+ LLVMValueRef Fn = LLVMGetBasicBlockParent(BB);
+ return LLVMGetGlobalParent(Fn);
+}
+
+// Try to clone everything in the llvm::Value hierarchy.
+static LLVMValueRef clone_value(LLVMValueRef Src, LLVMBuilderRef Builder, ValueMap &VMap) {
+ const char *Name = LLVMGetValueName(Src);
+
+ // First, the value may be constant.
+ if (LLVMIsAConstant(Src)) {
+ LLVMModuleRef M = get_module(Builder);
+
+ // Maybe it is a symbol
+ if (LLVMIsAGlobalValue(Src)) {
+ // Try function
+ LLVMValueRef Dst = LLVMGetNamedFunction(M, Name);
+ if (Dst != nullptr)
+ return Dst;
+
+ // Try global variable
+ Dst = LLVMGetNamedGlobal(M, Name);
+ if (Dst != nullptr)
+ return Dst;
+
+ fprintf(stderr, "Could not find @%s\n", Name);
+ exit(-1);
+ }
+
+ // Try literal
+ LLVMContextRef Ctx = LLVMGetModuleContext(M);
+ return clone_literal(Src, Ctx);
+ }
+
+ // Try undef
+ if (LLVMIsUndef(Src)) {
+ LLVMContextRef Ctx = LLVMGetModuleContext(get_module(Builder));
+ LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
+ return LLVMGetUndef(Ty);
+ }
+
+ // Check if this is something we already computed.
+ {
+ auto i = VMap.find(Src);
+ if (i != VMap.end())
+ return i->second;
+ }
+
+ // We tried everything, it must be an instruction
+ // that hasn't been generated already.
+ LLVMValueRef Dst = nullptr;
+
+ LLVMOpcode Op = LLVMGetInstructionOpcode(Src);
+ switch(Op) {
+ case LLVMRet: {
+ int OpCount = LLVMGetNumOperands(Src);
+ if (OpCount == 0)
+ Dst = LLVMBuildRetVoid(Builder);
+ else
+ Dst = LLVMBuildRet(Builder, clone_value(LLVMGetOperand(Src, 0),
+ Builder, VMap));
+ break;
+ }
+ case LLVMBr:
+ case LLVMSwitch:
+ case LLVMIndirectBr:
+ case LLVMInvoke:
+ case LLVMUnreachable:
+ break;
+ case LLVMAdd: {
+ LLVMValueRef LHS = clone_value(LLVMGetOperand(Src, 0), Builder, VMap);
+ LLVMValueRef RHS = clone_value(LLVMGetOperand(Src, 1), Builder, VMap);
+ Dst = LLVMBuildAdd(Builder, LHS, RHS, Name);
+ break;
+ }
+ case LLVMAlloca: {
+ LLVMTypeRef Ty = LLVMGetElementType(LLVMTypeOf(Src));
+ Dst = LLVMBuildAlloca(Builder, Ty, Name);
+ break;
+ }
+ case LLVMCall: {
+ int ArgCount = LLVMGetNumOperands(Src) - 1;
+ SmallVector<LLVMValueRef, 8> Args;
+ for (int i = 0; i < ArgCount; i++)
+ Args.push_back(clone_value(LLVMGetOperand(Src, i), Builder, VMap));
+ LLVMValueRef Fn = clone_value(LLVMGetOperand(Src, ArgCount), Builder, VMap);
+ Dst = LLVMBuildCall(Builder, Fn, Args.data(), ArgCount, Name);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (Dst == nullptr) {
+ fprintf(stderr, "%d is not a supported opcode\n", Op);
+ exit(-1);
+ }
+
+ return VMap[Src] = Dst;
+}
+
+static LLVMBasicBlockRef clone_bb(LLVMBasicBlockRef Src, LLVMValueRef Dst, ValueMap &VMap) {
+ LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Dst, "");
+
+ LLVMValueRef First = LLVMGetFirstInstruction(Src);
+ LLVMValueRef Last = LLVMGetLastInstruction(Src);
+
+ if (First == nullptr) {
+ if (Last != nullptr) {
+ fprintf(stderr, "Has no first instruction, but last one\n");
+ exit(-1);
+ }
+
+ return BB;
+ }
+
+ LLVMContextRef Ctx = LLVMGetModuleContext(LLVMGetGlobalParent(Dst));
+ LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx);
+ LLVMPositionBuilderAtEnd(Builder, BB);
+
+ LLVMValueRef Cur = First;
+ LLVMValueRef Next = nullptr;
+ while(true) {
+ clone_value(Cur, Builder, VMap);
+ Next = LLVMGetNextInstruction(Cur);
+ if (Next == nullptr) {
+ if (Cur != Last) {
+ fprintf(stderr, "Final instruction does not match Last\n");
+ exit(-1);
+ }
+
+ break;
+ }
+
+ LLVMValueRef Prev = LLVMGetPreviousInstruction(Next);
+ if (Prev != Cur) {
+ fprintf(stderr, "Next.Previous instruction is not Current\n");
+ exit(-1);
+ }
+
+ Cur = Next;
+ }
+
+ LLVMDisposeBuilder(Builder);
+ return BB;
+}
+
+static void clone_bbs(LLVMValueRef Src, LLVMValueRef Dst, ValueMap &VMap) {
+ unsigned Count = LLVMCountBasicBlocks(Src);
+ if (Count == 0)
+ return;
+
+ LLVMBasicBlockRef First = LLVMGetFirstBasicBlock(Src);
+ LLVMBasicBlockRef Last = LLVMGetLastBasicBlock(Src);
+
+ LLVMBasicBlockRef Cur = First;
+ LLVMBasicBlockRef Next = nullptr;
+ while(true) {
+ clone_bb(Cur, Dst, VMap);
+ Count--;
+ Next = LLVMGetNextBasicBlock(Cur);
+ if (Next == nullptr) {
+ if (Cur != Last) {
+ fprintf(stderr, "Final basic block does not match Last\n");
+ exit(-1);
+ }
+
+ break;
+ }
+
+ LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Next);
+ if (Prev != Cur) {
+ fprintf(stderr, "Next.Previous basic bloc is not Current\n");
+ exit(-1);
+ }
+
+ Cur = Next;
+ }
+
+ if (Count != 0) {
+ fprintf(stderr, "Basic block count does not match iterration\n");
+ exit(-1);
+ }
+}
+
+static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) {
+ unsigned Count = LLVMCountParams(Src);
+ if (Count != LLVMCountParams(Dst)) {
+ fprintf(stderr, "Parameter count mismatch\n");
+ exit(-1);
+ }
+
+ ValueMap VMap;
+ if (Count == 0)
+ return VMap;
+
+ LLVMValueRef SrcFirst = LLVMGetFirstParam(Src);
+ LLVMValueRef DstFirst = LLVMGetFirstParam(Dst);
+ LLVMValueRef SrcLast = LLVMGetLastParam(Src);
+ LLVMValueRef DstLast = LLVMGetLastParam(Dst);
+
+ LLVMValueRef SrcCur = SrcFirst;
+ LLVMValueRef DstCur = DstFirst;
+ LLVMValueRef SrcNext = nullptr;
+ LLVMValueRef DstNext = nullptr;
+ while (true) {
+ const char *Name = LLVMGetValueName(SrcCur);
+ LLVMSetValueName(DstCur, Name);
+
+ VMap[SrcCur] = DstCur;
+
+ Count--;
+ SrcNext = LLVMGetNextParam(SrcCur);
+ DstNext = LLVMGetNextParam(DstCur);
+ if (SrcNext == nullptr && DstNext == nullptr) {
+ if (SrcCur != SrcLast) {
+ fprintf(stderr, "SrcLast param does not match End\n");
+ exit(-1);
+ }
+
+ if (DstCur != DstLast) {
+ fprintf(stderr, "DstLast param does not match End\n");
+ exit(-1);
+ }
+
+ break;
+ }
+
+ if (SrcNext == nullptr) {
+ fprintf(stderr, "SrcNext was unexpectedly null\n");
+ exit(-1);
+ }
+
+ if (DstNext == nullptr) {
+ fprintf(stderr, "DstNext was unexpectedly null\n");
+ exit(-1);
+ }
+
+ LLVMValueRef SrcPrev = LLVMGetPreviousParam(SrcNext);
+ if (SrcPrev != SrcCur) {
+ fprintf(stderr, "SrcNext.Previous param is not Current\n");
+ exit(-1);
+ }
+
+ LLVMValueRef DstPrev = LLVMGetPreviousParam(DstNext);
+ if (DstPrev != DstCur) {
+ fprintf(stderr, "DstNext.Previous param is not Current\n");
+ exit(-1);
+ }
+
+ SrcCur = SrcNext;
+ DstCur = DstNext;
+ }
+
+ if (Count != 0) {
+ fprintf(stderr, "Parameter count does not match iteration\n");
+ exit(-1);
+ }
+
+ return VMap;
+}
+
+static LLVMValueRef clone_function(LLVMValueRef Src, LLVMModuleRef Dst) {
+ const char *Name = LLVMGetValueName(Src);
+ LLVMValueRef Fun = LLVMGetNamedFunction(Dst, Name);
+ if (Fun != nullptr)
+ return Fun;
+
+ LLVMTypeRef SrcTy = LLVMTypeOf(Src);
+ LLVMTypeRef DstTy = clone_type(SrcTy, LLVMGetModuleContext(Dst));
+ LLVMTypeRef FunTy = LLVMGetElementType(DstTy);
+
+ Fun = LLVMAddFunction(Dst, Name, FunTy);
+
+ ValueMap VMap = clone_params(Src, Fun);
+ clone_bbs(Src, Fun, VMap);
+
+ return Fun;
+}
+
+static void clone_functions(LLVMModuleRef Src, LLVMModuleRef Dst) {
+ LLVMValueRef Begin = LLVMGetFirstFunction(Src);
+ LLVMValueRef End = LLVMGetLastFunction(Src);
+
+ LLVMValueRef Cur = Begin;
+ LLVMValueRef Next = nullptr;
+ while (true) {
+ clone_function(Cur, Dst);
+ Next = LLVMGetNextFunction(Cur);
+ if (Next == nullptr) {
+ if (Cur != End) {
+ fprintf(stderr, "Last function does not match End\n");
+ exit(-1);
+ }
+
+ break;
+ }
+
+ LLVMValueRef Prev = LLVMGetPreviousFunction(Next);
+ if (Prev != Cur) {
+ fprintf(stderr, "Next.Previous function is not Current\n");
+ exit(-1);
+ }
+
+ Cur = Next;
+ }
+}
+
+int echo(void) {
+ LLVMEnablePrettyStackTrace();
+
+ LLVMModuleRef Src = load_module(false, true);
+
+ LLVMContextRef Ctx = LLVMContextCreate();
+ LLVMModuleRef Dst = LLVMModuleCreateWithNameInContext("<stdin>", Ctx);
+
+ clone_functions(Src, Dst);
+ char *Str = LLVMPrintModuleToString(Dst);
+ fputs(Str, stdout);
+
+ LLVMDisposeMessage(Str);
+ LLVMDisposeModule(Dst);
+ LLVMContextDispose(Ctx);
+
+ return 0;
+}
diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h
index 7929fc4d19b..72f3ccb44ab 100644
--- a/llvm/tools/llvm-c-test/llvm-c-test.h
+++ b/llvm/tools/llvm-c-test/llvm-c-test.h
@@ -14,11 +14,17 @@
#define LLVM_C_TEST_H
#include <stdbool.h>
+#include "llvm-c/Core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
// helpers.c
void tokenize_stdin(void (*cb)(char **tokens, int ntokens));
// module.c
+LLVMModuleRef load_module(bool Lazy, bool New);
int module_dump(bool Lazy, bool New);
int module_list_functions(void);
int module_list_globals(void);
@@ -40,4 +46,11 @@ int object_list_symbols(void);
// targets.c
int targets_list(void);
+// echo.c
+int echo(void);
+
+#ifdef __cplusplus
+}
+#endif /* !defined(__cplusplus) */
+
#endif
diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c
index e6b6e17098b..10d7d75f4ff 100644
--- a/llvm/tools/llvm-c-test/main.c
+++ b/llvm/tools/llvm-c-test/main.c
@@ -13,7 +13,6 @@
#include "llvm-c-test.h"
#include "llvm-c/BitReader.h"
-#include "llvm-c/Core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -47,6 +46,9 @@ static void print_usage(void) {
fprintf(stderr, " Read lines of triple, hex ascii machine code from stdin "
"- print disassembly\n\n");
fprintf(stderr, " * --calc\n");
+ fprintf(stderr, " * --echo\n");
+ fprintf(stderr,
+ " Read object file form stdin - and print it back out\n\n");
fprintf(
stderr,
" Read lines of name, rpn from stdin - print generated module\n\n");
@@ -83,6 +85,8 @@ int main(int argc, char **argv) {
return add_named_metadata_operand();
} else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) {
return set_metadata();
+ } else if (argc == 2 && !strcmp(argv[1], "--echo")) {
+ return echo();
} else {
print_usage();
}
diff --git a/llvm/tools/llvm-c-test/metadata.c b/llvm/tools/llvm-c-test/metadata.c
index b64a696c528..eabe75f1c80 100644
--- a/llvm/tools/llvm-c-test/metadata.c
+++ b/llvm/tools/llvm-c-test/metadata.c
@@ -13,7 +13,6 @@
\*===----------------------------------------------------------------------===*/
#include "llvm-c-test.h"
-#include "llvm-c/Core.h"
int add_named_metadata_operand(void) {
LLVMModuleRef m = LLVMModuleCreateWithName("Mod");
diff --git a/llvm/tools/llvm-c-test/module.c b/llvm/tools/llvm-c-test/module.c
index a6c47bf5fa1..16ed6dbf435 100644
--- a/llvm/tools/llvm-c-test/module.c
+++ b/llvm/tools/llvm-c-test/module.c
@@ -14,7 +14,6 @@
#include "llvm-c-test.h"
#include "llvm-c/BitReader.h"
-#include "llvm-c/Core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -26,7 +25,7 @@ static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {
exit(1);
}
-static LLVMModuleRef load_module(bool Lazy, bool New) {
+LLVMModuleRef load_module(bool Lazy, bool New) {
LLVMMemoryBufferRef MB;
LLVMModuleRef M;
char *msg = NULL;
diff --git a/llvm/tools/llvm-c-test/object.c b/llvm/tools/llvm-c-test/object.c
index 43521787b60..a5421d9066d 100644
--- a/llvm/tools/llvm-c-test/object.c
+++ b/llvm/tools/llvm-c-test/object.c
@@ -13,7 +13,6 @@
\*===----------------------------------------------------------------------===*/
#include "llvm-c-test.h"
-#include "llvm-c/Core.h"
#include "llvm-c/Object.h"
#include <stdio.h>
#include <stdlib.h>
OpenPOWER on IntegriCloud