diff options
Diffstat (limited to 'tools/llvm-c-test/echo.cpp')
-rw-r--r-- | tools/llvm-c-test/echo.cpp | 958 |
1 files changed, 958 insertions, 0 deletions
diff --git a/tools/llvm-c-test/echo.cpp b/tools/llvm-c-test/echo.cpp new file mode 100644 index 0000000000000..72ff138c74e32 --- /dev/null +++ b/tools/llvm-c-test/echo.cpp @@ -0,0 +1,958 @@ +//===-- 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 command 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-c/Target.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/ErrorHandling.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; +typedef CAPIDenseMap<LLVMBasicBlockRef>::Map BasicBlockMap; + +struct TypeCloner { + LLVMModuleRef M; + LLVMContextRef Ctx; + + TypeCloner(LLVMModuleRef M): M(M), Ctx(LLVMGetModuleContext(M)) {} + + LLVMTypeRef Clone(LLVMValueRef Src) { + return Clone(LLVMTypeOf(Src)); + } + + LLVMTypeRef Clone(LLVMTypeRef Src) { + 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(Params[i]); + } + + LLVMTypeRef FunTy = LLVMFunctionType(Clone(LLVMGetReturnType(Src)), + Params, ParamCount, + LLVMIsFunctionVarArg(Src)); + if (ParamCount > 0) + free(Params); + return FunTy; + } + case LLVMStructTypeKind: { + LLVMTypeRef S = nullptr; + const char *Name = LLVMGetStructName(Src); + if (Name) { + S = LLVMGetTypeByName(M, Name); + if (S) + return S; + S = LLVMStructCreateNamed(Ctx, Name); + if (LLVMIsOpaqueStruct(Src)) + return S; + } + + unsigned EltCount = LLVMCountStructElementTypes(Src); + SmallVector<LLVMTypeRef, 8> Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(Clone(LLVMStructGetTypeAtIndex(Src, i))); + if (Name) + LLVMStructSetBody(S, Elts.data(), EltCount, LLVMIsPackedStruct(Src)); + else + S = LLVMStructTypeInContext(Ctx, Elts.data(), EltCount, + LLVMIsPackedStruct(Src)); + return S; + } + case LLVMArrayTypeKind: + return LLVMArrayType( + Clone(LLVMGetElementType(Src)), + LLVMGetArrayLength(Src) + ); + case LLVMPointerTypeKind: + return LLVMPointerType( + Clone(LLVMGetElementType(Src)), + LLVMGetPointerAddressSpace(Src) + ); + case LLVMVectorTypeKind: + return LLVMVectorType( + Clone(LLVMGetElementType(Src)), + 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 ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) { + unsigned Count = LLVMCountParams(Src); + if (Count != LLVMCountParams(Dst)) + report_fatal_error("Parameter count mismatch"); + + 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) + report_fatal_error("SrcLast param does not match End"); + if (DstCur != DstLast) + report_fatal_error("DstLast param does not match End"); + break; + } + + if (SrcNext == nullptr) + report_fatal_error("SrcNext was unexpectedly null"); + if (DstNext == nullptr) + report_fatal_error("DstNext was unexpectedly null"); + + LLVMValueRef SrcPrev = LLVMGetPreviousParam(SrcNext); + if (SrcPrev != SrcCur) + report_fatal_error("SrcNext.Previous param is not Current"); + + LLVMValueRef DstPrev = LLVMGetPreviousParam(DstNext); + if (DstPrev != DstCur) + report_fatal_error("DstNext.Previous param is not Current"); + + SrcCur = SrcNext; + DstCur = DstNext; + } + + if (Count != 0) + report_fatal_error("Parameter count does not match iteration"); + + return VMap; +} + +static void check_value_kind(LLVMValueRef V, LLVMValueKind K) { + if (LLVMGetValueKind(V) != K) + report_fatal_error("LLVMGetValueKind returned incorrect type"); +} + +static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M); + +static LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) { + LLVMValueRef Ret = clone_constant_impl(Cst, M); + check_value_kind(Ret, LLVMGetValueKind(Cst)); + return Ret; +} + +static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) { + if (!LLVMIsAConstant(Cst)) + report_fatal_error("Expected a constant"); + + // Maybe it is a symbol + if (LLVMIsAGlobalValue(Cst)) { + const char *Name = LLVMGetValueName(Cst); + + // Try function + if (LLVMIsAFunction(Cst)) { + check_value_kind(Cst, LLVMFunctionValueKind); + LLVMValueRef Dst = LLVMGetNamedFunction(M, Name); + if (Dst) + return Dst; + report_fatal_error("Could not find function"); + } + + // Try global variable + if (LLVMIsAGlobalVariable(Cst)) { + check_value_kind(Cst, LLVMGlobalVariableValueKind); + LLVMValueRef Dst = LLVMGetNamedGlobal(M, Name); + if (Dst) + return Dst; + report_fatal_error("Could not find function"); + } + + fprintf(stderr, "Could not find @%s\n", Name); + exit(-1); + } + + // Try integer literal + if (LLVMIsAConstantInt(Cst)) { + check_value_kind(Cst, LLVMConstantIntValueKind); + return LLVMConstInt(TypeCloner(M).Clone(Cst), + LLVMConstIntGetZExtValue(Cst), false); + } + + // Try zeroinitializer + if (LLVMIsAConstantAggregateZero(Cst)) { + check_value_kind(Cst, LLVMConstantAggregateZeroValueKind); + return LLVMConstNull(TypeCloner(M).Clone(Cst)); + } + + // Try constant array + if (LLVMIsAConstantArray(Cst)) { + check_value_kind(Cst, LLVMConstantArrayValueKind); + LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); + unsigned EltCount = LLVMGetArrayLength(Ty); + SmallVector<LLVMValueRef, 8> Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(clone_constant(LLVMGetOperand(Cst, i), M)); + return LLVMConstArray(LLVMGetElementType(Ty), Elts.data(), EltCount); + } + + // Try contant data array + if (LLVMIsAConstantDataArray(Cst)) { + check_value_kind(Cst, LLVMConstantDataArrayValueKind); + LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); + unsigned EltCount = LLVMGetArrayLength(Ty); + SmallVector<LLVMValueRef, 8> Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(clone_constant(LLVMGetElementAsConstant(Cst, i), M)); + return LLVMConstArray(LLVMGetElementType(Ty), Elts.data(), EltCount); + } + + // Try constant struct + if (LLVMIsAConstantStruct(Cst)) { + check_value_kind(Cst, LLVMConstantStructValueKind); + LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); + unsigned EltCount = LLVMCountStructElementTypes(Ty); + SmallVector<LLVMValueRef, 8> Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(clone_constant(LLVMGetOperand(Cst, i), M)); + if (LLVMGetStructName(Ty)) + return LLVMConstNamedStruct(Ty, Elts.data(), EltCount); + return LLVMConstStructInContext(LLVMGetModuleContext(M), Elts.data(), + EltCount, LLVMIsPackedStruct(Ty)); + } + + // Try undef + if (LLVMIsUndef(Cst)) { + check_value_kind(Cst, LLVMUndefValueValueKind); + return LLVMGetUndef(TypeCloner(M).Clone(Cst)); + } + + // Try float literal + if (LLVMIsAConstantFP(Cst)) { + check_value_kind(Cst, LLVMConstantFPValueKind); + report_fatal_error("ConstantFP is not supported"); + } + + // This kind of constant is not supported + if (!LLVMIsAConstantExpr(Cst)) + report_fatal_error("Expected a constant expression"); + + // At this point, it must be a constant expression + check_value_kind(Cst, LLVMConstantExprValueKind); + + LLVMOpcode Op = LLVMGetConstOpcode(Cst); + switch(Op) { + case LLVMBitCast: + return LLVMConstBitCast(clone_constant(LLVMGetOperand(Cst, 0), M), + TypeCloner(M).Clone(Cst)); + default: + fprintf(stderr, "%d is not a supported opcode\n", Op); + exit(-1); + } +} + +struct FunCloner { + LLVMValueRef Fun; + LLVMModuleRef M; + + ValueMap VMap; + BasicBlockMap BBMap; + + FunCloner(LLVMValueRef Src, LLVMValueRef Dst): Fun(Dst), + M(LLVMGetGlobalParent(Fun)), VMap(clone_params(Src, Dst)) {} + + LLVMTypeRef CloneType(LLVMTypeRef Src) { + return TypeCloner(M).Clone(Src); + } + + LLVMTypeRef CloneType(LLVMValueRef Src) { + return TypeCloner(M).Clone(Src); + } + + // Try to clone everything in the llvm::Value hierarchy. + LLVMValueRef CloneValue(LLVMValueRef Src) { + // First, the value may be constant. + if (LLVMIsAConstant(Src)) + return clone_constant(Src, M); + + // Function argument should always be in the map already. + auto i = VMap.find(Src); + if (i != VMap.end()) + return i->second; + + if (!LLVMIsAInstruction(Src)) + report_fatal_error("Expected an instruction"); + + auto Ctx = LLVMGetModuleContext(M); + auto Builder = LLVMCreateBuilderInContext(Ctx); + auto BB = DeclareBB(LLVMGetInstructionParent(Src)); + LLVMPositionBuilderAtEnd(Builder, BB); + auto Dst = CloneInstruction(Src, Builder); + LLVMDisposeBuilder(Builder); + return Dst; + } + + void CloneAttrs(LLVMValueRef Src, LLVMValueRef Dst) { + auto Ctx = LLVMGetModuleContext(M); + int ArgCount = LLVMGetNumArgOperands(Src); + for (int i = LLVMAttributeReturnIndex; i <= ArgCount; i++) { + for (unsigned k = 0, e = LLVMGetLastEnumAttributeKind(); k < e; ++k) { + if (auto SrcA = LLVMGetCallSiteEnumAttribute(Src, i, k)) { + auto Val = LLVMGetEnumAttributeValue(SrcA); + auto A = LLVMCreateEnumAttribute(Ctx, k, Val); + LLVMAddCallSiteAttribute(Dst, i, A); + } + } + } + } + + LLVMValueRef CloneInstruction(LLVMValueRef Src, LLVMBuilderRef Builder) { + check_value_kind(Src, LLVMInstructionValueKind); + if (!LLVMIsAInstruction(Src)) + report_fatal_error("Expected an instruction"); + + const char *Name = LLVMGetValueName(Src); + + // Check if this is something we already computed. + { + auto i = VMap.find(Src); + if (i != VMap.end()) { + // If we have a hit, it means we already generated the instruction + // as a dependancy to somethign else. We need to make sure + // it is ordered properly. + auto I = i->second; + LLVMInstructionRemoveFromParent(I); + LLVMInsertIntoBuilderWithName(Builder, I, Name); + return I; + } + } + + // 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, CloneValue(LLVMGetOperand(Src, 0))); + break; + } + case LLVMBr: { + if (!LLVMIsConditional(Src)) { + LLVMValueRef SrcOp = LLVMGetOperand(Src, 0); + LLVMBasicBlockRef SrcBB = LLVMValueAsBasicBlock(SrcOp); + Dst = LLVMBuildBr(Builder, DeclareBB(SrcBB)); + break; + } + + LLVMValueRef Cond = LLVMGetCondition(Src); + LLVMValueRef Else = LLVMGetOperand(Src, 1); + LLVMBasicBlockRef ElseBB = DeclareBB(LLVMValueAsBasicBlock(Else)); + LLVMValueRef Then = LLVMGetOperand(Src, 2); + LLVMBasicBlockRef ThenBB = DeclareBB(LLVMValueAsBasicBlock(Then)); + Dst = LLVMBuildCondBr(Builder, Cond, ThenBB, ElseBB); + break; + } + case LLVMSwitch: + case LLVMIndirectBr: + break; + case LLVMInvoke: { + SmallVector<LLVMValueRef, 8> Args; + int ArgCount = LLVMGetNumArgOperands(Src); + for (int i = 0; i < ArgCount; i++) + Args.push_back(CloneValue(LLVMGetOperand(Src, i))); + LLVMValueRef Fn = CloneValue(LLVMGetCalledValue(Src)); + LLVMBasicBlockRef Then = DeclareBB(LLVMGetNormalDest(Src)); + LLVMBasicBlockRef Unwind = DeclareBB(LLVMGetUnwindDest(Src)); + Dst = LLVMBuildInvoke(Builder, Fn, Args.data(), ArgCount, + Then, Unwind, Name); + CloneAttrs(Src, Dst); + break; + } + case LLVMUnreachable: + Dst = LLVMBuildUnreachable(Builder); + break; + case LLVMAdd: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildAdd(Builder, LHS, RHS, Name); + break; + } + case LLVMSub: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildSub(Builder, LHS, RHS, Name); + break; + } + case LLVMMul: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildMul(Builder, LHS, RHS, Name); + break; + } + case LLVMUDiv: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildUDiv(Builder, LHS, RHS, Name); + break; + } + case LLVMSDiv: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildSDiv(Builder, LHS, RHS, Name); + break; + } + case LLVMURem: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildURem(Builder, LHS, RHS, Name); + break; + } + case LLVMSRem: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildSRem(Builder, LHS, RHS, Name); + break; + } + case LLVMShl: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildShl(Builder, LHS, RHS, Name); + break; + } + case LLVMLShr: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildLShr(Builder, LHS, RHS, Name); + break; + } + case LLVMAShr: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildAShr(Builder, LHS, RHS, Name); + break; + } + case LLVMAnd: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildAnd(Builder, LHS, RHS, Name); + break; + } + case LLVMOr: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildOr(Builder, LHS, RHS, Name); + break; + } + case LLVMXor: { + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildXor(Builder, LHS, RHS, Name); + break; + } + case LLVMAlloca: { + LLVMTypeRef Ty = CloneType(LLVMGetAllocatedType(Src)); + Dst = LLVMBuildAlloca(Builder, Ty, Name); + break; + } + case LLVMLoad: { + LLVMValueRef Ptr = CloneValue(LLVMGetOperand(Src, 0)); + Dst = LLVMBuildLoad(Builder, Ptr, Name); + LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); + break; + } + case LLVMStore: { + LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef Ptr = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildStore(Builder, Val, Ptr); + LLVMSetAlignment(Dst, LLVMGetAlignment(Src)); + break; + } + case LLVMGetElementPtr: { + LLVMValueRef Ptr = CloneValue(LLVMGetOperand(Src, 0)); + SmallVector<LLVMValueRef, 8> Idx; + int NumIdx = LLVMGetNumIndices(Src); + for (int i = 1; i <= NumIdx; i++) + Idx.push_back(CloneValue(LLVMGetOperand(Src, i))); + if (LLVMIsInBounds(Src)) + Dst = LLVMBuildInBoundsGEP(Builder, Ptr, Idx.data(), NumIdx, Name); + else + Dst = LLVMBuildGEP(Builder, Ptr, Idx.data(), NumIdx, Name); + break; + } + case LLVMAtomicCmpXchg: { + LLVMValueRef Ptr = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef Cmp = CloneValue(LLVMGetOperand(Src, 1)); + LLVMValueRef New = CloneValue(LLVMGetOperand(Src, 2)); + LLVMAtomicOrdering Succ = LLVMGetCmpXchgSuccessOrdering(Src); + LLVMAtomicOrdering Fail = LLVMGetCmpXchgFailureOrdering(Src); + LLVMBool SingleThread = LLVMIsAtomicSingleThread(Src); + + Dst = LLVMBuildAtomicCmpXchg(Builder, Ptr, Cmp, New, Succ, Fail, + SingleThread); + } break; + case LLVMBitCast: { + LLVMValueRef V = CloneValue(LLVMGetOperand(Src, 0)); + Dst = LLVMBuildBitCast(Builder, V, CloneType(Src), Name); + break; + } + case LLVMICmp: { + LLVMIntPredicate Pred = LLVMGetICmpPredicate(Src); + LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildICmp(Builder, Pred, LHS, RHS, Name); + break; + } + case LLVMPHI: { + // We need to agressively set things here because of loops. + VMap[Src] = Dst = LLVMBuildPhi(Builder, CloneType(Src), Name); + + SmallVector<LLVMValueRef, 8> Values; + SmallVector<LLVMBasicBlockRef, 8> Blocks; + + unsigned IncomingCount = LLVMCountIncoming(Src); + for (unsigned i = 0; i < IncomingCount; ++i) { + Blocks.push_back(DeclareBB(LLVMGetIncomingBlock(Src, i))); + Values.push_back(CloneValue(LLVMGetIncomingValue(Src, i))); + } + + LLVMAddIncoming(Dst, Values.data(), Blocks.data(), IncomingCount); + return Dst; + } + case LLVMCall: { + SmallVector<LLVMValueRef, 8> Args; + int ArgCount = LLVMGetNumArgOperands(Src); + for (int i = 0; i < ArgCount; i++) + Args.push_back(CloneValue(LLVMGetOperand(Src, i))); + LLVMValueRef Fn = CloneValue(LLVMGetCalledValue(Src)); + Dst = LLVMBuildCall(Builder, Fn, Args.data(), ArgCount, Name); + LLVMSetTailCall(Dst, LLVMIsTailCall(Src)); + CloneAttrs(Src, Dst); + break; + } + case LLVMResume: { + Dst = LLVMBuildResume(Builder, CloneValue(LLVMGetOperand(Src, 0))); + break; + } + case LLVMLandingPad: { + // The landing pad API is a bit screwed up for historical reasons. + Dst = LLVMBuildLandingPad(Builder, CloneType(Src), nullptr, 0, Name); + unsigned NumClauses = LLVMGetNumClauses(Src); + for (unsigned i = 0; i < NumClauses; ++i) + LLVMAddClause(Dst, CloneValue(LLVMGetClause(Src, i))); + LLVMSetCleanup(Dst, LLVMIsCleanup(Src)); + break; + } + case LLVMExtractValue: { + LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); + if (LLVMGetNumIndices(Src) != 1) + report_fatal_error("Expected only one indice"); + auto I = LLVMGetIndices(Src)[0]; + Dst = LLVMBuildExtractValue(Builder, Agg, I, Name); + break; + } + case LLVMInsertValue: { + LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef V = CloneValue(LLVMGetOperand(Src, 1)); + if (LLVMGetNumIndices(Src) != 1) + report_fatal_error("Expected only one indice"); + auto I = LLVMGetIndices(Src)[0]; + Dst = LLVMBuildInsertValue(Builder, Agg, V, I, Name); + break; + } + default: + break; + } + + if (Dst == nullptr) { + fprintf(stderr, "%d is not a supported opcode\n", Op); + exit(-1); + } + + check_value_kind(Dst, LLVMInstructionValueKind); + return VMap[Src] = Dst; + } + + LLVMBasicBlockRef DeclareBB(LLVMBasicBlockRef Src) { + // Check if this is something we already computed. + { + auto i = BBMap.find(Src); + if (i != BBMap.end()) { + return i->second; + } + } + + LLVMValueRef V = LLVMBasicBlockAsValue(Src); + if (!LLVMValueIsBasicBlock(V) || LLVMValueAsBasicBlock(V) != Src) + report_fatal_error("Basic block is not a basic block"); + + const char *Name = LLVMGetBasicBlockName(Src); + const char *VName = LLVMGetValueName(V); + if (Name != VName) + report_fatal_error("Basic block name mismatch"); + + LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Fun, Name); + return BBMap[Src] = BB; + } + + LLVMBasicBlockRef CloneBB(LLVMBasicBlockRef Src) { + LLVMBasicBlockRef BB = DeclareBB(Src); + + // Make sure ordering is correct. + LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Src); + if (Prev) + LLVMMoveBasicBlockAfter(BB, DeclareBB(Prev)); + + LLVMValueRef First = LLVMGetFirstInstruction(Src); + LLVMValueRef Last = LLVMGetLastInstruction(Src); + + if (First == nullptr) { + if (Last != nullptr) + report_fatal_error("Has no first instruction, but last one"); + return BB; + } + + auto Ctx = LLVMGetModuleContext(M); + LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx); + LLVMPositionBuilderAtEnd(Builder, BB); + + LLVMValueRef Cur = First; + LLVMValueRef Next = nullptr; + while(true) { + CloneInstruction(Cur, Builder); + Next = LLVMGetNextInstruction(Cur); + if (Next == nullptr) { + if (Cur != Last) + report_fatal_error("Final instruction does not match Last"); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousInstruction(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous instruction is not Current"); + + Cur = Next; + } + + LLVMDisposeBuilder(Builder); + return BB; + } + + void CloneBBs(LLVMValueRef Src) { + unsigned Count = LLVMCountBasicBlocks(Src); + if (Count == 0) + return; + + LLVMBasicBlockRef First = LLVMGetFirstBasicBlock(Src); + LLVMBasicBlockRef Last = LLVMGetLastBasicBlock(Src); + + LLVMBasicBlockRef Cur = First; + LLVMBasicBlockRef Next = nullptr; + while(true) { + CloneBB(Cur); + Count--; + Next = LLVMGetNextBasicBlock(Cur); + if (Next == nullptr) { + if (Cur != Last) + report_fatal_error("Final basic block does not match Last"); + break; + } + + LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous basic bloc is not Current"); + + Cur = Next; + } + + if (Count != 0) + report_fatal_error("Basic block count does not match iterration"); + } +}; + +static void declare_symbols(LLVMModuleRef Src, LLVMModuleRef M) { + LLVMValueRef Begin = LLVMGetFirstGlobal(Src); + LLVMValueRef End = LLVMGetLastGlobal(Src); + + LLVMValueRef Cur = Begin; + LLVMValueRef Next = nullptr; + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no begining"); + goto FunDecl; + } + + while (true) { + const char *Name = LLVMGetValueName(Cur); + if (LLVMGetNamedGlobal(M, Name)) + report_fatal_error("GlobalVariable already cloned"); + LLVMAddGlobal(M, LLVMGetElementType(TypeCloner(M).Clone(Cur)), Name); + + Next = LLVMGetNextGlobal(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error(""); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousGlobal(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous global is not Current"); + + Cur = Next; + } + +FunDecl: + Begin = LLVMGetFirstFunction(Src); + End = LLVMGetLastFunction(Src); + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no begining"); + return; + } + + auto Ctx = LLVMGetModuleContext(M); + + Cur = Begin; + Next = nullptr; + while (true) { + const char *Name = LLVMGetValueName(Cur); + if (LLVMGetNamedFunction(M, Name)) + report_fatal_error("Function already cloned"); + auto Ty = LLVMGetElementType(TypeCloner(M).Clone(Cur)); + auto F = LLVMAddFunction(M, Name, Ty); + + // Copy attributes + for (int i = LLVMAttributeFunctionIndex, c = LLVMCountParams(F); + i <= c; ++i) { + for (unsigned k = 0, e = LLVMGetLastEnumAttributeKind(); k < e; ++k) { + if (auto SrcA = LLVMGetEnumAttributeAtIndex(Cur, i, k)) { + auto Val = LLVMGetEnumAttributeValue(SrcA); + auto DstA = LLVMCreateEnumAttribute(Ctx, k, Val); + LLVMAddAttributeAtIndex(F, i, DstA); + } + } + } + + Next = LLVMGetNextFunction(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error("Last function does not match End"); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousFunction(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous function is not Current"); + + Cur = Next; + } +} + +static void clone_symbols(LLVMModuleRef Src, LLVMModuleRef M) { + LLVMValueRef Begin = LLVMGetFirstGlobal(Src); + LLVMValueRef End = LLVMGetLastGlobal(Src); + + LLVMValueRef Cur = Begin; + LLVMValueRef Next = nullptr; + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no begining"); + goto FunClone; + } + + while (true) { + const char *Name = LLVMGetValueName(Cur); + LLVMValueRef G = LLVMGetNamedGlobal(M, Name); + if (!G) + report_fatal_error("GlobalVariable must have been declared already"); + + if (auto I = LLVMGetInitializer(Cur)) + LLVMSetInitializer(G, clone_constant(I, M)); + + LLVMSetGlobalConstant(G, LLVMIsGlobalConstant(Cur)); + LLVMSetThreadLocal(G, LLVMIsThreadLocal(Cur)); + LLVMSetExternallyInitialized(G, LLVMIsExternallyInitialized(Cur)); + LLVMSetLinkage(G, LLVMGetLinkage(Cur)); + LLVMSetSection(G, LLVMGetSection(Cur)); + LLVMSetVisibility(G, LLVMGetVisibility(Cur)); + LLVMSetUnnamedAddr(G, LLVMHasUnnamedAddr(Cur)); + LLVMSetAlignment(G, LLVMGetAlignment(Cur)); + + Next = LLVMGetNextGlobal(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error(""); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousGlobal(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous global is not Current"); + + Cur = Next; + } + +FunClone: + Begin = LLVMGetFirstFunction(Src); + End = LLVMGetLastFunction(Src); + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no begining"); + return; + } + + Cur = Begin; + Next = nullptr; + while (true) { + const char *Name = LLVMGetValueName(Cur); + LLVMValueRef Fun = LLVMGetNamedFunction(M, Name); + if (!Fun) + report_fatal_error("Function must have been declared already"); + + if (LLVMHasPersonalityFn(Cur)) { + const char *FName = LLVMGetValueName(LLVMGetPersonalityFn(Cur)); + LLVMValueRef P = LLVMGetNamedFunction(M, FName); + if (!P) + report_fatal_error("Could not find personality function"); + LLVMSetPersonalityFn(Fun, P); + } + + FunCloner FC(Cur, Fun); + FC.CloneBBs(Cur); + + Next = LLVMGetNextFunction(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error("Last function does not match End"); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousFunction(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous function is not Current"); + + Cur = Next; + } +} + +int llvm_echo(void) { + LLVMEnablePrettyStackTrace(); + + LLVMModuleRef Src = llvm_load_module(false, true); + size_t Len; + const char *ModuleName = LLVMGetModuleIdentifier(Src, &Len); + LLVMContextRef Ctx = LLVMContextCreate(); + LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleName, Ctx); + + // This whole switcharound is done because the C API has no way to + // set the source_filename + LLVMSetModuleIdentifier(M, "", 0); + LLVMGetModuleIdentifier(M, &Len); + if (Len != 0) + report_fatal_error("LLVM{Set,Get}ModuleIdentifier failed"); + LLVMSetModuleIdentifier(M, ModuleName, strlen(ModuleName)); + + LLVMSetTarget(M, LLVMGetTarget(Src)); + LLVMSetModuleDataLayout(M, LLVMGetModuleDataLayout(Src)); + if (strcmp(LLVMGetDataLayoutStr(M), LLVMGetDataLayoutStr(Src))) + report_fatal_error("Inconsistent DataLayout string representation"); + + declare_symbols(Src, M); + clone_symbols(Src, M); + char *Str = LLVMPrintModuleToString(M); + fputs(Str, stdout); + + LLVMDisposeMessage(Str); + LLVMDisposeModule(M); + LLVMContextDispose(Ctx); + + return 0; +} |