OmniSciDB  2e3a973ef4
AutomaticIRMetadataGuard.h
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cctype>
20 #include <cstdint>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "CgenState.h"
26 
27 #ifndef NDEBUG
28 
30  public:
32  const std::string& ppfile,
33  const size_t ppline,
34  const std::string& ppfunc)
35  : cgen_state_(cgen_state)
36  , ppfile_(ppfile)
37  , ppline_(ppline)
38  , ppfunc_(ppfunc)
39  , our_instructions_(nullptr)
40  , done_(false)
46  }
47 
49 
50  void done() noexcept {
51  if (!done_) {
53  if (this_is_root_) {
56  }
57  done_ = true;
58  }
59  }
60 
62  // iterate over all LLVM instructions in the module
63  for (auto func_it = cgen_state_->module_->begin();
64  func_it != cgen_state_->module_->end();
65  ++func_it) {
66  for (auto bb_it = func_it->begin(); bb_it != func_it->end(); ++bb_it) {
67  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
68  // remember all the instructions that already existed
69  // before this guard object was constructed
70  CHECK_EQ(preexisting_instructions_.count(&*instr_it), 0U);
71  preexisting_instructions_.insert(&*instr_it);
72  }
73  }
74  }
75  }
76 
77  void rememberOurInstructions() noexcept {
78  // iterate over all LLVM instructions in the module
79  for (auto func_it = cgen_state_->module_->begin();
80  func_it != cgen_state_->module_->end();
81  ++func_it) {
82  for (auto bb_it = func_it->begin(); bb_it != func_it->end(); ++bb_it) {
83  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
84  // remember any new instructions as ours, skipping
85  // instructions already remembered as preexisting
86  llvm::Instruction* i = &*instr_it;
87  if (!preexisting_instructions_.count(i)) {
88  std::string qefile = makeQueryEngineFilename();
89  std::string footnote =
90  ppfunc_ + " near " + qefile + " line #" + std::to_string(ppline_);
91  auto it = our_instructions_->find(i);
92  if (it == our_instructions_->end()) {
93  std::string bfile = replacePunctuation(makeBaseFilename());
94  our_instructions_->emplace(i, InstructionInfo{bfile, footnote});
95  } else {
96  it->second.detailed_footnote_ =
97  footnote + ", " + it->second.detailed_footnote_;
98  }
99  }
100  }
101  }
102  }
103  }
104 
105  void markInstructions() noexcept {
106  // iterate over all LLVM instructions in the module
107  for (auto func_it = cgen_state_->module_->begin();
108  func_it != cgen_state_->module_->end();
109  ++func_it) {
110  for (auto bb_it = func_it->begin(); bb_it != func_it->end(); ++bb_it) {
111  for (auto instr_it = bb_it->begin(); instr_it != bb_it->end(); ++instr_it) {
112  auto our_it = our_instructions_->find(&*instr_it);
113  if (our_it == our_instructions_->end()) {
114  continue;
115  }
116  unsigned kind_id =
117  cgen_state_->context_.getMDKindID(our_it->second.main_filename_);
118  auto value = llvm::MDNode::get(
120  llvm::MDString::get(
122  detailed_footnote_prefix_ + our_it->second.detailed_footnote_));
123  our_it->first->setMetadata(kind_id, value);
124  }
125  }
126  }
127  }
128 
129  private:
130  std::string makeBaseFilename() {
131  std::vector<std::string> fnames = split(ppfile_, "/");
132  if (!fnames.empty()) {
133  return fnames.back();
134  }
135  return ppfile_;
136  }
137 
138  std::string makeQueryEngineFilename() {
139  std::vector<std::string> fnames = split(ppfile_, "/");
140  bool copying{false};
141  std::string f;
142  for (auto n : fnames) {
143  if (copying && !n.empty()) {
144  if (!f.empty()) {
145  f += "/";
146  }
147  f += n;
148  }
149  if (n == "QueryEngine") {
150  copying = true;
151  }
152  }
153  if (f.empty() && fnames.size() > 0) {
154  f = fnames.back();
155  } else if (f.empty()) {
156  f = ppfile_;
157  }
158  return f;
159  }
160 
161  std::string replacePunctuation(std::string text) {
162  static const std::unordered_set<std::string::value_type> allowed_punct{'_', '.'};
163  for (auto& ch : text) {
164  if (std::ispunct(ch) && !allowed_punct.count(ch)) {
165  ch = '_';
166  }
167  }
168  return text;
169  }
170 
171  private:
173  std::string main_filename_;
174  std::string detailed_footnote_;
175  };
176  using OurInstructions = std::unordered_map<llvm::Instruction*, InstructionInfo>;
177 
179 
180  const std::string ppfile_;
181  const size_t ppline_;
182  const std::string ppfunc_;
183 
184  std::unordered_set<llvm::Instruction*> preexisting_instructions_;
186 
187  bool done_;
189 
190  inline static std::unordered_map<CgenState*, OurInstructions> instructions_;
191 
192  inline static const std::string detailed_footnote_prefix_{"Omnisci Debugging Info: "};
193 };
194 
195 #define AUTOMATIC_IR_METADATA(CGENSTATE) \
196  AutomaticIRMetadataGuard automatic_ir_metadata_guard( \
197  CGENSTATE, __FILE__, __LINE__, __func__)
198 
199 #define AUTOMATIC_IR_METADATA_DONE() automatic_ir_metadata_guard.done()
200 
201 #else // NDEBUG
202 
203 #define AUTOMATIC_IR_METADATA(CGENSTATE)
204 #define AUTOMATIC_IR_METADATA_DONE()
205 
206 #endif // NDEBUG
#define CHECK_EQ(x, y)
Definition: Logger.h:205
void rememberPreexistingInstructions() noexcept
std::string to_string(char const *&&v)
std::vector< std::string > split(std::string_view str, std::string_view delim, std::optional< size_t > maxsplit)
split apart a string into a vector of substrings
AutomaticIRMetadataGuard(CgenState *cgen_state, const std::string &ppfile, const size_t ppline, const std::string &ppfunc)
llvm::Module * module_
Definition: CgenState.h:330
llvm::LLVMContext & context_
Definition: CgenState.h:339
static std::unordered_map< CgenState *, OurInstructions > instructions_
std::unordered_map< llvm::Instruction *, InstructionInfo > OurInstructions
std::unordered_set< llvm::Instruction * > preexisting_instructions_
#define CHECK(condition)
Definition: Logger.h:197
std::string replacePunctuation(std::string text)
static const std::string detailed_footnote_prefix_