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

ahueck / llvm-dimeta / 17204706958

25 Aug 2025 09:20AM UTC coverage: 72.695% (-10.7%) from 83.355%
17204706958

Pull #45

github

web-flow
Merge 047c32aa1 into c60847ea6
Pull Request #45: Disable TBAA for all cases

1700 of 2971 branches covered (57.22%)

Branch coverage included in aggregate %.

205 of 211 new or added lines in 7 files covered. (97.16%)

57 existing lines in 7 files now uncovered.

2219 of 2420 relevant lines covered (91.69%)

7453.49 hits per line

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

73.48
/lib/type/Dimeta.cpp
1
//  llvm-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 "Dimeta.h"
9

10
#include "DIFinder.h"
11
#include "DIRootType.h"
12
#include "DITypeExtractor.h"
13
#include "DataflowAnalysis.h"
14
#include "DefUseAnalysis.h"
15
#include "DimetaData.h"
16
#include "DimetaParse.h"
17
#include "MemoryOps.h"
18
#include "Util.h"
19
#include "ValuePath.h"
20
#include "support/Logger.h"
21

22
#include "llvm/ADT/ArrayRef.h"
23
#include "llvm/ADT/STLExtras.h"
24
#include "llvm/ADT/SmallVector.h"
25
#include "llvm/ADT/ilist_iterator.h"
26
#include "llvm/BinaryFormat/Dwarf.h"
27
#include "llvm/Config/llvm-config.h"
28
#include "llvm/IR/Argument.h"
29
#include "llvm/IR/Constants.h"
30
#include "llvm/IR/DebugInfoMetadata.h"
31
#include "llvm/IR/Function.h"
32
#include "llvm/IR/GlobalVariable.h"
33
#include "llvm/IR/InstIterator.h"
34
#include "llvm/IR/InstrTypes.h"
35
#include "llvm/IR/Instructions.h"
36
#include "llvm/IR/IntrinsicInst.h"
37
#include "llvm/IR/Metadata.h"
38
#include "llvm/IR/Operator.h"
39
#include "llvm/IR/Value.h"
40
#include "llvm/Support/Casting.h"
41
#include "llvm/Support/Debug.h"
42
#include "llvm/Support/ErrorHandling.h"
43
#include "llvm/Support/raw_ostream.h"
44

45
#include <cassert>
46
#include <iterator>
47
#include <string>
48

49
namespace llvm {
50
class DbgVariableIntrinsic;
51
}  // namespace llvm
52

53
#if LLVM_VERSION_MAJOR == 10
54
// For FindDbgAddrUses:
55
#include "llvm/Transforms/Utils/Local.h"
56
#endif
57

58
namespace dimeta {
59

60
namespace experimental {
61
std::optional<llvm::DIType*> di_type_for(const llvm::Value* value);
62
}
63

64
llvm::SmallVector<llvm::DIType*, 4> collect_types(const llvm::CallBase* call,
2,602✔
65
                                                  llvm::ArrayRef<dataflow::ValuePath> paths_to_type) {
66
  using namespace llvm;
67
  SmallVector<llvm::DIType*, 4> di_types;
2,602✔
68
  llvm::transform(paths_to_type, dimeta::util::optional_back_inserter(di_types), [&](const auto& path) {
5,204!
69
    return type::find_type(dataflow::CallValuePath{call, path});
2,602!
UNCOV
70
  });
×
71
  return di_types;
2,602✔
72
}
2,602!
73

74
auto final_ditype(std::optional<llvm::DIType*> root_ditype) -> std::pair<std::optional<llvm::DIType*>, int> {
11,184✔
75
  if (!root_ditype) {
11,184✔
76
    return {{}, 0};
26✔
77
  }
78
  int level{0};
11,158✔
79
  llvm::DIType* type = *root_ditype;
11,158✔
80
  while (llvm::isa<llvm::DIDerivedType>(type)) {
21,416✔
81
    auto ditype = llvm::dyn_cast<llvm::DIDerivedType>(type);
10,382✔
82
    if (ditype->getTag() == llvm::dwarf::DW_TAG_pointer_type) {
10,382✔
83
      ++level;
6,698✔
84
    }
6,698✔
85
    // void*-based derived types have basetype=null:
86
    if (ditype->getBaseType() == nullptr) {
10,382✔
87
      return {type, level};
124✔
88
    }
89
    type = ditype->getBaseType();
10,258✔
90
  }
10,382✔
91

92
  return {type, level};
11,034✔
93
}
11,184✔
94

95
std::optional<llvm::DIType*> type_for_malloclike(const llvm::CallBase* call) {
2,486✔
96
  auto local = difinder::get_array_access_assignment(call);
2,486✔
97
  if (local) {
2,486✔
98
    LOG_DEBUG("Call has local variable " << *call)
99
    // LOG_DEBUG("Call type " << log::ditype_str(local.value()->getType()))
100
    auto base_type = local.value().var->getType();
152✔
101
    if (local.value().array_access) {
152✔
102
      if (auto* array_type = llvm::dyn_cast<llvm::DICompositeType>(base_type)) {
168!
103
        LOG_DEBUG("Returning type of access to array " << log::ditype_str(array_type))
104
        return array_type->getBaseType();
84✔
105
      }
106
    }
×
107
    return base_type;
68✔
108
  }
152✔
109

110
  const auto ditype_paths = dataflow::type_for_heap_call(call);
2,334✔
111

112
  LOG_DEBUG("Found paths, now collecting types")
113
  const auto ditypes_vector = collect_types(call, ditype_paths);
2,334!
114
  if (ditypes_vector.empty()) {
2,334!
115
    return {};
26✔
116
  }
117
  return *ditypes_vector.begin();
2,308!
118
}
2,486✔
119

120
std::optional<llvm::DIType*> type_for_newlike(const llvm::CallBase* call) {
712✔
121
  auto* heapalloc_md = call->getMetadata("heapallocsite");
712✔
122
  assert(heapalloc_md != nullptr && "Missing required heapallocsite metadata.");
1,424!
123
  if (auto* type = llvm::dyn_cast<llvm::DIType>(heapalloc_md)) {
1,424!
124
    //    util::DIPrinter printer(llvm::outs(), call->getParent()->getParent()->getParent());
125
    //    printer.traverseType(type);
126
    //    llvm::dbgs() << "Final Type: " << *type << "\n";
127
    return type;
712✔
128
  }
129
  return {};
×
130
}
712✔
131

132
std::optional<DimetaData> type_for(const llvm::CallBase* call) {
18,522✔
133
  using namespace llvm;
134
  const dimeta::memory::MemOps mem_ops;
18,522✔
135

136
  auto* cb_fun = call->getCalledFunction();
18,522!
137
  if (!cb_fun) {
18,522!
138
    return {};
8✔
139
  }
140

141
  if (!mem_ops.isAlloc(cb_fun->getName())) {
18,514!
142
    LOG_TRACE("Skipping call base: " << cb_fun->getName());
143
    return {};
15,174✔
144
  }
145

146
  std::optional<llvm::DIType*> extracted_type{};
3,340✔
147
  int pointer_level_offset{0};
3,340✔
148

149
  const auto is_cuda_like = mem_ops.isCudaLike(cb_fun->getName());
3,340!
150
  if (is_cuda_like) {
3,340✔
151
    LOG_DEBUG("Type for cuda-like " << cb_fun->getName())
152
    extracted_type = experimental::di_type_for(call->getOperand(0));
142!
153

154
    // when wrapped in, e.g., cudaMalloc<float>(float**, ...), we remove one pointer level:
155
    // auto* parent    = call->getFunction();
156
    // const auto name = std::string{cb_fun->getName()} + "<";
157
    // LOG_DEBUG(name << " vs. " << util::try_demangle(*makeparent))
158
    // if (extracted_type && util::try_demangle(*parent).find(name) != std::string::npos) {
159
    //   LOG_DEBUG("Reset cuda-like pointer level")
160
    //   auto ditype = llvm::dyn_cast<llvm::DIDerivedType>(extracted_type.value());
161
    //   if (ditype->getTag() == llvm::dwarf::DW_TAG_pointer_type) {
162
    //     extracted_type = ditype->getBaseType();
163
    //   }
164
    // }
165
  }
142✔
166

167
  const auto is_cxx_new = mem_ops.isNewLike(cb_fun->getName());
3,340!
168

169
#ifdef DIMETA_USE_HEAPALLOCSITE
170
  if (is_cxx_new) {
3,340✔
171
    if (call->getMetadata("heapallocsite")) {
750!
172
      LOG_TRACE("Type for new-like " << cb_fun->getName())
173
      extracted_type = type_for_newlike(call);
712!
174
      // !heapallocsite gives the type after "new", i.e., new int -> int, new int*[n] -> int*.
175
      // Our malloc-related algorithm would return int* and int** respectively, however, hence:
176
      pointer_level_offset += 1;
712✔
177
    } else {
712✔
178
      LOG_DEBUG("new-like allocation does not have heapallocsite metadata.")
179
    }
180
  }
750✔
181
#endif
182

183
  if (!extracted_type) {
3,340✔
184
    LOG_DEBUG("Type for malloc-like: " << cb_fun->getName())
185
    extracted_type = type_for_malloclike(call);
2,486!
186
  }
2,486✔
187
  auto source_loc                        = difinder::find_location(call);
3,340!
188
  const auto [final_type, pointer_level] = final_ditype(extracted_type);
3,340!
189
  const auto meta = DimetaData{DimetaData::MemLoc::kHeap,           {}, extracted_type, final_type, source_loc,
10,020✔
190
                               pointer_level + pointer_level_offset};
3,340✔
191
  return meta;
3,340✔
192
}
18,522✔
193

194
std::optional<DimetaData> type_for(const llvm::AllocaInst* ai) {
7,445✔
195
  const auto local_di_var = difinder::find_local_variable(ai);
7,445✔
196

197
  if (local_di_var) {
7,445✔
198
    auto extracted_type                    = local_di_var.value()->getType();
7,210✔
199
    auto source_loc                        = difinder::find_location(ai);
7,210✔
200
    const auto [final_type, pointer_level] = final_ditype(extracted_type);
21,630✔
201
    const auto meta =
7,210✔
202
        DimetaData{DimetaData::MemLoc::kStack, local_di_var, extracted_type, final_type, source_loc, pointer_level};
21,630✔
203
    return meta;
7,210✔
204
  }
7,210✔
205

206
  LOG_DEBUG("No local_variable for " << *ai)
207

208
  return {};
235✔
209
}
7,445✔
210

211
std::optional<DimetaData> type_for(const llvm::GlobalVariable* gv) {
1,019✔
212
  llvm::SmallVector<llvm::DIGlobalVariableExpression*, 2> dbg_info;
1,019✔
213
  gv->getDebugInfo(dbg_info);
1,019!
214
  if (!dbg_info.empty()) {
1,019!
215
    auto gv_expr                           = *dbg_info.begin();
634!
216
    auto gv_type                           = gv_expr->getVariable()->getType();
634!
217
    const auto [final_type, pointer_level] = final_ditype(gv_type);
634!
218
    return DimetaData{DimetaData::MemLoc::kGlobal, gv_expr->getVariable(), gv_type, final_type, {}, pointer_level};
634!
219
  }
634✔
220
  return {};
385✔
221
}
1,019✔
222

223
std::optional<CompileUnitTypeList> compile_unit_types(const llvm::Module* module) {
2,016✔
224
  CompileUnitTypeList list;
2,016✔
225
  for (auto* compile_unit : module->debug_compile_units()) {
4,019!
226
    CompileUnitTypes current_cu;
2,003✔
227
    current_cu.name = compile_unit->getFilename();
2,003!
228
    for (auto* retained_type : compile_unit->getRetainedTypes()) {
3,302!
229
      if (auto* type = llvm::dyn_cast<llvm::DIType>(retained_type)) {
2,598!
230
        auto dimeta_result = parser::make_dimetadata(type);
1,299!
231
        if (!dimeta_result) {
1,299!
232
          continue;
×
233
        }
234
        current_cu.types.push_back(dimeta_result->type_);
1,299!
235
      }
1,299!
236
    }
1,299!
237
    list.push_back(current_cu);
2,003!
238
  }
2,003✔
239
  return (list.empty() ? std::optional<CompileUnitTypeList>{} : list);
2,016!
240
}
2,016✔
241

242
namespace experimental {
243
std::optional<llvm::DIType*> di_type_for(const llvm::Value* value) {
142✔
244
  auto paths                = dataflow::experimental::path_from_value(value);
142✔
245
  const auto ditypes_vector = collect_types(nullptr, paths);
142!
246
  if (ditypes_vector.empty()) {
142!
247
    return {};
×
248
  }
249

250
  return *ditypes_vector.begin();
142!
251
}
142✔
252

253
std::optional<QualifiedType> type_for(const llvm::Value* value) {
126✔
254
  auto paths                = dataflow::experimental::path_from_value(value);
126✔
255
  const auto ditypes_vector = collect_types(nullptr, paths);
126!
256
  if (ditypes_vector.empty()) {
126!
257
    return {};
×
258
  }
259

260
  for (const auto& type : ditypes_vector) {
252!
261
    auto dimeta_result = parser::make_dimetadata(type);
126!
262
    if (!dimeta_result) {
126!
263
      continue;
×
264
    }
265
    return dimeta_result->type_;
126!
266
  }
126!
267

268
  return {};
×
269
}
126✔
270

271
}  // namespace experimental
272

273
}  // namespace dimeta
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