• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ahueck / llvm-dimeta / 13933486559

18 Mar 2025 09:06PM UTC coverage: 83.197% (-0.4%) from 83.637%
13933486559

push

github

web-flow
Refactoring (#35)

1027 of 1482 branches covered (69.3%)

Branch coverage included in aggregate %.

86 of 87 new or added lines in 10 files covered. (98.85%)

17 existing lines in 7 files now uncovered.

1924 of 2065 relevant lines covered (93.17%)

3950.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.69
/test/verifier/TestPass.cpp
1
//  Dimeta library
2
//  Copyright (c) 2022-2025 llvm-dimeta authors
3
//  Distributed under the BSD 3-Clause license.
4
//  (See accompanying file LICENSE)
5
//  SPDX-License-Identifier: BSD-3-Clause
6
//
7

8
#include "support/Logger.h"
9
#include "type/DIUtil.h"
10
#include "type/DIVisitor.h"
11
#include "type/Dimeta.h"
12
#include "type/DimetaData.h"
13
#include "type/DimetaIO.h"
14
#include "type/DimetaParse.h"
15

16
#include "llvm-c/Types.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/StringRef.h"
19
#include "llvm/ADT/ilist_iterator.h"
20
#include "llvm/Demangle/Demangle.h"
21
#include "llvm/IR/DebugInfoMetadata.h"
22
#include "llvm/IR/Function.h"
23
#include "llvm/IR/InstIterator.h"
24
#include "llvm/IR/InstrTypes.h"
25
#include "llvm/IR/Instructions.h"
26
#include "llvm/IR/LegacyPassManager.h"
27
#include "llvm/IR/Module.h"
28
#include "llvm/IR/Value.h"
29
#include "llvm/Pass.h"
30
#include "llvm/Passes/PassBuilder.h"
31
#include "llvm/Passes/PassPlugin.h"
32
#include "llvm/Support/Casting.h"
33
#include "llvm/Support/CommandLine.h"
34
#include "llvm/Support/ErrorHandling.h"
35
#include "llvm/Support/raw_ostream.h"
36

37
#include <iomanip>
38
#include <iterator>
39
#include <optional>
40
#include <sstream>
41
#include <string>
42
#include <string_view>
43

44
namespace llvm {
45
class PointerType;
46
}  // namespace llvm
47

48
using namespace llvm;
49

50
static cl::opt<bool> cl_dimeta_test_print_yaml("yaml", cl::init(true));
953✔
51
static cl::opt<bool> cl_dimeta_test_print_yaml_retained("yaml-retained", cl::init(false));
953✔
52
static cl::opt<bool> cl_dimeta_test_print_tree("dump-tree", cl::init(false));
953✔
53
static cl::opt<bool> cl_dimeta_test_stack_pointer("stack-pointer-skip", cl::init(false));
953✔
54
static cl::opt<bool> cl_dimeta_test_print("dump", cl::init(false));
953✔
55

56
namespace dimeta::test {
57

58
template <typename String>
59
inline std::string demangle(String&& s) {
1,436✔
60
  std::string name = std::string{s};
1,436✔
61
#if LLVM_VERSION_MAJOR >= 17
62
  auto demangle = llvm::itaniumDemangle(name.data());
585✔
63
#else
64
  auto demangle = llvm::itaniumDemangle(name.data(), nullptr, nullptr, nullptr);
851✔
65
#endif
66
  if (demangle && !std::string(demangle).empty()) {
1,436✔
67
    return {demangle};
792✔
68
  }
69
  return name;
644✔
70
}
1,436✔
71

72
template <typename T>
73
inline std::string try_demangle(const T& site) {
1,436✔
74
  if constexpr (std::is_same_v<T, llvm::CallBase>) {
75
    if (site.isIndirectCall()) {
76
      return "";
77
    }
78
    return demangle(site.getCalledFunction()->getName());
79
  } else {
80
    if constexpr (std::is_same_v<T, llvm::Function>) {
81
      return demangle(site.getName());
1,436✔
82
    } else {
83
      return demangle(site);
84
    }
85
  }
86
}
87

88
namespace util {
89

90
std::string rep_string(const std::string& input, int rep) {
2,724✔
91
  std::ostringstream os;
2,724✔
92
  std::fill_n(std::ostream_iterator<std::string>(os), rep, input);
2,724✔
93
  return os.str();
2,724✔
94
}
2,724✔
95

96
auto to_string(dimeta::DimetaData& data, bool stack = false) {
2,724✔
97
  const std::string prefix = [&]() {
5,448✔
98
    switch (data.memory_location) {
2,724✔
99
      case DimetaData::MemLoc::kGlobal:
100
        return " Global";
141✔
101
      case DimetaData::MemLoc::kStack:
102
        return " Stack";
1,805✔
103
      default:
104
        return "";
778✔
105
    }
106
  }();
2,724✔
107

108
  std::string logging_message;
2,724✔
109
  llvm::raw_string_ostream rso(logging_message);
2,724✔
110
  rso << "Extracted Type" << prefix << ": " << log::ditype_str(data.entry_type.value_or(nullptr)) << "\n";
2,724✔
111
  rso << "Final Type" << prefix << ": " << log::ditype_str(data.base_type.value_or(nullptr)) << "\n";
2,724✔
112
  rso << "Pointer level: " << data.pointer_level << " (T" << rep_string("*", data.pointer_level) << ")\n";
2,724✔
113
  return rso.str();
2,724✔
114
}
2,724✔
115

116
auto print_loc(std::optional<location::SourceLocation> loc) {
2,716✔
117
  std::string logging_message;
2,716✔
118
  llvm::raw_string_ostream rso(logging_message);
2,716✔
119
  rso << "Location: ";
2,716✔
120
  if (loc) {
2,716!
121
    rso << "\"" << loc->file << "\":\"" << loc->function << "\":" << loc->line;
2,716✔
122
  } else {
2,716✔
123
    rso << "empty";
×
124
  }
125
  return rso.str();
2,716✔
126
}
2,716✔
127

128
template <typename T>
129
bool variable_is_toggled(const T& var, std::string_view env_name) {
9,212✔
130
  if (var.getNumOccurrences() > 0) {
9,212!
UNCOV
131
    return var.getValue();
×
132
  }
133
  const char* env_value = std::getenv(env_name.data());
9,212✔
134
  if (env_value != nullptr) {
9,212✔
135
    return std::string_view{env_value}.compare("1") == 0;
620✔
136
  }
137
  return var.getValue();
8,592✔
138
}
9,212✔
139

140
}  // namespace util
141

142
class TestPass : public llvm::PassInfoMixin<TestPass> {
1,906✔
143
 private:
144
  Module* current_module{nullptr};
1,906✔
145

146
  template <typename Type>
147
  bool serialization_roundtrip(Type compound, bool print_yaml = false) {
2,716✔
148
    std::string initial_oss_string;
2,716✔
149
    llvm::raw_string_ostream initial_oss(initial_oss_string);
2,716✔
150
    io::emit(initial_oss, compound);
2,716✔
151

152
    if (print_yaml) {
2,716!
153
      llvm::outs() << initial_oss.str();
2,716✔
154
    }
2,716✔
155

156
    Type cmp;
2,716✔
157
    dimeta::io::input(initial_oss.str(), cmp);
2,716✔
158

159
    std::string roundtrip_oss_string;
2,716✔
160
    llvm::raw_string_ostream roundtrip_oss(roundtrip_oss_string);
2,716✔
161
    io::emit(roundtrip_oss, cmp);
2,716✔
162

163
    llvm::StringRef const initial{initial_oss.str()};
2,716✔
164

165
    return initial.compare(llvm::StringRef{roundtrip_oss.str()}) == 0;
2,716✔
166
  }
2,716✔
167

168
 public:
169
  llvm::PreservedAnalyses run(llvm::Module& module, llvm::ModuleAnalysisManager&) {
928✔
170
    const auto changed = runOnModule(module);
928✔
171
    return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all();
928!
172
  }
928✔
173

174
  bool runOnModule(Module& module) {
953✔
175
    this->current_module = &module;
953✔
176
    log::LogContext::get().setModule(&module);
953✔
177

178
    const auto serialize_yaml = [&](const auto& located_type) {
1,094✔
179
      bool result{false};
141✔
180
      if (located_type) {
141!
181
        result = serialization_roundtrip(located_type.value(),
282✔
182
                                         util::variable_is_toggled(cl_dimeta_test_print_yaml, "DIMETA_TEST_YAML"));
141✔
183
      }
141✔
184
      LOG_MSG("Yaml Verifier Global: " << static_cast<int>(result));
141✔
185
    };
141✔
186

187
    for (auto& global : module.globals()) {
1,303✔
188
      auto global_meta = type_for(&global);
350✔
189
      if (global_meta) {
350✔
190
        LOG_DEBUG("Type for global: " << global)
141✔
191
        LOG_DEBUG(util::to_string(global_meta.value()));
141✔
192
        auto located_type = located_type_for(&global);
141✔
193
        if (located_type) {
141!
194
          LOG_DEBUG(util::print_loc(located_type->location));
141✔
195
          serialize_yaml(located_type);
141✔
196
        } else {
141✔
197
          LOG_ERROR("No located dimeta type for global")
×
198
        }
199
      }
141✔
200
    }
350✔
201

202
    auto compile_unit_list = dimeta::compile_unit_types(&module).value_or(CompileUnitTypeList{});
953✔
203
    if (util::variable_is_toggled(cl_dimeta_test_print_yaml_retained, "DIMETA_TEST_YAML_RETAINED")) {
953✔
204
      std::string initial_oss_string;
4✔
205
      llvm::raw_string_ostream initial_oss(initial_oss_string);
4✔
206
      io::emit(initial_oss, compile_unit_list);
4✔
207
      llvm::outs() << initial_oss.str();
4✔
208
      // for (const auto& cu : compile_unit_list) {
209
      //   std::string initial_oss_string;
210
      //   llvm::raw_string_ostream initial_oss(initial_oss_string);
211
      //   io::emit(initial_oss, cu);
212
      //   llvm::outs() << initial_oss.str();
213
      // }
214
    }
4✔
215

216
    llvm::for_each(module.functions(), [&](auto& func) { return runOnFunc(func); });
4,933✔
217
    return false;
218
  }
953✔
219

220
  void runOnFunc(Function& func) {
3,955✔
221
    if (func.isDeclaration()) {
3,955✔
222
      return;
2,544✔
223
    }
224
    const auto f_name = try_demangle(func);
1,411✔
225
    // const auto f_name_ref = llvm::StringRef(f_name);
226

227
    LOG_MSG("\nFunction: " << f_name << ":");
1,411✔
228

229
    const auto get_located_type = [&](auto* call_inst) -> std::optional<LocatedType> {
7,996✔
230
      auto located_type = located_type_for(call_inst);
6,585✔
231
      if (located_type) {
6,585!
232
        LOG_DEBUG(util::print_loc(located_type->location));
2,575✔
233
        return located_type;
2,575✔
234
      }
235
      LOG_ERROR("No located dimeta type.")
4,010✔
236
      return {};
4,010✔
237
    };
6,585✔
238

239
    const auto serialize_yaml = [&](auto* inst) {
3,994✔
240
      auto located_type = get_located_type(inst);
2,583✔
241
      bool result{false};
2,583✔
242
      if (located_type) {
2,583!
243
        result = serialization_roundtrip(located_type.value(),
5,150✔
244
                                         util::variable_is_toggled(cl_dimeta_test_print_yaml, "DIMETA_TEST_YAML"));
2,575✔
245
      }
2,575✔
246
      LOG_MSG(*inst << ": Yaml Verifier: " << static_cast<int>(result));
2,583✔
247
    };
2,583✔
248

249
    const auto print_di_tree = [&](const DimetaData& di_var) {
3,216✔
250
      if (util::variable_is_toggled(cl_dimeta_test_print, "DIMETA_TEST_DUMP")) {
1,805✔
251
        di::util::print_dinode(std::get<DILocalVariable*>(di_var.di_variable.value()), outs(), current_module);
5✔
252
      }
5✔
253
    };
1,805✔
254

255
    const auto dump_di_tree = [&](const DimetaData& di_var) {
3,216✔
256
      if (util::variable_is_toggled(cl_dimeta_test_print_tree, "DIMETA_TEST_DUMP_TREE")) {
1,805!
257
        auto local_di_var = std::get<DILocalVariable*>(di_var.di_variable.value());
×
258
#if LLVM_VERSION_MAJOR < 14
259
        local_di_var->print(outs(), current_module);
260
#else
261
        local_di_var->dumpTree(current_module);
262
#endif
263
      }
×
264
    };
1,805✔
265

266
    for (auto& inst : llvm::instructions(func)) {
19,421✔
267
      if (auto* call_inst = dyn_cast<CallBase>(&inst)) {
22,790✔
268
        auto ditype_meta = type_for(call_inst);
4,780✔
269
        if (ditype_meta) {
4,780✔
270
          LOG_DEBUG("Type for heap-like: " << *call_inst)
778✔
271
          LOG_DEBUG(util::to_string(ditype_meta.value()) << "\n");
778✔
272
          // auto result = located_type_for(ditype_meta.value());
273
          serialize_yaml(call_inst);
778✔
274
          continue;
778✔
275
        }
276
        get_located_type(call_inst);
4,002✔
277
      }
4,780✔
278

279
      if (auto* alloca_inst = dyn_cast<AllocaInst>(&inst)) {
19,165!
280
        if (util::variable_is_toggled(cl_dimeta_test_stack_pointer, "DIMETA_TEST_STACK_POINTER_SKIP") &&
1,933!
281
            isa<llvm::PointerType>(alloca_inst->getAllocatedType())) {
×
282
          LOG_DEBUG("Skip " << *alloca_inst << "\n");
×
283
          continue;
×
284
        }
285
        auto di_var = type_for(alloca_inst);
1,933✔
286
        if (di_var) {
1,933✔
287
          LOG_DEBUG("Type for alloca: " << *alloca_inst)
1,805✔
288
          LOG_DEBUG(util::to_string(di_var.value()) << "\n");
1,805✔
289
          dump_di_tree(di_var.value());
1,805✔
290
          print_di_tree(di_var.value());
1,805✔
291
          serialize_yaml(alloca_inst);
1,805✔
292
        }
1,805✔
293
      }
1,933✔
294
    }
18,010!
295
  }
3,955✔
296
};
297

298
class LegacyTestPass : public ModulePass {
299
 private:
300
  TestPass pass_impl_;
301

302
 public:
303
  static char ID;  // NOLINT
UNCOV
304
  LegacyTestPass() : ModulePass(ID) {
×
UNCOV
305
  }
×
306

UNCOV
307
  bool runOnModule(Module& module) override {
×
UNCOV
308
    const auto modified = pass_impl_.runOnModule(module);
×
UNCOV
309
    return modified;
×
UNCOV
310
  }
×
311

UNCOV
312
  ~LegacyTestPass() override = default;
×
313
};
314

315
}  // namespace dimeta::test
316

317
#define DEBUG_TYPE "dimeta-test-pass"
318

319
//.....................
320
// New PM
321
//.....................
322
llvm::PassPluginLibraryInfo getDimetaTestPassPluginInfo() {
953✔
323
  return {LLVM_PLUGIN_API_VERSION, "Dimeta Test Pass", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) {
1,906✔
324
            pass_builder.registerPipelineParsingCallback(
1,906✔
325
                [](StringRef name, ModulePassManager& module_pm, ArrayRef<PassBuilder::PipelineElement>) {
2,859✔
326
                  if (name == "dimeta-test") {
1,906!
327
                    module_pm.addPass(dimeta::test::TestPass());
1,906✔
328
                    return true;
1,906✔
329
                  }
330
                  return false;
×
331
                });
1,906✔
332
          }};
953✔
333
}
334

335
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
953✔
336
  return getDimetaTestPassPluginInfo();
953✔
337
}
338

339
//.....................
340
// Old PM
341
//.....................
342
char dimeta::test::LegacyTestPass::ID = 0;  // NOLINT
343

344
static RegisterPass<dimeta::test::LegacyTestPass> x("dimeta-test", "Dimeta Data Type Test Pass");  // NOLINT
953✔
345

346
ModulePass* createTestPass() {
×
347
  return new dimeta::test::LegacyTestPass();
×
348
}
349

350
extern "C" void AddTestPass(LLVMPassManagerRef pass_manager) {
×
351
  unwrap(pass_manager)->add(createTestPass());
×
352
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc