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" |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 16 | #include "llvm/Support/ErrorHandling.h" |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 17 | |
| 18 | using namespace llvm; |
| 19 | using namespace coverage; |
| 20 | |
| 21 | CounterExpressionBuilder::CounterExpressionBuilder(unsigned NumCounterValues) { |
| 22 | Terms.resize(NumCounterValues); |
| 23 | } |
| 24 | |
| 25 | Counter CounterExpressionBuilder::get(const CounterExpression &E) { |
| 26 | for (unsigned I = 0, S = Expressions.size(); I < S; ++I) { |
| 27 | if (Expressions[I] == E) |
| 28 | return Counter::getExpression(I); |
| 29 | } |
| 30 | Expressions.push_back(E); |
| 31 | return Counter::getExpression(Expressions.size() - 1); |
| 32 | } |
| 33 | |
| 34 | void CounterExpressionBuilder::extractTerms(Counter C, int Sign) { |
| 35 | switch (C.getKind()) { |
| 36 | case Counter::Zero: |
| 37 | break; |
| 38 | case Counter::CounterValueReference: |
| 39 | Terms[C.getCounterID()] += Sign; |
| 40 | break; |
| 41 | case Counter::Expression: |
| 42 | const auto &E = Expressions[C.getExpressionID()]; |
| 43 | extractTerms(E.LHS, Sign); |
| 44 | extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign); |
| 45 | break; |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { |
| 50 | // Gather constant terms. |
| 51 | for (auto &I : Terms) |
| 52 | I = 0; |
| 53 | extractTerms(ExpressionTree); |
| 54 | |
| 55 | Counter C; |
| 56 | // Create additions. |
| 57 | // Note: the additions are created first |
| 58 | // to avoid creation of a tree like ((0 - X) + Y) instead of (Y - X). |
| 59 | for (unsigned I = 0, S = Terms.size(); I < S; ++I) { |
| 60 | if (Terms[I] <= 0) |
| 61 | continue; |
| 62 | for (int J = 0; J < Terms[I]; ++J) { |
| 63 | if (C.isZero()) |
| 64 | C = Counter::getCounter(I); |
| 65 | else |
| 66 | C = get(CounterExpression(CounterExpression::Add, C, |
| 67 | Counter::getCounter(I))); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // Create subtractions. |
| 72 | for (unsigned I = 0, S = Terms.size(); I < S; ++I) { |
| 73 | if (Terms[I] >= 0) |
| 74 | continue; |
| 75 | for (int J = 0; J < (-Terms[I]); ++J) |
| 76 | C = get(CounterExpression(CounterExpression::Subtract, C, |
| 77 | Counter::getCounter(I))); |
| 78 | } |
| 79 | return C; |
| 80 | } |
| 81 | |
| 82 | Counter CounterExpressionBuilder::add(Counter LHS, Counter RHS) { |
| 83 | return simplify(get(CounterExpression(CounterExpression::Add, LHS, RHS))); |
| 84 | } |
| 85 | |
| 86 | Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS) { |
| 87 | return simplify( |
| 88 | get(CounterExpression(CounterExpression::Subtract, LHS, RHS))); |
| 89 | } |
| 90 | |
| 91 | void CounterMappingContext::dump(const Counter &C, |
| 92 | llvm::raw_ostream &OS) const { |
| 93 | switch (C.getKind()) { |
| 94 | case Counter::Zero: |
| 95 | OS << '0'; |
| 96 | return; |
| 97 | case Counter::CounterValueReference: |
| 98 | OS << '#' << C.getCounterID(); |
| 99 | break; |
| 100 | case Counter::Expression: { |
| 101 | if (C.getExpressionID() >= Expressions.size()) |
| 102 | return; |
| 103 | const auto &E = Expressions[C.getExpressionID()]; |
| 104 | OS << '('; |
Alex Lorenz | a422911c | 2014-07-29 19:58:16 +0000 | [diff] [blame] | 105 | dump(E.LHS, OS); |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 106 | OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); |
Alex Lorenz | a422911c | 2014-07-29 19:58:16 +0000 | [diff] [blame] | 107 | dump(E.RHS, OS); |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 108 | OS << ')'; |
| 109 | break; |
| 110 | } |
| 111 | } |
| 112 | if (CounterValues.empty()) |
| 113 | return; |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 114 | ErrorOr<int64_t> Value = evaluate(C); |
| 115 | if (!Value) |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 116 | return; |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 117 | OS << '[' << *Value << ']'; |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 118 | } |
| 119 | |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 120 | ErrorOr<int64_t> CounterMappingContext::evaluate(const Counter &C) const { |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 121 | switch (C.getKind()) { |
| 122 | case Counter::Zero: |
| 123 | return 0; |
| 124 | case Counter::CounterValueReference: |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 125 | if (C.getCounterID() >= CounterValues.size()) |
Justin Bogner | 3f18834 | 2014-09-08 21:31:43 +0000 | [diff] [blame] | 126 | return std::make_error_code(std::errc::argument_out_of_domain); |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 127 | return CounterValues[C.getCounterID()]; |
| 128 | case Counter::Expression: { |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 129 | if (C.getExpressionID() >= Expressions.size()) |
Justin Bogner | 3f18834 | 2014-09-08 21:31:43 +0000 | [diff] [blame] | 130 | return std::make_error_code(std::errc::argument_out_of_domain); |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 131 | const auto &E = Expressions[C.getExpressionID()]; |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 132 | ErrorOr<int64_t> LHS = evaluate(E.LHS); |
| 133 | if (!LHS) |
| 134 | return LHS; |
| 135 | ErrorOr<int64_t> RHS = evaluate(E.RHS); |
| 136 | if (!RHS) |
| 137 | return RHS; |
| 138 | return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS; |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 139 | } |
| 140 | } |
Justin Bogner | 85b0a03 | 2014-09-08 21:04:00 +0000 | [diff] [blame] | 141 | llvm_unreachable("Unhandled CounterKind"); |
Alex Lorenz | a20a5d5 | 2014-07-24 23:57:54 +0000 | [diff] [blame] | 142 | } |