ldc/gen/coverage.cpp
2022-02-26 19:15:46 +01:00

89 lines
3.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- gen/coverage.h - Code Coverage Analysis -----------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/coverage.h"
#include "dmd/module.h"
#include "driver/cl_options.h"
#include "gen/irstate.h"
#include "gen/logger.h"
void emitCoverageLinecountInc(const Loc &loc) {
Module *m = gIR->dmodule;
// Only emit coverage increment for locations in the source of the current
// module
// (for example, 'inlined' methods from other source files should be skipped).
if (!global.params.cov || !loc.linnum || !loc.filename || !m->d_cover_data ||
strcmp(m->srcfile.toChars(), loc.filename) != 0) {
return;
}
const unsigned line = loc.linnum - 1; // convert to 0-based line# index
assert(line < m->numlines);
IF_LOG Logger::println("Coverage: increment _d_cover_data[%d]", line);
LOG_SCOPE;
// Increment the line counter:
// Get GEP into _d_cover_data array...
LLType *i32Type = LLType::getInt32Ty(gIR->context());
LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(line)};
LLValue *ptr = llvm::ConstantExpr::getGetElementPtr(
LLArrayType::get(i32Type, m->numlines), m->d_cover_data, idxs, true);
// ...and generate the "increment" instruction(s)
switch (opts::coverageIncrement) {
case opts::CoverageIncrement::_default: // fallthrough
case opts::CoverageIncrement::atomic:
// Do an atomic increment, so this works when multiple threads are executed.
gIR->ir->CreateAtomicRMW(llvm::AtomicRMWInst::Add, ptr, DtoConstUint(1),
#if LDC_LLVM_VER >= 1300
LLAlign(4),
#endif
llvm::AtomicOrdering::Monotonic);
break;
case opts::CoverageIncrement::nonatomic: {
// Do a non-atomic increment, user is responsible for correct results with
// multithreaded execution
llvm::LoadInst *load = gIR->ir->CreateAlignedLoad(
#if LDC_LLVM_VER >= 800
i32Type,
#endif
ptr, LLAlign(4));
llvm::StoreInst *store = gIR->ir->CreateAlignedStore(
gIR->ir->CreateAdd(load, DtoConstUint(1)), ptr, LLAlign(4));
// add !nontemporal attribute, to inform the optimizer that caching is not
// needed
llvm::MDNode *node = llvm::MDNode::get(
gIR->context(), llvm::ConstantAsMetadata::get(DtoConstInt(1)));
load->setMetadata("nontemporal", node);
store->setMetadata("nontemporal", node);
break;
}
case opts::CoverageIncrement::boolean: {
// Do a boolean set, avoiding a memory read (blocking) and threading issues
// at the cost of not "counting"
llvm::StoreInst *store =
gIR->ir->CreateAlignedStore(DtoConstUint(1), ptr, LLAlign(4));
// add !nontemporal attribute, to inform the optimizer that caching is not
// needed
llvm::MDNode *node = llvm::MDNode::get(
gIR->context(), llvm::ConstantAsMetadata::get(DtoConstInt(1)));
store->setMetadata("nontemporal", node);
break;
}
}
// Set the 'counter valid' bit to 1 for this line of code
unsigned num_sizet_bits = gDataLayout->getTypeSizeInBits(DtoSize_t());
unsigned idx = line / num_sizet_bits;
unsigned bitidx = line % num_sizet_bits;
IF_LOG Logger::println("_d_cover_valid[%d] |= (1 << %d)", idx, bitidx);
m->d_cover_valid_init[idx] |= (size_t(1) << bitidx);
}