| //===-- 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 = static_cast<LLVMTypeRef*>( | |
| safe_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: | |
| return LLVMMetadataTypeInContext(Ctx); | |
| case LLVMX86_MMXTypeKind: | |
| return LLVMX86MMXTypeInContext(Ctx); | |
| case LLVMTokenTypeKind: | |
| return LLVMTokenTypeInContext(Ctx); | |
| } | |
| 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) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(SrcCur, &NameLen); | |
| LLVMSetValueName2(DstCur, Name, NameLen); | |
| 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)) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cst, &NameLen); | |
| // 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 variable"); | |
| } | |
| // Try global alias | |
| if (LLVMIsAGlobalAlias(Cst)) { | |
| check_value_kind(Cst, LLVMGlobalAliasValueKind); | |
| LLVMValueRef Dst = LLVMGetNamedGlobalAlias(M, Name, NameLen); | |
| if (Dst) | |
| return Dst; | |
| report_fatal_error("Could not find alias"); | |
| } | |
| 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 null | |
| if (LLVMIsNull(Cst)) { | |
| check_value_kind(Cst, LLVMConstantTokenNoneValueKind); | |
| LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); | |
| return LLVMConstNull(Ty); | |
| } | |
| // 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"); | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Src, &NameLen); | |
| // 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, CloneValue(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 aggressively 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 LLVMCleanupRet: { | |
| LLVMValueRef CatchPad = CloneValue(LLVMGetOperand(Src, 0)); | |
| LLVMBasicBlockRef Unwind = nullptr; | |
| if (LLVMBasicBlockRef UDest = LLVMGetUnwindDest(Src)) | |
| Unwind = DeclareBB(UDest); | |
| Dst = LLVMBuildCleanupRet(Builder, CatchPad, Unwind); | |
| break; | |
| } | |
| case LLVMCatchRet: { | |
| LLVMValueRef CatchPad = CloneValue(LLVMGetOperand(Src, 0)); | |
| LLVMBasicBlockRef SuccBB = DeclareBB(LLVMGetSuccessor(Src, 0)); | |
| Dst = LLVMBuildCatchRet(Builder, CatchPad, SuccBB); | |
| break; | |
| } | |
| case LLVMCatchPad: { | |
| LLVMValueRef ParentPad = CloneValue(LLVMGetParentCatchSwitch(Src)); | |
| SmallVector<LLVMValueRef, 8> Args; | |
| int ArgCount = LLVMGetNumArgOperands(Src); | |
| for (int i = 0; i < ArgCount; i++) | |
| Args.push_back(CloneValue(LLVMGetOperand(Src, i))); | |
| Dst = LLVMBuildCatchPad(Builder, ParentPad, | |
| Args.data(), ArgCount, Name); | |
| break; | |
| } | |
| case LLVMCleanupPad: { | |
| LLVMValueRef ParentPad = CloneValue(LLVMGetOperand(Src, 0)); | |
| SmallVector<LLVMValueRef, 8> Args; | |
| int ArgCount = LLVMGetNumArgOperands(Src); | |
| for (int i = 0; i < ArgCount; i++) | |
| Args.push_back(CloneValue(LLVMGetArgOperand(Src, i))); | |
| Dst = LLVMBuildCleanupPad(Builder, ParentPad, | |
| Args.data(), ArgCount, Name); | |
| break; | |
| } | |
| case LLVMCatchSwitch: { | |
| LLVMValueRef ParentPad = CloneValue(LLVMGetOperand(Src, 0)); | |
| LLVMBasicBlockRef UnwindBB = nullptr; | |
| if (LLVMBasicBlockRef UDest = LLVMGetUnwindDest(Src)) { | |
| UnwindBB = DeclareBB(UDest); | |
| } | |
| unsigned NumHandlers = LLVMGetNumHandlers(Src); | |
| Dst = LLVMBuildCatchSwitch(Builder, ParentPad, UnwindBB, NumHandlers, Name); | |
| if (NumHandlers > 0) { | |
| LLVMBasicBlockRef *Handlers = static_cast<LLVMBasicBlockRef*>( | |
| safe_malloc(NumHandlers * sizeof(LLVMBasicBlockRef))); | |
| LLVMGetHandlers(Src, Handlers); | |
| for (unsigned i = 0; i < NumHandlers; i++) | |
| LLVMAddHandler(Dst, DeclareBB(Handlers[i])); | |
| free(Handlers); | |
| } | |
| 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); | |
| size_t NameLen; | |
| const char *VName = LLVMGetValueName2(V, &NameLen); | |
| 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) { | |
| auto Ctx = LLVMGetModuleContext(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 beginning"); | |
| goto FunDecl; | |
| } | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| 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 beginning"); | |
| goto AliasDecl; | |
| } | |
| Cur = Begin; | |
| Next = nullptr; | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| 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; | |
| } | |
| AliasDecl: | |
| Begin = LLVMGetFirstGlobalAlias(Src); | |
| End = LLVMGetLastGlobalAlias(Src); | |
| if (!Begin) { | |
| if (End != nullptr) | |
| report_fatal_error("Range has an end but no beginning"); | |
| return; | |
| } | |
| Cur = Begin; | |
| Next = nullptr; | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| if (LLVMGetNamedGlobalAlias(M, Name, NameLen)) | |
| report_fatal_error("Global alias already cloned"); | |
| LLVMTypeRef CurType = TypeCloner(M).Clone(Cur); | |
| // FIXME: Allow NULL aliasee. | |
| LLVMAddAlias(M, CurType, LLVMGetUndef(CurType), Name); | |
| Next = LLVMGetNextGlobalAlias(Cur); | |
| if (Next == nullptr) { | |
| if (Cur != End) | |
| report_fatal_error(""); | |
| break; | |
| } | |
| LLVMValueRef Prev = LLVMGetPreviousGlobalAlias(Next); | |
| if (Prev != Cur) | |
| report_fatal_error("Next.Previous global 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 beginning"); | |
| goto FunClone; | |
| } | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| 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)); | |
| LLVMSetUnnamedAddress(G, LLVMGetUnnamedAddress(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 beginning"); | |
| goto AliasClone; | |
| } | |
| Cur = Begin; | |
| Next = nullptr; | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| LLVMValueRef Fun = LLVMGetNamedFunction(M, Name); | |
| if (!Fun) | |
| report_fatal_error("Function must have been declared already"); | |
| if (LLVMHasPersonalityFn(Cur)) { | |
| size_t FNameLen; | |
| const char *FName = LLVMGetValueName2(LLVMGetPersonalityFn(Cur), | |
| &FNameLen); | |
| 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; | |
| } | |
| AliasClone: | |
| Begin = LLVMGetFirstGlobalAlias(Src); | |
| End = LLVMGetLastGlobalAlias(Src); | |
| if (!Begin) { | |
| if (End != nullptr) | |
| report_fatal_error("Range has an end but no beginning"); | |
| return; | |
| } | |
| Cur = Begin; | |
| Next = nullptr; | |
| while (true) { | |
| size_t NameLen; | |
| const char *Name = LLVMGetValueName2(Cur, &NameLen); | |
| LLVMValueRef Alias = LLVMGetNamedGlobalAlias(M, Name, NameLen); | |
| if (!Alias) | |
| report_fatal_error("Global alias must have been declared already"); | |
| if (LLVMValueRef Aliasee = LLVMAliasGetAliasee(Cur)) { | |
| LLVMAliasSetAliasee(Alias, clone_constant(Aliasee, M)); | |
| } | |
| LLVMSetLinkage(Alias, LLVMGetLinkage(Cur)); | |
| LLVMSetUnnamedAddress(Alias, LLVMGetUnnamedAddress(Cur)); | |
| Next = LLVMGetNextGlobalAlias(Cur); | |
| if (Next == nullptr) { | |
| if (Cur != End) | |
| report_fatal_error("Last global alias does not match End"); | |
| break; | |
| } | |
| LLVMValueRef Prev = LLVMGetPreviousGlobalAlias(Next); | |
| if (Prev != Cur) | |
| report_fatal_error("Next.Previous global alias is not Current"); | |
| Cur = Next; | |
| } | |
| } | |
| int llvm_echo(void) { | |
| LLVMEnablePrettyStackTrace(); | |
| LLVMModuleRef Src = llvm_load_module(false, true); | |
| size_t SourceFileLen; | |
| const char *SourceFileName = LLVMGetSourceFileName(Src, &SourceFileLen); | |
| size_t ModuleIdentLen; | |
| const char *ModuleName = LLVMGetModuleIdentifier(Src, &ModuleIdentLen); | |
| LLVMContextRef Ctx = LLVMContextCreate(); | |
| LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleName, Ctx); | |
| LLVMSetSourceFileName(M, SourceFileName, SourceFileLen); | |
| LLVMSetModuleIdentifier(M, ModuleName, ModuleIdentLen); | |
| size_t SourceFlagsLen; | |
| LLVMModuleFlagEntry *ModuleFlags = | |
| LLVMCopyModuleFlagsMetadata(Src, &SourceFlagsLen); | |
| for (unsigned i = 0; i < SourceFlagsLen; ++i) { | |
| size_t EntryNameLen; | |
| const char *EntryName = | |
| LLVMModuleFlagEntriesGetKey(ModuleFlags, i, &EntryNameLen); | |
| LLVMAddModuleFlag(M, LLVMModuleFlagEntriesGetFlagBehavior(ModuleFlags, i), | |
| EntryName, EntryNameLen, | |
| LLVMModuleFlagEntriesGetMetadata(ModuleFlags, i)); | |
| } | |
| LLVMSetTarget(M, LLVMGetTarget(Src)); | |
| LLVMSetModuleDataLayout(M, LLVMGetModuleDataLayout(Src)); | |
| if (strcmp(LLVMGetDataLayoutStr(M), LLVMGetDataLayoutStr(Src))) | |
| report_fatal_error("Inconsistent DataLayout string representation"); | |
| size_t ModuleInlineAsmLen; | |
| const char *ModuleAsm = LLVMGetModuleInlineAsm(Src, &ModuleInlineAsmLen); | |
| LLVMSetModuleInlineAsm2(M, ModuleAsm, ModuleInlineAsmLen); | |
| declare_symbols(Src, M); | |
| clone_symbols(Src, M); | |
| char *Str = LLVMPrintModuleToString(M); | |
| fputs(Str, stdout); | |
| LLVMDisposeModuleFlagsMetadata(ModuleFlags); | |
| LLVMDisposeMessage(Str); | |
| LLVMDisposeModule(Src); | |
| LLVMDisposeModule(M); | |
| LLVMContextDispose(Ctx); | |
| return 0; | |
| } |