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

ahueck / llvm-dimeta / 15703160060

17 Jun 2025 09:13AM UTC coverage: 82.212% (-1.1%) from 83.355%
15703160060

Pull #45

github

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

1226 of 1777 branches covered (68.99%)

Branch coverage included in aggregate %.

197 of 203 new or added lines in 6 files covered. (97.04%)

48 existing lines in 5 files now uncovered.

2208 of 2400 relevant lines covered (92.0%)

7493.4 hits per line

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

62.04
/lib/type/DIRootType.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 "DIRootType.h"
9

10
#include "DIFinder.h"
11
#include "DataflowAnalysis.h"
12
#include "DefUseAnalysis.h"
13
#include "Dimeta.h"
14
#include "MemoryOps.h"
15
#include "Util.h"
16
#include "ValuePath.h"
17
#include "support/Logger.h"
18

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

42
#include <cassert>
43
#include <iterator>
44
#include <optional>
45

46
namespace dimeta::root {
47

48
namespace helper {
49

50
std::optional<llvm::DIType*> get_return_type_of(const llvm::Function* called_function,
81✔
51
                                                const llvm::CallBase* call_instruction) {
52
  if (auto* sub_program = called_function->getSubprogram(); sub_program != nullptr) {
162!
53
    auto types_of_subprog = sub_program->getType()->getTypeArray();
81✔
54
    assert(types_of_subprog.size() > 0 && "Need the return type of the function");
162!
55
    auto* return_type = types_of_subprog[0];
81✔
56
    LOG_DEBUG("Found return type " << log::ditype_str(return_type))
57
    return return_type;
81✔
58
  }
81✔
59
  LOG_DEBUG("Function has no subProgram to query, trying di_local finder")
60
  auto di_local = difinder::find_local_variable(call_instruction);
×
61
  if (di_local) {
×
62
    // TODO: for now we ignore local vars with name "this", as these are auto generated
63
    auto is_this_var = di_local.value()->getName() == "this";
×
64
    if (is_this_var) {
×
65
      LOG_DEBUG("'this' local variable as store target unsupported.")
66
      return {};
×
67
    }
68
    LOG_DEBUG("Found local variable " << log::ditype_str(di_local.value()))
69
    return di_local.value()->getType();
×
70
  }
×
71
  return {};
×
72
}
81✔
73

74
std::optional<llvm::DIType*> type_of_store_to_call(const dataflow::ValuePath& path, const llvm::Function* called_f,
189✔
75
                                                   const llvm::CallBase* call_inst) {
76
  if (auto* leaf_value = path.start_value().value_or(nullptr); leaf_value != nullptr) {
378!
77
    LOG_DEBUG("Looking at start value of path: " << *leaf_value)
78
    // Here we look at if we store to a function that returns pointer/ref,
79
    // indicating return of call is the type we need:
80
    if (auto* store = llvm::dyn_cast<llvm::StoreInst>(leaf_value)) {
261✔
81
      // We have a final store and root w.r.t. call, hence, assume return type is the relevant root DIType:
82
      return get_return_type_of(called_f, call_inst);
72✔
83
    }
84
  }
117✔
85
  return {};
117✔
86
}
189✔
87

88
std::optional<llvm::DIType*> type_of_call_argument(const dataflow::ValuePath& path, const llvm::Function* called_f,
108✔
89
                                                   const llvm::CallBase* call_inst) {
90
  // Argument passed to current call:
91
  const auto* arg_val = path.previous_value().value_or(nullptr);
108✔
92

93
  // if (arg_val == nullptr) {
94
  //   LOG_DEBUG("Previous value should be argument to some function!")
95
  //   return {};
96
  // }
97

98
  assert(arg_val != nullptr && "Previous value should be argument to some function!");
216!
99
  // Argument number:
100
  const auto* const arg_pos =
216✔
101
      llvm::find_if(call_inst->args(), [&arg_val](const auto& arg_use) -> bool { return arg_use.get() == arg_val; });
360✔
102

103
  if (arg_pos == std::end(call_inst->args())) {
108!
104
    LOG_DEBUG("Could not find arg position for " << *arg_val)
105
    return {};
×
106
  }
107

108
  auto arg_num = std::distance(call_inst->arg_begin(), arg_pos);
108✔
109
  LOG_DEBUG("Looking at arg pos " << arg_num)
110
  // Extract debug info from function at arg_num:
111
  if (auto* sub_program = called_f->getSubprogram(); sub_program != nullptr) {
216!
112
    // DI-types of a subprog. include return type at pos 0, hence + 1:
113
    const auto sub_prog_arg_pos = arg_num + 1;
108✔
114
    auto types_of_subprog       = sub_program->getType()->getTypeArray();
108✔
115
    assert((types_of_subprog.size() > sub_prog_arg_pos) && "Type array smaller than arg num!");
216!
116
    auto* type = types_of_subprog[sub_prog_arg_pos];
108✔
117
    LOG_DEBUG("Found DIType at arg pos " << log::ditype_str(type))
118
    return type;
108✔
119
  }
108✔
120
  LOG_DEBUG("Did not find arg pos")
121
  return {};
×
122
}
108✔
123

124
std::optional<llvm::DIType*> type_of_argument(const llvm::Argument& argument) {
692✔
125
  if (auto* subprogram = argument.getParent()->getSubprogram(); subprogram != nullptr) {
1,384!
126
    const auto type_array = subprogram->getType()->getTypeArray();
692✔
127
    const auto arg_pos    = [&](const auto arg_num) {
2,076✔
128
      if (argument.hasStructRetAttr()) {
692✔
129
        // return value is passed as argument at this point
130
        return arg_num;  // see test cpp/heap_lhs_function_opt_nofwd.cpp
8✔
131
      }
132
      return arg_num + 1;
684✔
133
    }(argument.getArgNo());
1,384✔
134

135
    LOG_DEBUG(log::ditype_str(subprogram) << " -> " << argument)
136
    LOG_DEBUG("Arg data: " << argument.getArgNo() << " Type num operands: " << type_array->getNumOperands())
137
    assert(arg_pos < type_array.size() && "Arg position greater than DI type array of subprogram!");
1,384!
138
    return type_array[arg_pos];
692✔
139
  }
692✔
140

141
  return {};
×
142
}
692✔
143

144
}  // namespace helper
145

146
std::optional<llvm::DIType*> find_type_root(const dataflow::CallValuePath& call_path) {
2,580✔
147
  using namespace llvm;
148
  const auto* root_value = call_path.path.value().value_or(nullptr);
2,580✔
149
  if (!root_value) {
2,580!
150
    return {};
×
151
  }
152
  LOG_DEBUG("Root value is " << *root_value)
153

154
  if (const auto* ret = dyn_cast<ReturnInst>(root_value)) {
2,708✔
155
    auto* sub_prog = ret->getFunction()->getSubprogram();
128✔
156
    if (!sub_prog) {
128✔
157
      return {};
8✔
158
    }
159
    auto type_array = sub_prog->getType()->getTypeArray();
120✔
160
    if (type_array.size() > 0) {
120!
161
      return {type_array[0]};
120✔
162
    }
163
    return {};
×
164
  }
128✔
165

166
  if (const auto* alloca = dyn_cast<AllocaInst>(root_value)) {
3,685✔
167
    auto local_di_var = difinder::find_local_variable(alloca);
1,233✔
168
    if (local_di_var) {
1,233!
169
      return local_di_var.value()->getType();
1,233✔
170
    }
171

UNCOV
172
    for (auto user : alloca->users()) {
×
UNCOV
173
      if (auto store = llvm::dyn_cast<llvm::StoreInst>(user)) {
×
UNCOV
174
        if (const auto* argument = llvm::dyn_cast<llvm::Argument>(store->getValueOperand())) {
×
UNCOV
175
          return helper::type_of_argument(*argument);
×
176
        }
177
      }
×
UNCOV
178
    }
×
179

180
    // see test heap_case_inheritance.cpp (e.g., returns several objects as base class pointer):
181
    // TODO: check if that ever applies to C, should probably only execute for C++ codes.
182
    LOG_DEBUG("Dataflow analysis of alloca")
183
    auto paths_from_alloca = dataflow::path_from_alloca(alloca);
×
184
    for (auto& path : paths_from_alloca) {
×
185
      LOG_DEBUG("Path from alloca " << path)
186
      auto type_of_alloca = find_type_root(dataflow::CallValuePath{std::nullopt, path});
×
187
      if (type_of_alloca) {
×
188
        return type_of_alloca;
×
189
      }
190
    }
×
191

192
    return {};
×
193
  }
1,233✔
194

195
  if (const auto* call_inst = llvm::dyn_cast<CallBase>(root_value)) {
1,440✔
196
    LOG_DEBUG("Root is a call")
197
    const auto* called_f = call_inst->getCalledFunction();
221✔
198
    if (called_f == nullptr) {
221!
199
      LOG_DEBUG("Called function not found for call base " << *call_inst)
200
      return {};
×
201
    }
202

203
    dimeta::memory::MemOps ops;
221✔
204
    if (ops.allocKind(called_f->getName())) {
221✔
205
      // see test c/heap_tachyon_mock_images.c
206
      LOG_DEBUG("Root is malloc-like call")
207
      // TODO ask for type of newlike call here!
208
      if (call_path.call && (call_inst == call_path.call.value())) {
32!
209
        // Test triggers by cpp/heap_lhs_function_opt_nofwd.cpp and ir/01_endless_recursion.ll
210
        LOG_WARNING("Root value is the same as the initial malloc-like call")
14✔
211
        return {};
14✔
212
      }
213
      auto extracted_type = type_for(call_inst);
18✔
214
      if (!extracted_type) {
18!
215
        LOG_DEBUG("Failed to collect DI data for " << called_f->getName())
216
        return {};
×
217
      }
218

219
      return extracted_type->entry_type;
18✔
220
    }
18✔
221

222
    const auto& path = call_path.path;
189✔
223

224
    // "a = malloc;", "store a, get_pointer();" -> look at return type of get_pointer()
225
    auto store_function_type = helper::type_of_store_to_call(path, called_f, call_inst);
189✔
226
    if (store_function_type) {
189✔
227
      return store_function_type;
72✔
228
    }
229

230
    if (path.previous_value()) {
117✔
231
      // foo(malloc(...)); -> look at foo args
232
      auto type_of_call_arg = helper::type_of_call_argument(path, called_f, call_inst);
108✔
233
      if (!type_of_call_arg) {
108!
234
        LOG_DEBUG("Did not find arg pos")
235
        return {};
×
236
      }
237
      return type_of_call_arg;
108✔
238
    }
108✔
239

240
    LOG_DEBUG("Trying return type of function " << *called_f)
241
    return helper::get_return_type_of(called_f, call_inst);
9✔
242
  }
221✔
243

244
  if (const auto* global_variable = llvm::dyn_cast<llvm::GlobalVariable>(root_value)) {
1,304✔
245
    auto dbg_md = global_variable->getMetadata("dbg");
306✔
246
    if (!dbg_md) {
306!
247
      return {};
×
248
    }
249
    if (auto* global_expression = llvm::dyn_cast<llvm::DIGlobalVariableExpression>(dbg_md)) {
612!
250
      return global_expression->getVariable()->getType();
306✔
251
    }
252
    return {};
×
253
  }
306✔
254

255
  if (const auto* argument = llvm::dyn_cast<llvm::Argument>(root_value)) {
1,384!
256
    return helper::type_of_argument(*argument);
692✔
257
  }
258

259
  if (const auto* const_expr = llvm::dyn_cast<llvm::ConstantExpr>(root_value)) {
×
260
    LOG_DEBUG("ConstantExpr unsupported");
261
  }
×
262

263
  LOG_DEBUG("No matching value found for " << *root_value);
264
  return {};
×
265
}
2,580✔
266

267
}  // namespace dimeta::root
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