File: coverage.cpp

package info (click to toggle)
ldc 1%3A1.30.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 59,248 kB
  • sloc: cpp: 61,598; ansic: 14,545; sh: 1,014; makefile: 972; asm: 510; objc: 135; exp: 48; python: 12
file content (85 lines) | stat: -rw-r--r-- 3,421 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//===-- 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(i32Type, 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);
}