//===-- 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 "llvm/Support/ErrorHandling.h" #include #include using namespace llvm; // Provide DenseMapInfo for C API opaque types. template 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 struct CAPIDenseMap { struct CAPIDenseMapInfo { static inline T* getEmptyKey() { uintptr_t Val = static_cast(-1); return reinterpret_cast(Val); } static inline T* getTombstoneKey() { uintptr_t Val = static_cast(-2); return reinterpret_cast(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 Map; }; typedef CAPIDenseMap::Map ValueMap; typedef CAPIDenseMap::Map BasicBlockMap; 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); } static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst); struct FunCloner { LLVMValueRef Fun; ValueMap VMap; BasicBlockMap BBMap; FunCloner(LLVMValueRef Src, LLVMValueRef Dst) : Fun(Dst), VMap(clone_params(Src, Dst)) {} // Try to clone everything in the llvm::Value hierarchy. LLVMValueRef CloneValue(LLVMValueRef Src, LLVMBuilderRef Builder) { 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, CloneValue(LLVMGetOperand(Src, 0), Builder)); break; } case LLVMBr: { LLVMBasicBlockRef SrcBB = LLVMValueAsBasicBlock(LLVMGetOperand(Src, 0)); Dst = LLVMBuildBr(Builder, DeclareBB(SrcBB)); break; } case LLVMSwitch: case LLVMIndirectBr: case LLVMInvoke: break; case LLVMUnreachable: Dst = LLVMBuildUnreachable(Builder); break; case LLVMAdd: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildAdd(Builder, LHS, RHS, Name); break; } case LLVMSub: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildSub(Builder, LHS, RHS, Name); break; } case LLVMMul: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildMul(Builder, LHS, RHS, Name); break; } case LLVMUDiv: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildUDiv(Builder, LHS, RHS, Name); break; } case LLVMSDiv: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildSDiv(Builder, LHS, RHS, Name); break; } case LLVMURem: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildURem(Builder, LHS, RHS, Name); break; } case LLVMSRem: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildSRem(Builder, LHS, RHS, Name); break; } case LLVMShl: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildShl(Builder, LHS, RHS, Name); break; } case LLVMLShr: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildLShr(Builder, LHS, RHS, Name); break; } case LLVMAShr: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildAShr(Builder, LHS, RHS, Name); break; } case LLVMAnd: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildAnd(Builder, LHS, RHS, Name); break; } case LLVMOr: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildOr(Builder, LHS, RHS, Name); break; } case LLVMXor: { LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0), Builder); LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1), Builder); Dst = LLVMBuildXor(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 Args; for (int i = 0; i < ArgCount; i++) Args.push_back(CloneValue(LLVMGetOperand(Src, i), Builder)); LLVMValueRef Fn = CloneValue(LLVMGetOperand(Src, ArgCount), Builder); 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; } LLVMBasicBlockRef DeclareBB(LLVMBasicBlockRef Src) { // Check if this is something we already computed. { auto i = BBMap.find(Src); if (i != BBMap.end()) { return i->second; } } const char *Name = LLVMGetBasicBlockName(Src); LLVMValueRef V = LLVMBasicBlockAsValue(Src); if (!LLVMValueIsBasicBlock(V) || LLVMValueAsBasicBlock(V) != Src) report_fatal_error("Basic block is not a basic block\n"); 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) { fprintf(stderr, "Has no first instruction, but last one\n"); exit(-1); } return BB; } LLVMContextRef Ctx = LLVMGetModuleContext(LLVMGetGlobalParent(Fun)); LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx); LLVMPositionBuilderAtEnd(Builder, BB); LLVMValueRef Cur = First; LLVMValueRef Next = nullptr; while(true) { CloneValue(Cur, Builder); 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; } 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) { 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); FunCloner FC(Src, Fun); FC.CloneBBs(Src); 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 llvm_echo(void) { LLVMEnablePrettyStackTrace(); LLVMModuleRef Src = llvm_load_module(false, true); 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; }