• 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

65.89
/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*> type_of_store_to_call(const dataflow::ValuePath& path, const llvm::Function* called_f,
100✔
51
                                                   const llvm::CallBase* call_inst) {
52
  if (auto* leaf_value = path.start_value().value_or(nullptr); leaf_value != nullptr) {
200!
53
    LOG_DEBUG("Looking at start value of path: " << *leaf_value)
54
    // Here we look at if we store to a function that returns pointer/ref,
55
    // indicating return of call is the type we need:
56
    if (auto* store = llvm::dyn_cast<llvm::StoreInst>(leaf_value)) {
140✔
57
      // We have a final store and root w.r.t. call, hence, assume return type is the relevant root DIType:
58
      if (auto* sub_program = called_f->getSubprogram(); sub_program != nullptr) {
80!
59
        auto types_of_subprog = sub_program->getType()->getTypeArray();
40✔
60
        assert(types_of_subprog.size() > 0 && "Need the return type of the function");
80!
61
        auto* return_type = types_of_subprog[0];
40✔
62
        LOG_DEBUG("Found return type " << log::ditype_str(return_type))
63
        return return_type;
40✔
64
      }
40✔
65

66
      LOG_DEBUG("Function has no subProgram to query, trying di_local finder")
67
      auto di_local = difinder::find_local_variable(call_inst);
×
68
      if (di_local) {
×
69
        // TODO: for now we ignore local vars with name "this", as these are auto generated
70
        auto is_this_var = di_local.value()->getName() == "this";
×
71
        if (is_this_var) {
×
72
          LOG_DEBUG("'this' local variable as store target unsupported.")
73
          return {};
×
74
        }
75
        LOG_DEBUG("Found local variable " << log::ditype_str(di_local.value()))
76
        return di_local.value()->getType();
×
UNCOV
77
      }
×
78
    }
×
79
  }
60✔
80
  return {};
60✔
81
}
100✔
82

83
std::optional<llvm::DIType*> type_of_call_argument(const dataflow::ValuePath& path, const llvm::Function* called_f,
60✔
84
                                                   const llvm::CallBase* call_inst) {
85
  // Argument passed to current call:
86
  const auto* arg_val = path.previous_value().value_or(nullptr);
60✔
87
  assert(arg_val != nullptr && "Previous value should be argument to some function!");
120!
88
  // Argument number:
89
  const auto* const arg_pos =
120✔
90
      llvm::find_if(call_inst->args(), [&arg_val](const auto& arg_use) -> bool { return arg_use.get() == arg_val; });
200✔
91

92
  if (arg_pos == std::end(call_inst->args())) {
60!
93
    LOG_DEBUG("Could not find arg position for " << *arg_val)
94
    return {};
×
95
  }
96
  auto arg_num = std::distance(call_inst->arg_begin(), arg_pos);
60✔
97
  LOG_DEBUG("Looking at arg pos " << arg_num)
98
  // Extract debug info from function at arg_num:
99
  if (auto* sub_program = called_f->getSubprogram(); sub_program != nullptr) {
120!
100
    // DI-types of a subprog. include return type at pos 0, hence + 1:
101
    const auto sub_prog_arg_pos = arg_num + 1;
60✔
102
    auto types_of_subprog       = sub_program->getType()->getTypeArray();
60✔
103
    assert((types_of_subprog.size() > sub_prog_arg_pos) && "Type array smaller than arg num!");
120!
104
    auto* type = types_of_subprog[sub_prog_arg_pos];
60✔
105
    LOG_DEBUG("Found DIType at arg pos " << log::ditype_str(type))
106
    return type;
60✔
107
  }
60✔
108
  LOG_DEBUG("Did not find arg pos")
109
  return {};
×
110
}
60✔
111

112
}  // namespace helper
113

114
std::optional<llvm::DIType*> find_type_root(const dataflow::CallValuePath& call_path) {
1,174✔
115
  using namespace llvm;
116
  const auto* root_value = call_path.path.value().value_or(nullptr);
1,174✔
117
  if (!root_value) {
1,174!
118
    return {};
×
119
  }
120
  LOG_DEBUG("Root value is " << *root_value)
121

122
  if (const auto* ret = dyn_cast<ReturnInst>(root_value)) {
1,268✔
123
    auto* sub_prog = ret->getFunction()->getSubprogram();
94✔
124
    if (!sub_prog) {
94✔
125
      return {};
4✔
126
    }
127
    auto type_array = sub_prog->getType()->getTypeArray();
90✔
128
    if (type_array.size() > 0) {
90!
129
      return {type_array[0]};
90✔
130
    }
131
    return {};
×
132
  }
94✔
133

134
  if (const auto* alloca = dyn_cast<AllocaInst>(root_value)) {
1,574✔
135
    auto local_di_var = difinder::find_local_variable(alloca);
494✔
136
    if (local_di_var) {
494!
137
      return local_di_var.value()->getType();
494✔
138
    }
139

140
    // see test heap_case_inheritance.cpp (e.g., returns several objects as base class pointer):
141
    // TODO: check if that ever applies to C, should probably only execute for C++ codes.
142
    LOG_DEBUG("Dataflow analysis of alloca")
143
    auto paths_from_alloca = dataflow::path_from_alloca(alloca);
×
144
    for (auto& path : paths_from_alloca) {
×
145
      LOG_DEBUG("Path from alloca " << path)
146
      auto type_of_alloca = find_type_root(dataflow::CallValuePath{std::nullopt, path});
×
147
      if (type_of_alloca) {
×
148
        return type_of_alloca;
×
149
      }
150
    }
×
151

152
    return {};
×
153
  }
494✔
154

155
  if (const auto* call_inst = llvm::dyn_cast<CallBase>(root_value)) {
702✔
156
    LOG_DEBUG("Root is a call")
157
    const auto* called_f = call_inst->getCalledFunction();
116✔
158
    if (called_f == nullptr) {
116!
159
      LOG_DEBUG("Called function not found for call base " << *call_inst)
160
      return {};
×
161
    }
162

163
    dimeta::memory::MemOps ops;
116✔
164
    if (ops.allocKind(called_f->getName())) {
116✔
165
      // see test c/heap_tachyon_mock_images.c
166
      LOG_DEBUG("Root is malloc-like call")
167
      // TODO ask for type of newlike call here!
168
      if (call_path.call && (call_inst == call_path.call.value())) {
16!
169
        // Test triggers by cpp/heap_lhs_function_opt_nofwd.cpp and ir/01_endless_recursion.ll
170
        LOG_WARNING("Root value is the same as the initial malloc-like call")
6✔
171
        return {};
6✔
172
      }
173
      auto extracted_type = type_for(call_inst);
10✔
174
      if (!extracted_type) {
10!
175
        LOG_DEBUG("Failed to collect DI data for " << called_f->getName())
176
        return {};
×
177
      }
178

179
      return extracted_type->entry_type;
10✔
180
    }
10✔
181

182
    const auto& path         = call_path.path;
100✔
183
    auto store_function_type = helper::type_of_store_to_call(path, called_f, call_inst);
100✔
184
    if (store_function_type) {
100✔
185
      return store_function_type;
40✔
186
    }
187

188
    auto type_of_call_arg = helper::type_of_call_argument(path, called_f, call_inst);
60✔
189
    if (!type_of_call_arg) {
60!
190
      LOG_DEBUG("Did not find arg pos")
191
      return {};
×
192
    }
193
    return type_of_call_arg;
60✔
194
  }
116✔
195

196
  if (const auto* global_variable = llvm::dyn_cast<llvm::GlobalVariable>(root_value)) {
600✔
197
    auto dbg_md = global_variable->getMetadata("dbg");
130✔
198
    if (!dbg_md) {
130!
199
      return {};
×
200
    }
201
    if (auto* global_expression = llvm::dyn_cast<llvm::DIGlobalVariableExpression>(dbg_md)) {
260!
202
      return global_expression->getVariable()->getType();
130✔
203
    }
204
    return {};
×
205
  }
130✔
206

207
  if (const auto* argument = llvm::dyn_cast<llvm::Argument>(root_value)) {
680!
208
    if (auto* subprogram = argument->getParent()->getSubprogram(); subprogram != nullptr) {
680!
209
      const auto type_array = subprogram->getType()->getTypeArray();
340✔
210
      const auto arg_pos    = [&](const auto arg_num) {
1,020✔
211
        if (argument->hasStructRetAttr()) {
340✔
212
          // return value is passed as argument at this point
213
          return arg_num;  // see test cpp/heap_lhs_function_opt_nofwd.cpp
4✔
214
        }
215
        return arg_num + 1;
336✔
216
      }(argument->getArgNo());
680✔
217

218
      LOG_DEBUG(log::ditype_str(subprogram) << " -> " << *argument)
219
      LOG_DEBUG("Arg data: " << argument->getArgNo() << " Type num operands: " << type_array->getNumOperands())
220
      assert(arg_pos < type_array.size() && "Arg position greater than DI type array of subprogram!");
680!
221
      return type_array[arg_pos];
340✔
222
    }
340✔
223

224
    return {};
×
225
  }
226

227
  if (const auto* const_expr = llvm::dyn_cast<llvm::ConstantExpr>(root_value)) {
×
228
    LOG_DEBUG("ConstantExpr unsupported");
UNCOV
229
  }
×
230

231
  LOG_DEBUG("No matching value found for " << *root_value);
232
  return {};
×
233
}
1,174✔
234

235
}  // 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