1*f76f3154SDaniel Sanders //===- lib/Support/CodeGenCoverage.cpp -------------------------------------==// 2*f76f3154SDaniel Sanders // 3*f76f3154SDaniel Sanders // The LLVM Compiler Infrastructure 4*f76f3154SDaniel Sanders // 5*f76f3154SDaniel Sanders // This file is distributed under the University of Illinois Open Source 6*f76f3154SDaniel Sanders // License. See LICENSE.TXT for details. 7*f76f3154SDaniel Sanders // 8*f76f3154SDaniel Sanders //===----------------------------------------------------------------------===// 9*f76f3154SDaniel Sanders /// \file 10*f76f3154SDaniel Sanders /// This file implements the CodeGenCoverage class. 11*f76f3154SDaniel Sanders //===----------------------------------------------------------------------===// 12*f76f3154SDaniel Sanders 13*f76f3154SDaniel Sanders #include "llvm/Support/CodeGenCoverage.h" 14*f76f3154SDaniel Sanders 15*f76f3154SDaniel Sanders #include "llvm/Support/Endian.h" 16*f76f3154SDaniel Sanders #include "llvm/Support/FileSystem.h" 17*f76f3154SDaniel Sanders #include "llvm/Support/Mutex.h" 18*f76f3154SDaniel Sanders #include "llvm/Support/ScopedPrinter.h" 19*f76f3154SDaniel Sanders #include "llvm/Support/ToolOutputFile.h" 20*f76f3154SDaniel Sanders 21*f76f3154SDaniel Sanders #if LLVM_ON_UNIX 22*f76f3154SDaniel Sanders #include <unistd.h> 23*f76f3154SDaniel Sanders #elif LLVM_ON_WIN32 24*f76f3154SDaniel Sanders #include <windows.h> 25*f76f3154SDaniel Sanders #endif 26*f76f3154SDaniel Sanders 27*f76f3154SDaniel Sanders using namespace llvm; 28*f76f3154SDaniel Sanders 29*f76f3154SDaniel Sanders static sys::SmartMutex<true> OutputMutex; 30*f76f3154SDaniel Sanders 31*f76f3154SDaniel Sanders CodeGenCoverage::CodeGenCoverage() {} 32*f76f3154SDaniel Sanders 33*f76f3154SDaniel Sanders void CodeGenCoverage::setCovered(uint64_t RuleID) { 34*f76f3154SDaniel Sanders if (RuleCoverage.size() <= RuleID) 35*f76f3154SDaniel Sanders RuleCoverage.resize(RuleID + 1, 0); 36*f76f3154SDaniel Sanders RuleCoverage[RuleID] = true; 37*f76f3154SDaniel Sanders } 38*f76f3154SDaniel Sanders 39*f76f3154SDaniel Sanders bool CodeGenCoverage::isCovered(uint64_t RuleID) { 40*f76f3154SDaniel Sanders if (RuleCoverage.size() <= RuleID) 41*f76f3154SDaniel Sanders return false; 42*f76f3154SDaniel Sanders return RuleCoverage[RuleID]; 43*f76f3154SDaniel Sanders } 44*f76f3154SDaniel Sanders 45*f76f3154SDaniel Sanders bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) { 46*f76f3154SDaniel Sanders const char *CurPtr = Buffer.getBufferStart(); 47*f76f3154SDaniel Sanders 48*f76f3154SDaniel Sanders while (CurPtr != Buffer.getBufferEnd()) { 49*f76f3154SDaniel Sanders // Read the backend name from the input. 50*f76f3154SDaniel Sanders const char *LexedBackendName = CurPtr; 51*f76f3154SDaniel Sanders while (*CurPtr++ != 0) 52*f76f3154SDaniel Sanders ; 53*f76f3154SDaniel Sanders if (CurPtr == Buffer.getBufferEnd()) 54*f76f3154SDaniel Sanders return false; // Data is invalid, expected rule id's to follow. 55*f76f3154SDaniel Sanders 56*f76f3154SDaniel Sanders bool IsForThisBackend = BackendName.equals(LexedBackendName); 57*f76f3154SDaniel Sanders while (CurPtr != Buffer.getBufferEnd()) { 58*f76f3154SDaniel Sanders if (std::distance(CurPtr, Buffer.getBufferEnd()) < 8) 59*f76f3154SDaniel Sanders return false; // Data is invalid. Not enough bytes for another rule id. 60*f76f3154SDaniel Sanders 61*f76f3154SDaniel Sanders uint64_t RuleID = support::endian::read64(CurPtr, support::native); 62*f76f3154SDaniel Sanders CurPtr += 8; 63*f76f3154SDaniel Sanders 64*f76f3154SDaniel Sanders // ~0ull terminates the rule id list. 65*f76f3154SDaniel Sanders if (RuleID == ~0ull) 66*f76f3154SDaniel Sanders break; 67*f76f3154SDaniel Sanders 68*f76f3154SDaniel Sanders // Anything else, is recorded or ignored depending on whether it's 69*f76f3154SDaniel Sanders // intended for the backend we're interested in. 70*f76f3154SDaniel Sanders if (IsForThisBackend) 71*f76f3154SDaniel Sanders setCovered(RuleID); 72*f76f3154SDaniel Sanders } 73*f76f3154SDaniel Sanders } 74*f76f3154SDaniel Sanders 75*f76f3154SDaniel Sanders return true; 76*f76f3154SDaniel Sanders } 77*f76f3154SDaniel Sanders 78*f76f3154SDaniel Sanders bool CodeGenCoverage::emit(StringRef CoveragePrefix, 79*f76f3154SDaniel Sanders StringRef BackendName) const { 80*f76f3154SDaniel Sanders if (!CoveragePrefix.empty() && !RuleCoverage.empty()) { 81*f76f3154SDaniel Sanders sys::SmartScopedLock<true> Lock(OutputMutex); 82*f76f3154SDaniel Sanders 83*f76f3154SDaniel Sanders // We can handle locking within a process easily enough but we don't want to 84*f76f3154SDaniel Sanders // manage it between multiple processes. Use the process ID to ensure no 85*f76f3154SDaniel Sanders // more than one process is ever writing to the same file at the same time. 86*f76f3154SDaniel Sanders std::string Pid = 87*f76f3154SDaniel Sanders #if LLVM_ON_UNIX 88*f76f3154SDaniel Sanders llvm::to_string(::getpid()); 89*f76f3154SDaniel Sanders #elif LLVM_ON_WIN32 90*f76f3154SDaniel Sanders llvm::to_string(::GetCurrentProcessId()); 91*f76f3154SDaniel Sanders #else 92*f76f3154SDaniel Sanders ""; 93*f76f3154SDaniel Sanders #endif 94*f76f3154SDaniel Sanders 95*f76f3154SDaniel Sanders std::string CoverageFilename = (CoveragePrefix + Pid).str(); 96*f76f3154SDaniel Sanders 97*f76f3154SDaniel Sanders std::error_code EC; 98*f76f3154SDaniel Sanders sys::fs::OpenFlags OpenFlags = sys::fs::F_Append; 99*f76f3154SDaniel Sanders std::unique_ptr<ToolOutputFile> CoverageFile = 100*f76f3154SDaniel Sanders llvm::make_unique<ToolOutputFile>(CoverageFilename, EC, OpenFlags); 101*f76f3154SDaniel Sanders if (EC) 102*f76f3154SDaniel Sanders return false; 103*f76f3154SDaniel Sanders 104*f76f3154SDaniel Sanders uint64_t Zero = 0; 105*f76f3154SDaniel Sanders uint64_t InvZero = ~0ull; 106*f76f3154SDaniel Sanders CoverageFile->os() << BackendName; 107*f76f3154SDaniel Sanders CoverageFile->os().write((const char *)&Zero, sizeof(unsigned char)); 108*f76f3154SDaniel Sanders for (uint64_t I : RuleCoverage.set_bits()) 109*f76f3154SDaniel Sanders CoverageFile->os().write((const char *)&I, sizeof(uint64_t)); 110*f76f3154SDaniel Sanders CoverageFile->os().write((const char *)&InvZero, sizeof(uint64_t)); 111*f76f3154SDaniel Sanders 112*f76f3154SDaniel Sanders CoverageFile->keep(); 113*f76f3154SDaniel Sanders } 114*f76f3154SDaniel Sanders 115*f76f3154SDaniel Sanders return true; 116*f76f3154SDaniel Sanders } 117*f76f3154SDaniel Sanders 118*f76f3154SDaniel Sanders void CodeGenCoverage::reset() { RuleCoverage.resize(0); } 119