Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -1301,11 +1301,16 @@ void LLVMReplaceAllUsesWith(LLVMValueRef OldVal, LLVMValueRef NewVal); /** - * Determine whether the specified constant instance is constant. + * Determine whether the specified value instance is constant. */ LLVMBool LLVMIsConstant(LLVMValueRef Val); /** + * Determine whether the specified value instance is a global. + */ +LLVMBool LLVMIsGlobalValue(LLVMValueRef Val); + +/** * Determine whether a value instance is undefined. */ LLVMBool LLVMIsUndef(LLVMValueRef Val); Index: lib/IR/Core.cpp =================================================================== --- lib/IR/Core.cpp +++ lib/IR/Core.cpp @@ -703,6 +703,10 @@ return isa(unwrap(Ty)); } +LLVMBool LLVMIsGlobalValue(LLVMValueRef Ty) { + return isa(unwrap(Ty)); +} + LLVMBool LLVMIsNull(LLVMValueRef Val) { if (Constant *C = dyn_cast(unwrap(Val))) return C->isNullValue(); Index: test/Bindings/llvm-c/echo.ll =================================================================== --- /dev/null +++ test/Bindings/llvm-c/echo.ll @@ -0,0 +1,34 @@ +; 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() + +define void @types() { + %1 = alloca half + %2 = alloca float + %3 = alloca double + %4 = alloca x86_fp80 + %5 = alloca fp128 + %6 = alloca ppc_fp128 +; TODO: label ? + %7 = alloca i7 + %8 = alloca void (i1)* +; TODO: struct + %9 = alloca [3 x i22] + %10 = alloca i328 addrspace(5)* + %11 = alloca <5 x i23*> +; TODO: metadata ? + %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 +} Index: tools/llvm-c-test/CMakeLists.txt =================================================================== --- tools/llvm-c-test/CMakeLists.txt +++ tools/llvm-c-test/CMakeLists.txt @@ -37,6 +37,7 @@ add_llvm_tool(llvm-c-test calc.c disassemble.c + echo.cpp helpers.c include-all.c main.c Index: tools/llvm-c-test/calc.c =================================================================== --- tools/llvm-c-test/calc.c +++ tools/llvm-c-test/calc.c @@ -14,7 +14,6 @@ \*===----------------------------------------------------------------------===*/ #include "llvm-c-test.h" -#include "llvm-c/Core.h" #include #include #include Index: tools/llvm-c-test/echo.cpp =================================================================== --- /dev/null +++ tools/llvm-c-test/echo.cpp @@ -0,0 +1,464 @@ +/*===-- echo.c - 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. *| *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" + +#include +#include + +#include "llvm/ADT/DenseMap.h" + +#define TRUE 1 +#define FALSE 0 + +using namespace llvm; + +typedef DenseMap ValueMap; + +typedef struct { + LLVMValueRef Src; + LLVMValueRef Dst; +} ValuePair; + +typedef struct { + size_t length; + ValuePair* ptr; +} ValuesSlice; + +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 = NULL; + 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); +} + +static LLVMValueRef clone_instruction(LLVMValueRef Src, LLVMBuilderRef Builder, ValueMap &VMap) { + const char *Name = LLVMGetValueName(Src); + + // Maybe it is a contant + if (LLVMIsConstant(Src)) { + LLVMModuleRef M = get_module(Builder); + + // Maybe it is a symbol + if (LLVMIsGlobalValue(Src)) { + // Try function + LLVMValueRef Dst = LLVMGetNamedFunction(M, Name); + if (Dst != NULL) { + return Dst; + } + + Dst = LLVMGetNamedGlobal(M, Name); + if (Dst != NULL) { + return Dst; + } + + fprintf(stderr, "Could not find @%s\n", Name); + exit(-1); + } + + // It must be a literal + LLVMContextRef Ctx = LLVMGetModuleContext(M); + return clone_literal(Src, Ctx); + } + + // Maybe it is an undef + if (LLVMIsUndef(Src)) { + LLVMContextRef Ctx = LLVMGetModuleContext(get_module(Builder)); + LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx); + return LLVMGetUndef(Ty); + } + + // Check if this is somethign we already computed. + { + auto i = VMap.find(Src); + if (i != VMap.end()) { + return i->second; + } + } + + // This is not in the map, generate. + LLVMValueRef Dst = NULL; + + LLVMOpcode Op = LLVMGetInstructionOpcode(Src); + switch(Op) { + case LLVMRet: { + int OpCount = LLVMGetNumOperands(Src); + Dst = (OpCount == 0) + ? LLVMBuildRetVoid(Builder) + : LLVMBuildRet( + Builder, + clone_instruction(LLVMGetOperand(Src, 0), Builder, VMap)); + break; + } + case LLVMBr: + case LLVMSwitch: + case LLVMIndirectBr: + case LLVMInvoke: + case LLVMUnreachable: + break; + case LLVMAdd: { + LLVMValueRef LHS = clone_instruction(LLVMGetOperand(Src, 0), Builder, VMap); + LLVMValueRef RHS = clone_instruction(LLVMGetOperand(Src, 1), Builder, VMap); + Dst = LLVMBuildAdd(Builder, LHS, RHS, Name); + break; + } + case LLVMAlloca: { + // TODO: Add a binding for AllocaInst::getAllocatedType + LLVMTypeRef Ty = LLVMGetElementType(LLVMTypeOf(Src)); + Dst = LLVMBuildAlloca(Builder, Ty, Name); + break; + } + case LLVMCall: { + // TODO: Add binding for CallInst API + int ArgCount = LLVMGetNumOperands(Src) - 1; + LLVMValueRef* Args = (LLVMValueRef*) malloc(ArgCount * sizeof(LLVMValueRef)); + for (int i = 0; i < ArgCount; i++) { + Args[i] = clone_instruction(LLVMGetOperand(Src, i), Builder, VMap); + } + + LLVMValueRef Fn = clone_instruction(LLVMGetOperand(Src, ArgCount), Builder, VMap); + Dst = LLVMBuildCall(Builder, Fn, Args, ArgCount, Name); + free(Args); + break; + } + default: + break; + } + + if (Dst == NULL) { + fprintf(stderr, "%d is not a supported opcode\n", Op); + exit(-1); + } + + // This is very inneffiscient, but we don't really care. + VMap[Src] = Dst; + + return Dst; +} + +static LLVMBasicBlockRef clone_bb(LLVMBasicBlockRef Src, LLVMValueRef Dst, ValueMap &VMap) { + // TODO: Extend C API to be able to get that name. + LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Dst, ""); + + LLVMValueRef First = LLVMGetFirstInstruction(Src); + LLVMValueRef Last = LLVMGetLastInstruction(Src); + + if (First == NULL) { + if (Last != NULL) { + 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 = NULL; + while(TRUE) { + clone_instruction(Cur, Builder, VMap); + Next = LLVMGetNextInstruction(Cur); + if (Next == NULL) { + 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 = NULL; + while(TRUE) { + clone_bb(Cur, Dst, VMap); + Count--; + Next = LLVMGetNextBasicBlock(Cur); + if (Next == NULL) { + 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 = NULL; + LLVMValueRef DstNext = NULL; + while (TRUE) { + const char *Name = LLVMGetValueName(SrcCur); + LLVMSetValueName(DstCur, Name); + + VMap[SrcCur] = DstCur; + + Count--; + SrcNext = LLVMGetNextParam(SrcCur); + DstNext = LLVMGetNextParam(DstCur); + if (SrcNext == NULL && DstNext == NULL) { + 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 == NULL) { + fprintf(stderr, "SrcNext was unexpectedly null\n"); + exit(-1); + } + + if (DstNext == NULL) { + 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 iterration\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 != NULL) { + 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 = NULL; + while (TRUE) { + clone_function(Cur, Dst); + Next = LLVMGetNextFunction(Cur); + if (Next == NULL) { + 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_from_bitcode(); + + LLVMContextRef Ctx = LLVMContextCreate(); + LLVMModuleRef Dst = LLVMModuleCreateWithNameInContext("", Ctx); + + clone_functions(Src, Dst); + char *Str = LLVMPrintModuleToString(Dst); + fputs(Str, stdout); + + LLVMDisposeMessage(Str); + LLVMDisposeModule(Dst); + LLVMContextDispose(Ctx); + + return 0; +} Index: tools/llvm-c-test/llvm-c-test.h =================================================================== --- tools/llvm-c-test/llvm-c-test.h +++ tools/llvm-c-test/llvm-c-test.h @@ -13,10 +13,17 @@ #ifndef LLVM_C_TEST_H #define LLVM_C_TEST_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_from_bitcode(void); int module_dump(void); int module_list_functions(void); int module_list_globals(void); @@ -38,4 +45,11 @@ // targets.c int targets_list(void); +// echo.c +int echo(void); + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + #endif Index: tools/llvm-c-test/main.c =================================================================== --- tools/llvm-c-test/main.c +++ 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 #include #include @@ -39,6 +38,9 @@ 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"); @@ -69,6 +71,8 @@ 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(); } Index: tools/llvm-c-test/metadata.c =================================================================== --- tools/llvm-c-test/metadata.c +++ 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"); Index: tools/llvm-c-test/module.c =================================================================== --- tools/llvm-c-test/module.c +++ tools/llvm-c-test/module.c @@ -14,12 +14,11 @@ #include "llvm-c-test.h" #include "llvm-c/BitReader.h" -#include "llvm-c/Core.h" #include #include #include -static LLVMModuleRef load_module(void) { +LLVMModuleRef load_module_from_bitcode(void) { LLVMMemoryBufferRef MB; LLVMModuleRef M; char *msg = NULL; @@ -40,7 +39,7 @@ } int module_dump(void) { - LLVMModuleRef M = load_module(); + LLVMModuleRef M = load_module_from_bitcode(); char *irstr = LLVMPrintModuleToString(M); puts(irstr); @@ -52,7 +51,7 @@ } int module_list_functions(void) { - LLVMModuleRef M = load_module(); + LLVMModuleRef M = load_module_from_bitcode(); LLVMValueRef f; f = LLVMGetFirstFunction(M); @@ -93,7 +92,7 @@ } int module_list_globals(void) { - LLVMModuleRef M = load_module(); + LLVMModuleRef M = load_module_from_bitcode(); LLVMValueRef g; g = LLVMGetFirstGlobal(M);