[llvm-exegesis] Fix missing std::move.
[llvm-complete.git] / lib / XRay / BlockVerifier.cpp
blob62be1a87ab5b94e715f668b3ee944755d114ea74
1 //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
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 #include "llvm/XRay/BlockVerifier.h"
10 #include "llvm/Support/Error.h"
12 namespace llvm {
13 namespace xray {
14 namespace {
16 constexpr unsigned long long mask(BlockVerifier::State S) {
17 return 1uLL << static_cast<std::size_t>(S);
20 constexpr std::size_t number(BlockVerifier::State S) {
21 return static_cast<std::size_t>(S);
24 StringRef recordToString(BlockVerifier::State R) {
25 switch (R) {
26 case BlockVerifier::State::BufferExtents:
27 return "BufferExtents";
28 case BlockVerifier::State::NewBuffer:
29 return "NewBuffer";
30 case BlockVerifier::State::WallClockTime:
31 return "WallClockTime";
32 case BlockVerifier::State::PIDEntry:
33 return "PIDEntry";
34 case BlockVerifier::State::NewCPUId:
35 return "NewCPUId";
36 case BlockVerifier::State::TSCWrap:
37 return "TSCWrap";
38 case BlockVerifier::State::CustomEvent:
39 return "CustomEvent";
40 case BlockVerifier::State::Function:
41 return "Function";
42 case BlockVerifier::State::CallArg:
43 return "CallArg";
44 case BlockVerifier::State::EndOfBuffer:
45 return "EndOfBuffer";
46 case BlockVerifier::State::StateMax:
47 case BlockVerifier::State::Unknown:
48 return "Unknown";
50 llvm_unreachable("Unkown state!");
53 struct Transition {
54 BlockVerifier::State From;
55 std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
58 } // namespace
60 Error BlockVerifier::transition(State To) {
61 using ToSet = std::bitset<number(State::StateMax)>;
62 static constexpr std::array<const Transition, number(State::StateMax)>
63 TransitionTable{{{State::Unknown,
64 {mask(State::BufferExtents) | mask(State::NewBuffer)}},
66 {State::BufferExtents, {mask(State::NewBuffer)}},
68 {State::NewBuffer, {mask(State::WallClockTime)}},
70 {State::WallClockTime,
71 {mask(State::PIDEntry) | mask(State::NewCPUId)}},
73 {State::PIDEntry, {mask(State::NewCPUId)}},
75 {State::NewCPUId,
76 {mask(State::NewCPUId) | mask(State::TSCWrap) |
77 mask(State::CustomEvent) | mask(State::Function) |
78 mask(State::EndOfBuffer)}},
80 {State::TSCWrap,
81 {mask(State::TSCWrap) | mask(State::NewCPUId) |
82 mask(State::CustomEvent) | mask(State::Function) |
83 mask(State::EndOfBuffer)}},
85 {State::CustomEvent,
86 {mask(State::CustomEvent) | mask(State::TSCWrap) |
87 mask(State::NewCPUId) | mask(State::Function) |
88 mask(State::EndOfBuffer)}},
90 {State::Function,
91 {mask(State::Function) | mask(State::TSCWrap) |
92 mask(State::NewCPUId) | mask(State::CustomEvent) |
93 mask(State::CallArg) | mask(State::EndOfBuffer)}},
95 {State::CallArg,
96 {mask(State::CallArg) | mask(State::Function) |
97 mask(State::TSCWrap) | mask(State::NewCPUId) |
98 mask(State::CustomEvent) | mask(State::EndOfBuffer)}},
100 {State::EndOfBuffer, {}}}};
102 if (CurrentRecord >= State::StateMax)
103 return createStringError(
104 std::make_error_code(std::errc::executable_format_error),
105 "BUG (BlockVerifier): Cannot find transition table entry for %s, "
106 "transitioning to %s.",
107 recordToString(CurrentRecord).data(), recordToString(To).data());
109 // If we're at an EndOfBuffer record, we ignore anything that follows that
110 // isn't a NewBuffer record.
111 if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
112 return Error::success();
114 auto &Mapping = TransitionTable[number(CurrentRecord)];
115 auto &Destinations = Mapping.ToStates;
116 assert(Mapping.From == CurrentRecord &&
117 "BUG: Wrong index for record mapping.");
118 if ((Destinations & ToSet(mask(To))) == 0)
119 return createStringError(
120 std::make_error_code(std::errc::executable_format_error),
121 "BlockVerifier: Invalid transition from %s to %s.",
122 recordToString(CurrentRecord).data(), recordToString(To).data());
124 CurrentRecord = To;
125 return Error::success();
126 } // namespace xray
128 Error BlockVerifier::visit(BufferExtents &) {
129 return transition(State::BufferExtents);
132 Error BlockVerifier::visit(WallclockRecord &) {
133 return transition(State::WallClockTime);
136 Error BlockVerifier::visit(NewCPUIDRecord &) {
137 return transition(State::NewCPUId);
140 Error BlockVerifier::visit(TSCWrapRecord &) {
141 return transition(State::TSCWrap);
144 Error BlockVerifier::visit(CustomEventRecord &) {
145 return transition(State::CustomEvent);
148 Error BlockVerifier::visit(CallArgRecord &) {
149 return transition(State::CallArg);
152 Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
154 Error BlockVerifier::visit(NewBufferRecord &) {
155 return transition(State::NewBuffer);
158 Error BlockVerifier::visit(EndBufferRecord &) {
159 return transition(State::EndOfBuffer);
162 Error BlockVerifier::visit(FunctionRecord &) {
163 return transition(State::Function);
166 Error BlockVerifier::verify() {
167 // The known terminal conditions are the following:
168 switch (CurrentRecord) {
169 case State::EndOfBuffer:
170 case State::NewCPUId:
171 case State::CustomEvent:
172 case State::Function:
173 case State::CallArg:
174 case State::TSCWrap:
175 return Error::success();
176 default:
177 return createStringError(
178 std::make_error_code(std::errc::executable_format_error),
179 "BlockVerifier: Invalid terminal condition %s, malformed block.",
180 recordToString(CurrentRecord).data());
184 void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
186 } // namespace xray
187 } // namespace llvm