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

tudasc / TypeART / 24399715246

14 Apr 2026 12:46PM UTC coverage: 90.246% (+1.3%) from 88.924%
24399715246

push

github

web-flow
Merge PR #187 from tudasc/devel

880 of 935 new or added lines in 31 files covered. (94.12%)

18 existing lines in 4 files now uncovered.

4885 of 5413 relevant lines covered (90.25%)

38924.81 hits per line

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

94.12
/lib/passes/instrumentation/TypeARTFunctions.cpp
1
// TypeART library
2

3
//
4
// Copyright (c) 2017-2026 TypeART Authors
5
// Distributed under the BSD 3-Clause license.
6
// (See accompanying file LICENSE.txt or copy at
7
// https://opensource.org/licenses/BSD-3-Clause)
8
//
9
// Project home: https://github.com/tudasc/TypeART
10
//
11
// SPDX-License-Identifier: BSD-3-Clause
12
//
13

14
#include "TypeARTFunctions.h"
15

16
#include "configuration/Configuration.h"
17
#include "instrumentation/TypeIDProvider.h"
18
#include "support/ConfigurationBase.h"
19
#include "support/Logger.h"
20
#include "support/OmpUtil.h"
21

22
#include "llvm/ADT/ArrayRef.h"
23
#include "llvm/ADT/StringMap.h"
24
#include "llvm/ADT/StringRef.h"
25
#include "llvm/IR/Argument.h"
26
#include "llvm/IR/Attributes.h"
27
#include "llvm/IR/DerivedTypes.h"
28
#include "llvm/IR/Function.h"
29
#include "llvm/IR/GlobalValue.h"
30
#include "llvm/IR/Module.h"
31
#include "llvm/IR/Type.h"
32
#include "llvm/Support/Casting.h"
33
#include "llvm/Support/raw_ostream.h"
34

35
#include <memory>
36
#include <optional>
37
#include <string>
38
#include <unordered_map>
39
#include <utility>
40

41
namespace typeart {
42
class InstrumentationHelper;
43
}  // namespace typeart
44

45
using namespace llvm;
46

47
namespace typeart {
48

49
namespace detail {
50
std::string get_func_suffix(IFunc id) {
85,950✔
51
  switch (id) {
85,950✔
52
    // case IFunc::free_cuda:
53
    // case IFunc::heap_cuda:
54
    //   return "_cuda";
55
    case IFunc::free_omp:
56
    case IFunc::heap_omp:
57
    case IFunc::stack_omp:
58
    case IFunc::scope_omp:
59
      return "_omp";
34,380✔
60
    default:
61
      return "";
51,570✔
62
  }
63
}
85,950✔
64

65
enum class IFuncType : unsigned { standard, omp, cuda };
66

67
IFuncType ifunc_type_for(llvm::Function* f) {
26,879✔
68
  if (f == nullptr) {
26,879✔
69
    return IFuncType::standard;
6,565✔
70
  }
71

72
  if (util::omp::isOmpContext(f)) {
20,314✔
73
    return IFuncType::omp;
316✔
74
  }
75

76
  return IFuncType::standard;
19,998✔
77
}
26,879✔
78

79
}  // namespace detail
80

81
IFunc ifunc_for_function(IFunc general_type, llvm::Value* value) {
26,879✔
82
  detail::IFuncType type = typeart::detail::IFuncType::standard;
26,879✔
83

84
  if (auto function = llvm::dyn_cast<Function>(value)) {
26,879✔
NEW
85
    type = detail::ifunc_type_for(function);
×
86
  } else if (auto alloca = llvm::dyn_cast<AllocaInst>(value)) {
26,879✔
87
    type = detail::ifunc_type_for(alloca->getFunction());
14,365✔
88
  } else if (llvm::isa<GlobalVariable>(value)) {
26,879✔
89
    type = detail::ifunc_type_for(nullptr);
6,565✔
90
  } else if (auto callbase = llvm::dyn_cast<CallBase>(value)) {
12,514✔
91
    type = detail::ifunc_type_for(callbase->getFunction());
5,949✔
92
    // auto maybe_cuda = detail::ifunc_type_for(callbase->getCalledFunction());
93
    // if (maybe_cuda == detail::IFuncType::cuda) {
94
    //   type = detail::IFuncType::cuda;
95
    // }
96
  }
5,949✔
97

98
  if (detail::IFuncType::standard == type) {
26,879✔
99
    return general_type;
26,563✔
100
  }
101

102
  // if (detail::IFuncType::cuda == type) {
103
  //   switch (general_type) {
104
  //     case IFunc::heap:
105
  //       return IFunc::heap_cuda;
106
  //     case IFunc::free:
107
  //       return IFunc::free_cuda;
108
  //     default:
109
  //       return general_type;
110
  //       //        llvm_unreachable("IFunc not supported for CUDA.");
111
  //   }
112
  // }
113

114
  switch (general_type) {
316✔
115
    case IFunc::stack:
116
      return IFunc::stack_omp;
220✔
117
    case IFunc::heap:
118
      return IFunc::heap_omp;
52✔
119
    case IFunc::free:
120
      return IFunc::free_omp;
44✔
121
    case IFunc::scope:
NEW
122
      return IFunc::scope_omp;
×
123
    default:
NEW
124
      llvm_unreachable("IFunc type is not supported for OpenMP.");
×
125
  }
126
}
26,879✔
127

128
class TAFunctions final : public TAFunctionQuery {
129
  // densemap has problems with IFunc
130
  using FMap = std::unordered_map<IFunc, llvm::Function*>;
131
  FMap typeart_callbacks;
132

133
 public:
134
  llvm::Function* getFunctionFor(
135
      IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const override;
136
  void putFunctionFor(IFunc id, llvm::Function* f);
137
  // void putAlternativeFunctionFor(IFunc id, llvm::Function* f);
138
};
139

140
class TAFunctionDeclarator {
141
  llvm::Module& module;
142
  //  [[maybe_unused]] InstrumentationHelper& instr;
143
  TAFunctions& typeart_functions;
144
  llvm::StringMap<llvm::Function*> function_map;
145

146
 public:
147
  TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func);
148
  llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef<llvm::Type*> args,
149
                                bool alternative = false);
150
  const llvm::StringMap<llvm::Function*>& getFunctionMap() const;
151
  virtual ~TAFunctionDeclarator() = default;
11,460✔
152
};
153

154
TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, TAFunctions& typeart_funcs)
22,920✔
155
    : module(mod), typeart_functions(typeart_funcs) {
11,460✔
156
}
11,460✔
157

158
llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename,
85,950✔
159
                                                    llvm::ArrayRef<llvm::Type*> args, bool alternative) {
160
  const auto make_fname = [&func_id](llvm::StringRef name, llvm::ArrayRef<llvm::Type*> callback_arguments) {
171,900✔
161
    std::string fname;
85,950✔
162
    llvm::raw_string_ostream os(fname);
85,950✔
163
    os << name;
85,950✔
164
    os << detail::get_func_suffix(func_id);
85,950✔
165

166
    // if (!fixed_name) {
167
    //   os << "_" << std::to_string(callback_arguments.size());
168
    // }
169
    // if (with_omp_postfix) {
170
    //   os << "_"
171
    //      << "omp";
172
    // }
173
    return os.str();
85,950✔
174
  };
85,950✔
175

176
  const auto name = make_fname(basename, args);
85,950✔
177

178
  if (auto it = function_map.find(name); it != function_map.end()) {
85,950✔
179
    return it->second;
×
180
  }
181

182
  auto& c                           = module.getContext();
85,950✔
183
  const auto addOptimizerAttributes = [&](llvm::Function* function) {
85,950✔
184
    function->setDoesNotThrow();
85,950✔
185
    function->setDoesNotFreeMemory();
85,950✔
186
    function->setDoesNotRecurse();
85,950✔
187
#if LLVM_VERSION_MAJOR >= 12
188
    function->setWillReturn();
85,950✔
189
#endif
190
    for (Argument& arg : function->args()) {
286,500✔
191
      if (arg.getType()->isPointerTy()) {
200,550✔
192
#if LLVM_VERSION_MAJOR < 20
193
        arg.addAttr(Attribute::NoCapture);
59,400✔
194
#endif
195
        arg.addAttr(Attribute::ReadOnly);
103,140✔
196
        arg.addAttr(Attribute::NoFree);
103,140✔
197
      }
103,140✔
198
    }
199
  };
85,950✔
200
  const auto setFunctionLinkageExternal = [](llvm::Function* function) {
65,260✔
201
    function->setLinkage(GlobalValue::ExternalLinkage);
65,260✔
202
    //     f->setLinkage(GlobalValue::ExternalWeakLinkage);
203
  };
65,260✔
204
  const auto do_make = [&](auto& function_name, auto function_type) {
171,900✔
205
    const bool has_func_declared = module.getFunction(function_name) != nullptr;
85,950✔
206
    auto func_in_module          = module.getOrInsertFunction(function_name, function_type);
85,950✔
207

208
    Function* function{nullptr};
85,950✔
209
    if (has_func_declared) {
85,950✔
210
      LOG_DEBUG("Function " << function_name << " is already declared in the module.")
211
      function = dyn_cast<Function>(func_in_module.getCallee()->stripPointerCasts());
20,690✔
212
    } else {
20,690✔
213
      function = dyn_cast<Function>(func_in_module.getCallee());
65,260✔
214
      setFunctionLinkageExternal(function);
65,260✔
215
    }
216

217
    addOptimizerAttributes(function);
85,950✔
218
    return function;
85,950✔
219
  };
220

221
  auto* generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false));
85,950✔
222

223
  function_map[name] = generated_function;
85,950✔
224

225
  // if (alternative) {
226
  //   typeart_functions.putAlternativeFunctionFor(func_id, generated_function);
227
  // } else {
228
  typeart_functions.putFunctionFor(func_id, generated_function);
85,950✔
229
  // }
230
  return generated_function;
85,950✔
231
}
85,950✔
232

233
const llvm::StringMap<llvm::Function*>& TAFunctionDeclarator::getFunctionMap() const {
×
234
  return function_map;
×
235
}
236

237
Function* TAFunctions::getFunctionFor(IFunc id, TypeSerializationImplementation impl) const {
40,943✔
238
  const auto find_ = [&](const auto& map_) -> std::optional<Function*> {
81,886✔
239
    const auto element = map_.find(id);
40,943✔
240
    if (element == std::end(map_)) {
40,943✔
NEW
241
      LOG_WARNING("No functions for id " << int(id))
×
NEW
242
      return {};
×
243
    }
244
    return element->second;
40,943✔
245
  };
40,943✔
246

247
  auto result = find_(typeart_callbacks);
40,943✔
248
  return result.value_or(nullptr);
40,943✔
249
}
250

251
void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) {
85,950✔
252
  typeart_callbacks[id] = f;
85,950✔
253
}
85,950✔
254

255
class TAFunctionAlternatives : public TAFunctionQuery {
256
  TAFunctions standard_;
257
  TAFunctions alternative_;
258

259
 public:
260
  TAFunctionAlternatives(TAFunctions standard, TAFunctions alternative)
7,418✔
261
      : standard_(std::move(standard)), alternative_(std::move(alternative)) {
7,418✔
262
  }
5,730✔
263
  Function* getFunctionFor(IFunc id, TypeSerializationImplementation impl) const override {
40,943✔
264
    if (impl != TypeSerializationImplementation::FILE) {
40,943✔
265
      auto alternative = alternative_.getFunctionFor(id);
4,370✔
266
      if (alternative != nullptr) {
4,370✔
267
        return alternative;
4,370✔
268
      }
NEW
269
    }
×
270
    return standard_.getFunctionFor(id);
36,573✔
271
  }
40,943✔
272
};
273

274
namespace callbacks {
275
struct TypeArtFunc {
276
  const std::string name;
277
  llvm::Value* f{nullptr};
46,251✔
278
};
279

280
TypeArtFunc typeart_alloc{"__typeart_alloc"};
5,139✔
281
TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"};
5,139✔
282
TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"};
5,139✔
283
TypeArtFunc typeart_free{"__typeart_free"};
5,139✔
284
TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"};
5,139✔
285

286
TypeArtFunc typeart_alloc_omp        = typeart_alloc;
5,139✔
287
TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack;
5,139✔
288
TypeArtFunc typeart_free_omp         = typeart_free;
5,139✔
289
TypeArtFunc typeart_leave_scope_omp  = typeart_leave_scope;
5,139✔
290

291
TypeArtFunc typeart_alloc_mty{"__typeart_alloc_mty"};
5,139✔
292
TypeArtFunc typeart_alloc_stack_mty{"__typeart_alloc_stack_mty"};
5,139✔
293
TypeArtFunc typeart_alloc_global_mty{"__typeart_alloc_global_mty"};
5,139✔
294
TypeArtFunc typeart_register_type{"__typeart_register_type"};
5,139✔
295
TypeArtFunc typeart_alloc_omp_mty        = typeart_alloc_mty;
5,139✔
296
TypeArtFunc typeart_alloc_stacks_omp_mty = typeart_alloc_stack_mty;
5,139✔
297

298
}  // namespace callbacks
299

300
std::unique_ptr<TAFunctionQuery> declare_instrumentation_functions(llvm::Module& m,
5,730✔
301
                                                                   const config::Configuration& configuration) {
302
  using namespace callbacks;
303
  TAFunctions functions;
5,730✔
304
  TAFunctions functions_alternative;
5,730✔
305
  InstrumentationHelper instrumentation_helper;
5,730✔
306
  instrumentation_helper.setModule(m);
5,730✔
307
  TAFunctionDeclarator decl(m, instrumentation_helper, functions);
5,730✔
308
  TAFunctionDeclarator decl_alternatives(m, instrumentation_helper, functions_alternative);
5,730✔
309

310
  auto alloc_arg_types      = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent);
5,730✔
311
  auto free_arg_types       = instrumentation_helper.make_parameters(IType::ptr);
5,730✔
312
  auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count);
5,730✔
313

314
  // const TypeSerializationImplementation local_types = configuration[config::ConfigStdArgs::type_serialization];
315
  auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent);
5,730✔
316
  typeart_alloc_mty.f      = decl_alternatives.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty);
5,730✔
317
  typeart_alloc_stack_mty.f =
5,730✔
318
      decl_alternatives.make_function(IFunc::stack, typeart_alloc_stack_mty.name, alloc_arg_types_mty);
5,730✔
319
  typeart_alloc_global_mty.f =
5,730✔
320
      decl_alternatives.make_function(IFunc::global, typeart_alloc_global_mty.name, alloc_arg_types_mty);
5,730✔
321
  typeart_register_type.f = decl.make_function(IFunc::type, typeart_register_type.name, free_arg_types);
5,730✔
322

323
  typeart_alloc.f        = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types);
5,730✔
324
  typeart_alloc_stack.f  = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types);
5,730✔
325
  typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types);
5,730✔
326
  typeart_free.f         = decl.make_function(IFunc::free, typeart_free.name, free_arg_types);
5,730✔
327
  typeart_leave_scope.f  = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types);
5,730✔
328

329
  typeart_alloc_omp.f        = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types);
5,730✔
330
  typeart_alloc_stacks_omp.f = decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types);
5,730✔
331
  typeart_free_omp.f         = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types);
5,730✔
332

333
  typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types);
5,730✔
334

335
  typeart_alloc_omp_mty.f =
5,730✔
336
      decl_alternatives.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty);
5,730✔
337
  typeart_alloc_stacks_omp_mty.f =
5,730✔
338
      decl_alternatives.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty);
5,730✔
339

340
  return std::make_unique<TAFunctionAlternatives>(functions, functions_alternative);
5,730✔
341
}
5,730✔
342

343
}  // namespace typeart
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