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

tudasc / TypeART / 19336558931

13 Nov 2025 03:24PM UTC coverage: 90.337% (+1.4%) from 88.924%
19336558931

push

github

web-flow
Global variables as type descriptors (#173)

597 of 629 new or added lines in 25 files covered. (94.91%)

2 existing lines in 2 files now uncovered.

4768 of 5278 relevant lines covered (90.34%)

208224.38 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-2025 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) {
49,590✔
51
  switch (id) {
49,590✔
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";
19,836✔
60
    default:
61
      return "";
29,754✔
62
  }
63
}
49,590✔
64

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

67
IFuncType ifunc_type_for(llvm::Function* f) {
15,768✔
68
  if (f == nullptr) {
15,768✔
69
    return IFuncType::standard;
3,725✔
70
  }
71

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

76
  return IFuncType::standard;
11,727✔
77
}
15,768✔
78

79
}  // namespace detail
80

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

84
  if (auto function = llvm::dyn_cast<Function>(value)) {
15,768✔
NEW
85
    type = detail::ifunc_type_for(function);
×
86
  } else if (auto alloca = llvm::dyn_cast<AllocaInst>(value)) {
15,768✔
87
    type = detail::ifunc_type_for(alloca->getFunction());
8,677✔
88
  } else if (llvm::isa<GlobalVariable>(value)) {
15,768✔
89
    type = detail::ifunc_type_for(nullptr);
3,725✔
90
  } else if (auto callbase = llvm::dyn_cast<CallBase>(value)) {
7,091✔
91
    type = detail::ifunc_type_for(callbase->getFunction());
3,366✔
92
    // auto maybe_cuda = detail::ifunc_type_for(callbase->getCalledFunction());
93
    // if (maybe_cuda == detail::IFuncType::cuda) {
94
    //   type = detail::IFuncType::cuda;
95
    // }
96
  }
3,366✔
97

98
  if (detail::IFuncType::standard == type) {
15,768✔
99
    return general_type;
15,452✔
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
}
15,768✔
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;
6,612✔
152
};
153

154
TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, TAFunctions& typeart_funcs)
13,224✔
155
    : module(mod), typeart_functions(typeart_funcs) {
6,612✔
156
}
6,612✔
157

158
llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename,
49,590✔
159
                                                    llvm::ArrayRef<llvm::Type*> args, bool alternative) {
160
  const auto make_fname = [&func_id](llvm::StringRef name, llvm::ArrayRef<llvm::Type*> callback_arguments) {
99,180✔
161
    std::string fname;
49,590✔
162
    llvm::raw_string_ostream os(fname);
49,590✔
163
    os << name;
49,590✔
164
    os << detail::get_func_suffix(func_id);
49,590✔
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();
49,590✔
174
  };
49,590✔
175

176
  const auto name = make_fname(basename, args);
49,590✔
177

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

182
  auto& c                           = module.getContext();
49,590✔
183
  const auto addOptimizerAttributes = [&](llvm::Function* function) {
49,590✔
184
    function->setDoesNotThrow();
49,590✔
185
    function->setDoesNotFreeMemory();
49,590✔
186
    function->setDoesNotRecurse();
49,590✔
187
#if LLVM_VERSION_MAJOR >= 12
188
    function->setWillReturn();
49,590✔
189
#endif
190
    for (Argument& arg : function->args()) {
165,300✔
191
      if (arg.getType()->isPointerTy()) {
115,710✔
192
        arg.addAttr(Attribute::NoCapture);
59,508✔
193
        arg.addAttr(Attribute::ReadOnly);
59,508✔
194
        arg.addAttr(Attribute::NoFree);
59,508✔
195
      }
59,508✔
196
    }
197
  };
49,590✔
198
  const auto setFunctionLinkageExternal = [](llvm::Function* function) {
37,720✔
199
    function->setLinkage(GlobalValue::ExternalLinkage);
37,720✔
200
    //     f->setLinkage(GlobalValue::ExternalWeakLinkage);
201
  };
37,720✔
202
  const auto do_make = [&](auto& function_name, auto function_type) {
99,180✔
203
    const bool has_func_declared = module.getFunction(function_name) != nullptr;
49,590✔
204
    auto func_in_module          = module.getOrInsertFunction(function_name, function_type);
49,590✔
205

206
    Function* function{nullptr};
49,590✔
207
    if (has_func_declared) {
49,590✔
208
      LOG_DEBUG("Function " << function_name << " is already declared in the module.")
209
      function = dyn_cast<Function>(func_in_module.getCallee()->stripPointerCasts());
11,870✔
210
    } else {
11,870✔
211
      function = dyn_cast<Function>(func_in_module.getCallee());
37,720✔
212
      setFunctionLinkageExternal(function);
37,720✔
213
    }
214

215
    addOptimizerAttributes(function);
49,590✔
216
    return function;
49,590✔
217
  };
218

219
  auto* generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false));
49,590✔
220

221
  function_map[name] = generated_function;
49,590✔
222

223
  // if (alternative) {
224
  //   typeart_functions.putAlternativeFunctionFor(func_id, generated_function);
225
  // } else {
226
  typeart_functions.putFunctionFor(func_id, generated_function);
49,590✔
227
  // }
228
  return generated_function;
49,590✔
229
}
49,590✔
230

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

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

245
  auto result = find_(typeart_callbacks);
22,883✔
246
  return result.value_or(nullptr);
22,883✔
247
}
248

249
void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) {
49,590✔
250
  typeart_callbacks[id] = f;
49,590✔
251
}
49,590✔
252

253
class TAFunctionAlternatives : public TAFunctionQuery {
254
  TAFunctions standard_;
255
  TAFunctions alternative_;
256

257
 public:
258
  TAFunctionAlternatives(TAFunctions standard, TAFunctions alternative)
5,018✔
259
      : standard_(std::move(standard)), alternative_(std::move(alternative)) {
5,018✔
260
  }
3,306✔
261
  Function* getFunctionFor(IFunc id, TypeSerializationImplementation impl) const override {
22,883✔
262
    if (impl != TypeSerializationImplementation::FILE) {
22,883✔
263
      auto alternative = alternative_.getFunctionFor(id);
1,736✔
264
      if (alternative != nullptr) {
1,736✔
265
        return alternative;
1,736✔
266
      }
NEW
267
    }
×
268
    return standard_.getFunctionFor(id);
21,147✔
269
  }
22,883✔
270
};
271

272
namespace callbacks {
273
struct TypeArtFunc {
274
  const std::string name;
275
  llvm::Value* f{nullptr};
27,108✔
276
};
277

278
TypeArtFunc typeart_alloc{"__typeart_alloc"};
3,012✔
279
TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"};
3,012✔
280
TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"};
3,012✔
281
TypeArtFunc typeart_free{"__typeart_free"};
3,012✔
282
TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"};
3,012✔
283

284
TypeArtFunc typeart_alloc_omp        = typeart_alloc;
3,012✔
285
TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack;
3,012✔
286
TypeArtFunc typeart_free_omp         = typeart_free;
3,012✔
287
TypeArtFunc typeart_leave_scope_omp  = typeart_leave_scope;
3,012✔
288

289
TypeArtFunc typeart_alloc_mty{"__typeart_alloc_mty"};
3,012✔
290
TypeArtFunc typeart_alloc_stack_mty{"__typeart_alloc_stack_mty"};
3,012✔
291
TypeArtFunc typeart_alloc_global_mty{"__typeart_alloc_global_mty"};
3,012✔
292
TypeArtFunc typeart_register_type{"__typeart_register_type"};
3,012✔
293
TypeArtFunc typeart_alloc_omp_mty        = typeart_alloc_mty;
3,012✔
294
TypeArtFunc typeart_alloc_stacks_omp_mty = typeart_alloc_stack_mty;
3,012✔
295

296
}  // namespace callbacks
297

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

308
  auto alloc_arg_types      = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent);
3,306✔
309
  auto free_arg_types       = instrumentation_helper.make_parameters(IType::ptr);
3,306✔
310
  auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count);
3,306✔
311

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

321
  typeart_alloc.f        = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types);
3,306✔
322
  typeart_alloc_stack.f  = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types);
3,306✔
323
  typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types);
3,306✔
324
  typeart_free.f         = decl.make_function(IFunc::free, typeart_free.name, free_arg_types);
3,306✔
325
  typeart_leave_scope.f  = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types);
3,306✔
326

327
  typeart_alloc_omp.f        = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types);
3,306✔
328
  typeart_alloc_stacks_omp.f = decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types);
3,306✔
329
  typeart_free_omp.f         = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types);
3,306✔
330

331
  typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types);
3,306✔
332

333
  typeart_alloc_omp_mty.f =
3,306✔
334
      decl_alternatives.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty);
3,306✔
335
  typeart_alloc_stacks_omp_mty.f =
3,306✔
336
      decl_alternatives.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty);
3,306✔
337

338
  return std::make_unique<TAFunctionAlternatives>(functions, functions_alternative);
3,306✔
339
}
3,306✔
340

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