2020-07-26 12:11:30 -05:00
|
|
|
#include "LLVMWrapper.h"
|
2020-07-02 13:27:15 -05:00
|
|
|
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
|
|
|
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
|
|
|
|
#include "llvm/ProfileData/InstrProf.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2021-02-20 09:43:05 -06:00
|
|
|
struct LLVMRustCounterMappingRegion {
|
|
|
|
coverage::Counter Count;
|
|
|
|
uint32_t FileID;
|
|
|
|
uint32_t ExpandedFileID;
|
|
|
|
uint32_t LineStart;
|
|
|
|
uint32_t ColumnStart;
|
|
|
|
uint32_t LineEnd;
|
|
|
|
uint32_t ColumnEnd;
|
|
|
|
coverage::CounterMappingRegion::RegionKind Kind;
|
|
|
|
};
|
|
|
|
|
2020-07-02 13:27:15 -05:00
|
|
|
extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
|
|
|
const char* const Filenames[],
|
|
|
|
size_t FilenamesLen,
|
|
|
|
RustStringRef BufferOut) {
|
2020-11-23 14:56:07 -06:00
|
|
|
SmallVector<StringRef,32> FilenameRefs;
|
2020-07-02 13:27:15 -05:00
|
|
|
for (size_t i = 0; i < FilenamesLen; i++) {
|
2020-11-23 14:56:07 -06:00
|
|
|
FilenameRefs.push_back(StringRef(Filenames[i]));
|
2020-07-02 13:27:15 -05:00
|
|
|
}
|
2020-11-23 14:56:07 -06:00
|
|
|
auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
|
|
|
|
makeArrayRef(FilenameRefs));
|
|
|
|
RawRustStringOstream OS(BufferOut);
|
|
|
|
FilenamesWriter.write(OS);
|
2020-07-02 13:27:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void LLVMRustCoverageWriteMappingToBuffer(
|
|
|
|
const unsigned *VirtualFileMappingIDs,
|
|
|
|
unsigned NumVirtualFileMappingIDs,
|
2020-07-24 23:14:28 -05:00
|
|
|
const coverage::CounterExpression *Expressions,
|
|
|
|
unsigned NumExpressions,
|
2021-02-20 09:43:05 -06:00
|
|
|
LLVMRustCounterMappingRegion *RustMappingRegions,
|
2020-07-24 23:14:28 -05:00
|
|
|
unsigned NumMappingRegions,
|
2020-07-02 13:27:15 -05:00
|
|
|
RustStringRef BufferOut) {
|
2021-02-20 09:43:05 -06:00
|
|
|
// Convert from FFI representation to LLVM representation.
|
|
|
|
SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
|
|
|
|
MappingRegions.reserve(NumMappingRegions);
|
|
|
|
for (const auto &Region : makeArrayRef(RustMappingRegions, NumMappingRegions)) {
|
|
|
|
MappingRegions.emplace_back(
|
|
|
|
Region.Count, Region.FileID, Region.ExpandedFileID,
|
|
|
|
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
|
|
|
|
Region.Kind);
|
|
|
|
}
|
2020-07-02 13:27:15 -05:00
|
|
|
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
|
2020-07-24 23:14:28 -05:00
|
|
|
makeArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
|
|
|
|
makeArrayRef(Expressions, NumExpressions),
|
2021-02-20 09:43:05 -06:00
|
|
|
MappingRegions);
|
2020-07-02 13:27:15 -05:00
|
|
|
RawRustStringOstream OS(BufferOut);
|
|
|
|
CoverageMappingWriter.write(OS);
|
|
|
|
}
|
|
|
|
|
LLVM IR coverage encoding aligns closer to Clang's
I found some areas for improvement while attempting to debug the
SegFault issue when running rust programs compiled using MSVC, with
coverage instrumentation.
I discovered that LLVM's coverage writer was generating incomplete
function name variable names (that's not a typo: the name of the
variable that holds a function name).
The existing implementation used one-up numbers to distinguish
variables, and correcting the names did not fix the MSVC coverage bug,
but the fix in this PR makes the names and resulting LLVM IR easier to
follow and more consistent with Clang's implementation.
I also changed the way the `-Zinstrument-coverage` option is supported
in symbol_export.rs. The original implementation was incorrect, and the
corrected version matches the handling for `-Zprofile-generate`, as it
turns out.
(An argument could be made that maybe `-Zinstrument-coverage` should
automatically enable `-Cprofile-generate`. In fact, if
`-Cprofile-generate` is analagous to Clang's `-fprofile-generate`, as
some documentation implies, Clang always requires this flag for its
implementation of source-based code coverage. This would require a
little more validation, and if implemented, would probably require
updating some of the user-facing messages related to
`-Cprofile-generate` to not be so specific to the PGO use case.)
None of these changes fixed the MSVC coverage problems, but they should
still be welcome improvements.
Lastly, I added some additional FIXME comments in instrument_coverage.rs
describing issues I found with the generated LLVM IR that would be
resolved if the coverage instrumentation is injected with a `Statement`
instead of as a new `BasicBlock`. I describe seven advantages of this
change, but it requires some discussion before making a change like
this.
2020-08-06 00:53:11 -05:00
|
|
|
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
|
|
|
|
StringRef FuncNameRef(FuncName);
|
|
|
|
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
|
|
|
|
}
|
|
|
|
|
2020-11-23 14:56:07 -06:00
|
|
|
extern "C" uint64_t LLVMRustCoverageHashCString(const char *StrVal) {
|
|
|
|
StringRef StrRef(StrVal);
|
|
|
|
return IndexedInstrProf::ComputeHash(StrRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" uint64_t LLVMRustCoverageHashByteArray(
|
|
|
|
const char *Bytes,
|
|
|
|
unsigned NumBytes) {
|
|
|
|
StringRef StrRef(Bytes, NumBytes);
|
|
|
|
return IndexedInstrProf::ComputeHash(StrRef);
|
2020-07-02 13:27:15 -05:00
|
|
|
}
|
|
|
|
|
2020-11-23 14:56:07 -06:00
|
|
|
static void WriteSectionNameToString(LLVMModuleRef M,
|
|
|
|
InstrProfSectKind SK,
|
|
|
|
RustStringRef Str) {
|
2020-07-02 13:27:15 -05:00
|
|
|
Triple TargetTriple(unwrap(M)->getTargetTriple());
|
2020-11-23 14:56:07 -06:00
|
|
|
auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat());
|
2020-07-02 13:27:15 -05:00
|
|
|
RawRustStringOstream OS(Str);
|
|
|
|
OS << name;
|
|
|
|
}
|
|
|
|
|
2020-11-23 14:56:07 -06:00
|
|
|
extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M,
|
|
|
|
RustStringRef Str) {
|
|
|
|
WriteSectionNameToString(M, IPSK_covmap, Str);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
|
|
|
|
RustStringRef Str) {
|
2020-11-24 13:50:24 -06:00
|
|
|
#if LLVM_VERSION_GE(11, 0)
|
2020-11-23 14:56:07 -06:00
|
|
|
WriteSectionNameToString(M, IPSK_covfun, Str);
|
2020-11-25 11:45:33 -06:00
|
|
|
// else do nothing; the `Version` check will abort codegen on the Rust side
|
2020-11-24 13:50:24 -06:00
|
|
|
#endif
|
2020-11-23 14:56:07 -06:00
|
|
|
}
|
|
|
|
|
2020-07-02 13:27:15 -05:00
|
|
|
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
|
|
|
|
auto name = getCoverageMappingVarName();
|
|
|
|
RawRustStringOstream OS(Str);
|
|
|
|
OS << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
|
2020-11-24 13:50:24 -06:00
|
|
|
#if LLVM_VERSION_GE(11, 0)
|
2020-11-23 14:56:07 -06:00
|
|
|
return coverage::CovMapVersion::Version4;
|
2020-11-24 13:50:24 -06:00
|
|
|
#else
|
2020-11-25 11:45:33 -06:00
|
|
|
return coverage::CovMapVersion::Version3;
|
2020-11-24 13:50:24 -06:00
|
|
|
#endif
|
2020-07-02 13:27:15 -05:00
|
|
|
}
|