Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 1 | //=-- CoverageMapping.cpp - Code coverage mapping support ---------*- C++ -*-=// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file contains support for clang's and llvm's instrumentation based |
| 11 | // code coverage. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "llvm/ProfileData/CoverageMapping.h" |
| 16 | |
| 17 | using namespace llvm; |
| 18 | using namespace coverage; |
| 19 | |
| 20 | CounterExpressionBuilder::CounterExpressionBuilder(unsigned NumCounterValues) { |
| 21 | Terms.resize(NumCounterValues); |
| 22 | } |
| 23 | |
| 24 | Counter CounterExpressionBuilder::get(const CounterExpression &E) { |
| 25 | for (unsigned I = 0, S = Expressions.size(); I < S; ++I) { |
| 26 | if (Expressions[I] == E) |
| 27 | return Counter::getExpression(I); |
| 28 | } |
| 29 | Expressions.push_back(E); |
| 30 | return Counter::getExpression(Expressions.size() - 1); |
| 31 | } |
| 32 | |
| 33 | void CounterExpressionBuilder::extractTerms(Counter C, int Sign) { |
| 34 | switch (C.getKind()) { |
| 35 | case Counter::Zero: |
| 36 | break; |
| 37 | case Counter::CounterValueReference: |
| 38 | Terms[C.getCounterID()] += Sign; |
| 39 | break; |
| 40 | case Counter::Expression: |
| 41 | const auto &E = Expressions[C.getExpressionID()]; |
| 42 | extractTerms(E.LHS, Sign); |
| 43 | extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign); |
| 44 | break; |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { |
| 49 | // Gather constant terms. |
| 50 | for (auto &I : Terms) |
| 51 | I = 0; |
| 52 | extractTerms(ExpressionTree); |
| 53 | |
| 54 | Counter C; |
| 55 | // Create additions. |
| 56 | // Note: the additions are created first |
| 57 | // to avoid creation of a tree like ((0 - X) + Y) instead of (Y - X). |
| 58 | for (unsigned I = 0, S = Terms.size(); I < S; ++I) { |
| 59 | if (Terms[I] <= 0) |
| 60 | continue; |
| 61 | for (int J = 0; J < Terms[I]; ++J) { |
| 62 | if (C.isZero()) |
| 63 | C = Counter::getCounter(I); |
| 64 | else |
| 65 | C = get(CounterExpression(CounterExpression::Add, C, |
| 66 | Counter::getCounter(I))); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // Create subtractions. |
| 71 | for (unsigned I = 0, S = Terms.size(); I < S; ++I) { |
| 72 | if (Terms[I] >= 0) |
| 73 | continue; |
| 74 | for (int J = 0; J < (-Terms[I]); ++J) |
| 75 | C = get(CounterExpression(CounterExpression::Subtract, C, |
| 76 | Counter::getCounter(I))); |
| 77 | } |
| 78 | return C; |
| 79 | } |
| 80 | |
| 81 | Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) { |
| 82 | return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS))); |
| 83 | } |
| 84 | |
| 85 | Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) { |
| 86 | return simplify( |
| 87 | get(CounterExpression(CounterExpression::Subtract, LHS, RHS))); |
| 88 | } |
| 89 | |
| 90 | void CounterMappingContext::dump(const Counter &C, |
| 91 | llvm::raw_ostream &OS) const { |
| 92 | switch (C.getKind()) { |
| 93 | case Counter::Zero: |
| 94 | OS << '0'; |
| 95 | return; |
| 96 | case Counter::CounterValueReference: |
| 97 | OS << '#' << C.getCounterID(); |
| 98 | break; |
| 99 | case Counter::Expression: { |
| 100 | if (C.getExpressionID() >= Expressions.size()) |
| 101 | return; |
| 102 | const auto &E = Expressions[C.getExpressionID()]; |
| 103 | OS << '('; |
| 104 | dump(E.LHS); |
| 105 | OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); |
| 106 | dump(E.RHS); |
| 107 | OS << ')'; |
| 108 | break; |
| 109 | } |
| 110 | } |
| 111 | if (CounterValues.empty()) |
| 112 | return; |
| 113 | std::error_code Error; |
| 114 | auto Value = evaluate(C, Error); |
| 115 | if (Error) |
| 116 | return; |
| 117 | OS << '[' << Value << ']'; |
| 118 | } |
| 119 | |
| 120 | int64_t CounterMappingContext::evaluate(const Counter &C, |
| 121 | std::error_code *EC) const { |
| 122 | switch (C.getKind()) { |
| 123 | case Counter::Zero: |
| 124 | return 0; |
| 125 | case Counter::CounterValueReference: |
| 126 | if (C.getCounterID() >= CounterValues.size()) { |
| 127 | if (EC) |
| 128 | *EC = std::make_error_code(std::errc::argument_out_of_domain); |
| 129 | break; |
| 130 | } |
| 131 | return CounterValues[C.getCounterID()]; |
| 132 | case Counter::Expression: { |
| 133 | if (C.getExpressionID() >= Expressions.size()) { |
| 134 | if (EC) |
| 135 | *EC = std::make_error_code(std::errc::argument_out_of_domain); |
| 136 | break; |
| 137 | } |
| 138 | const auto &E = Expressions[C.getExpressionID()]; |
| 139 | auto LHS = evaluate(E.LHS, EC); |
| 140 | if (EC && *EC) |
| 141 | return 0; |
| 142 | auto RHS = evaluate(E.RHS, EC); |
| 143 | if (EC && *EC) |
| 144 | return 0; |
| 145 | return E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS; |
| 146 | } |
| 147 | } |
| 148 | return 0; |
| 149 | } |