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

tudasc / TypeART / 25214948344

01 May 2026 12:52PM UTC coverage: 89.288% (-1.0%) from 90.246%
25214948344

Pull #188

github

web-flow
Merge f3181ef51 into 278119205
Pull Request #188: GPU memory allocation support

214 of 298 new or added lines in 20 files covered. (71.81%)

1 existing line in 1 file now uncovered.

5076 of 5685 relevant lines covered (89.29%)

43387.97 hits per line

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

92.35
/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/CudaUtil.h"
20
#include "support/HipUtil.h"
21
#include "support/Logger.h"
22
#include "support/OmpUtil.h"
23

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

37
#include <memory>
38
#include <optional>
39
#include <string>
40
#include <unordered_map>
41
#include <utility>
42

43
namespace typeart {
44
class InstrumentationHelper;
45
}  // namespace typeart
46

47
using namespace llvm;
48

49
namespace typeart {
50

51
namespace detail {
52
std::string get_func_suffix(IFunc id) {
133,077✔
53
  switch (id) {
133,077✔
54
    case IFunc::free_cuda:
55
    case IFunc::heap_cuda:
56
    case IFunc::free_hip:
57
    case IFunc::heap_hip:
58
      return "_gpu";
38,022✔
59
    case IFunc::free_omp:
60
    case IFunc::heap_omp:
61
    case IFunc::stack_omp:
62
    case IFunc::scope_omp:
63
      return "_omp";
38,022✔
64
    default:
65
      return "";
57,033✔
66
  }
67
}
133,077✔
68

69
enum class IFuncType : unsigned { standard, omp, cuda, hip };
70

71
IFuncType ifunc_type_for(llvm::Function* f) {
36,005✔
72
  if (f == nullptr) {
36,005✔
73
    return IFuncType::standard;
6,960✔
74
  }
75

76
  if (cuda::is_cuda_function(*f)) {
29,045✔
77
    return IFuncType::cuda;
34✔
78
  }
79

80
  if (hip::is_hip_function(*f)) {
29,011✔
NEW
81
    return IFuncType::hip;
×
82
  }
83

84
  if (util::omp::isOmpContext(f)) {
29,011✔
85
    return IFuncType::omp;
356✔
86
  }
87

88
  return IFuncType::standard;
28,655✔
89
}
36,005✔
90

91
}  // namespace detail
92

93
IFunc ifunc_for_function(IFunc general_type, llvm::Value* value) {
29,412✔
94
  detail::IFuncType type = typeart::detail::IFuncType::standard;
29,412✔
95

96
  if (auto function = llvm::dyn_cast<Function>(value)) {
29,412✔
97
    type = detail::ifunc_type_for(function);
×
98
  } else if (auto alloca = llvm::dyn_cast<AllocaInst>(value)) {
29,412✔
99
    type = detail::ifunc_type_for(alloca->getFunction());
15,859✔
100
  } else if (llvm::isa<GlobalVariable>(value)) {
29,412✔
101
    type = detail::ifunc_type_for(nullptr);
6,960✔
102
  } else if (auto callbase = llvm::dyn_cast<CallBase>(value)) {
13,553✔
103
    type                = detail::ifunc_type_for(callbase->getFunction());
6,593✔
104
    auto called_context = detail::ifunc_type_for(callbase->getCalledFunction());
6,593✔
105
    if (called_context == detail::IFuncType::cuda || called_context == detail::IFuncType::hip) {
6,593✔
106
      type = called_context;
34✔
107
    }
34✔
108
  }
6,593✔
109

110
  if (detail::IFuncType::standard == type) {
29,412✔
111
    return general_type;
29,022✔
112
  }
113

114
  if (detail::IFuncType::cuda == type) {
390✔
115
    switch (general_type) {
34✔
116
      case IFunc::heap:
117
        return IFunc::heap_cuda;
28✔
118
      case IFunc::free:
119
        return IFunc::free_cuda;
6✔
120
      default:
NEW
121
        return general_type;
×
122
    }
123
  }
124

125
  if (detail::IFuncType::hip == type) {
356✔
NEW
126
    switch (general_type) {
×
127
      case IFunc::heap:
NEW
128
        return IFunc::heap_hip;
×
129
      case IFunc::free:
NEW
130
        return IFunc::free_hip;
×
131
      default:
NEW
132
        return general_type;
×
133
    }
134
  }
135

136
  switch (general_type) {
356✔
137
    case IFunc::stack:
138
      return IFunc::stack_omp;
236✔
139
    case IFunc::heap:
140
      return IFunc::heap_omp;
65✔
141
    case IFunc::free:
142
      return IFunc::free_omp;
55✔
143
    case IFunc::scope:
144
      return IFunc::scope_omp;
×
145
    default:
146
      llvm_unreachable("IFunc type is not supported for OpenMP.");
×
147
  }
148
}
29,412✔
149

150
class TAFunctions final : public TAFunctionQuery {
151
  // densemap has problems with IFunc
152
  using FMap = std::unordered_map<IFunc, llvm::Function*>;
153
  FMap typeart_callbacks;
154

155
 public:
156
  llvm::Function* getFunctionFor(
157
      IFunc id, TypeSerializationImplementation impl = TypeSerializationImplementation::FILE) const override;
158
  void putFunctionFor(IFunc id, llvm::Function* f);
159
  // void putAlternativeFunctionFor(IFunc id, llvm::Function* f);
160
};
161

162
class TAFunctionDeclarator {
163
  llvm::Module& module;
164
  //  [[maybe_unused]] InstrumentationHelper& instr;
165
  TAFunctions& typeart_functions;
166
  llvm::StringMap<llvm::Function*> function_map;
167

168
 public:
169
  TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func);
170
  llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef<llvm::Type*> args,
171
                                bool alternative = false);
172
  const llvm::StringMap<llvm::Function*>& getFunctionMap() const;
173
  virtual ~TAFunctionDeclarator() = default;
12,674✔
174
};
175

176
TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, TAFunctions& typeart_funcs)
25,348✔
177
    : module(mod), typeart_functions(typeart_funcs) {
12,674✔
178
}
12,674✔
179

180
llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename,
133,077✔
181
                                                    llvm::ArrayRef<llvm::Type*> args, bool alternative) {
182
  const auto make_fname = [&func_id](llvm::StringRef name, llvm::ArrayRef<llvm::Type*> callback_arguments) {
266,154✔
183
    std::string fname;
133,077✔
184
    llvm::raw_string_ostream os(fname);
133,077✔
185
    os << name;
133,077✔
186
    os << detail::get_func_suffix(func_id);
133,077✔
187

188
    // if (!fixed_name) {
189
    //   os << "_" << std::to_string(callback_arguments.size());
190
    // }
191
    // if (with_omp_postfix) {
192
    //   os << "_"
193
    //      << "omp";
194
    // }
195
    return os.str();
133,077✔
196
  };
133,077✔
197

198
  const auto name = make_fname(basename, args);
133,077✔
199

200
  if (auto it = function_map.find(name); it != function_map.end()) {
133,077✔
201
    typeart_functions.putFunctionFor(func_id, it->second);
19,011✔
202
    return it->second;
19,011✔
203
  }
204

205
  auto& c                           = module.getContext();
114,066✔
206
  const auto addOptimizerAttributes = [&](llvm::Function* function) {
114,066✔
207
    function->setDoesNotThrow();
114,066✔
208
    function->setDoesNotFreeMemory();
114,066✔
209
    function->setDoesNotRecurse();
114,066✔
210
#if LLVM_VERSION_MAJOR >= 12
211
    function->setWillReturn();
114,066✔
212
#endif
213
    for (Argument& arg : function->args()) {
380,220✔
214
      if (arg.getType()->isPointerTy()) {
266,154✔
215
#if LLVM_VERSION_MAJOR < 20
216
        arg.addAttr(Attribute::NoCapture);
79,442✔
217
#endif
218
        arg.addAttr(Attribute::ReadOnly);
139,414✔
219
        arg.addAttr(Attribute::NoFree);
139,414✔
220
      }
139,414✔
221
    }
222
  };
114,066✔
223
  const auto setFunctionLinkageExternal = [](llvm::Function* function) {
87,076✔
224
    function->setLinkage(GlobalValue::ExternalLinkage);
87,076✔
225
    //     f->setLinkage(GlobalValue::ExternalWeakLinkage);
226
  };
87,076✔
227
  const auto do_make = [&](auto& function_name, auto function_type) {
228,132✔
228
    const bool has_func_declared = module.getFunction(function_name) != nullptr;
114,066✔
229
    auto func_in_module          = module.getOrInsertFunction(function_name, function_type);
114,066✔
230

231
    Function* function{nullptr};
114,066✔
232
    if (has_func_declared) {
114,066✔
233
      LOG_DEBUG("Function " << function_name << " is already declared in the module.")
234
      function = dyn_cast<Function>(func_in_module.getCallee()->stripPointerCasts());
26,990✔
235
    } else {
26,990✔
236
      function = dyn_cast<Function>(func_in_module.getCallee());
87,076✔
237
      setFunctionLinkageExternal(function);
87,076✔
238
    }
239

240
    addOptimizerAttributes(function);
114,066✔
241
    return function;
114,066✔
242
  };
243

244
  auto* generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false));
114,066✔
245

246
  function_map[name] = generated_function;
114,066✔
247

248
  // if (alternative) {
249
  //   typeart_functions.putAlternativeFunctionFor(func_id, generated_function);
250
  // } else {
251
  typeart_functions.putFunctionFor(func_id, generated_function);
114,066✔
252
  // }
253
  return generated_function;
114,066✔
254
}
133,077✔
255

256
const llvm::StringMap<llvm::Function*>& TAFunctionDeclarator::getFunctionMap() const {
×
257
  return function_map;
×
258
}
259

260
Function* TAFunctions::getFunctionFor(IFunc id, TypeSerializationImplementation impl) const {
44,892✔
261
  const auto find_ = [&](const auto& map_) -> std::optional<Function*> {
89,784✔
262
    const auto element = map_.find(id);
44,892✔
263
    if (element == std::end(map_)) {
44,892✔
264
      LOG_WARNING("No functions for id " << int(id))
×
265
      return {};
×
266
    }
267
    return element->second;
44,892✔
268
  };
44,892✔
269

270
  auto result = find_(typeart_callbacks);
44,892✔
271
  return result.value_or(nullptr);
44,892✔
272
}
273

274
void TAFunctions::putFunctionFor(IFunc id, llvm::Function* f) {
133,077✔
275
  typeart_callbacks[id] = f;
133,077✔
276
}
133,077✔
277

278
class TAFunctionAlternatives : public TAFunctionQuery {
279
  TAFunctions standard_;
280
  TAFunctions alternative_;
281

282
 public:
283
  TAFunctionAlternatives(TAFunctions standard, TAFunctions alternative)
8,336✔
284
      : standard_(std::move(standard)), alternative_(std::move(alternative)) {
8,336✔
285
  }
6,337✔
286
  Function* getFunctionFor(IFunc id, TypeSerializationImplementation impl) const override {
44,892✔
287
    if (impl != TypeSerializationImplementation::FILE) {
44,892✔
288
      auto alternative = alternative_.getFunctionFor(id);
4,721✔
289
      if (alternative != nullptr) {
4,721✔
290
        return alternative;
4,721✔
291
      }
292
    }
×
293
    return standard_.getFunctionFor(id);
40,171✔
294
  }
44,892✔
295
};
296

297
namespace callbacks {
298
struct TypeArtFunc {
299
  const std::string name;
300
  llvm::Value* f{nullptr};
51,246✔
301
};
302

303
TypeArtFunc typeart_alloc{"__typeart_alloc"};
5,694✔
304
TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"};
5,694✔
305
TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"};
5,694✔
306
TypeArtFunc typeart_free{"__typeart_free"};
5,694✔
307
TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"};
5,694✔
308

309
TypeArtFunc typeart_alloc_omp        = typeart_alloc;
5,694✔
310
TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack;
5,694✔
311
TypeArtFunc typeart_free_omp         = typeart_free;
5,694✔
312
TypeArtFunc typeart_leave_scope_omp  = typeart_leave_scope;
5,694✔
313
TypeArtFunc typeart_alloc_cuda       = typeart_alloc;
5,694✔
314
TypeArtFunc typeart_free_cuda        = typeart_free;
5,694✔
315

316
TypeArtFunc typeart_alloc_mty{"__typeart_alloc_mty"};
5,694✔
317
TypeArtFunc typeart_alloc_stack_mty{"__typeart_alloc_stack_mty"};
5,694✔
318
TypeArtFunc typeart_alloc_global_mty{"__typeart_alloc_global_mty"};
5,694✔
319
TypeArtFunc typeart_register_type{"__typeart_register_type"};
5,694✔
320
TypeArtFunc typeart_alloc_omp_mty        = typeart_alloc_mty;
5,694✔
321
TypeArtFunc typeart_alloc_stacks_omp_mty = typeart_alloc_stack_mty;
5,694✔
322

323
TypeArtFunc typeart_alloc_cuda_mty = typeart_alloc_mty;
5,694✔
324

325
}  // namespace callbacks
326

327
std::unique_ptr<TAFunctionQuery> declare_instrumentation_functions(llvm::Module& m,
6,337✔
328
                                                                   const config::Configuration& configuration) {
329
  using namespace callbacks;
330
  TAFunctions functions;
6,337✔
331
  TAFunctions functions_alternative;
6,337✔
332
  InstrumentationHelper instrumentation_helper;
6,337✔
333
  instrumentation_helper.setModule(m);
6,337✔
334
  TAFunctionDeclarator decl(m, instrumentation_helper, functions);
6,337✔
335
  TAFunctionDeclarator decl_alternatives(m, instrumentation_helper, functions_alternative);
6,337✔
336

337
  auto alloc_arg_types      = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent);
6,337✔
338
  auto free_arg_types       = instrumentation_helper.make_parameters(IType::ptr);
6,337✔
339
  auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count);
6,337✔
340

341
  // const TypeSerializationImplementation local_types = configuration[config::ConfigStdArgs::type_serialization];
342
  auto alloc_arg_types_mty = instrumentation_helper.make_parameters(IType::ptr, IType::ptr, IType::extent);
6,337✔
343
  typeart_alloc_mty.f      = decl_alternatives.make_function(IFunc::heap, typeart_alloc_mty.name, alloc_arg_types_mty);
6,337✔
344
  typeart_alloc_stack_mty.f =
6,337✔
345
      decl_alternatives.make_function(IFunc::stack, typeart_alloc_stack_mty.name, alloc_arg_types_mty);
6,337✔
346
  typeart_alloc_global_mty.f =
6,337✔
347
      decl_alternatives.make_function(IFunc::global, typeart_alloc_global_mty.name, alloc_arg_types_mty);
6,337✔
348
  // functions_alternative.putFunctionFor(IFunc::heap_cuda, llvm::cast<llvm::Function>(typeart_alloc_mty.f));
349
  typeart_register_type.f = decl.make_function(IFunc::type, typeart_register_type.name, free_arg_types);
6,337✔
350

351
  typeart_alloc.f        = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types);
6,337✔
352
  typeart_alloc_stack.f  = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types);
6,337✔
353
  typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types);
6,337✔
354
  typeart_free.f         = decl.make_function(IFunc::free, typeart_free.name, free_arg_types);
6,337✔
355
  typeart_leave_scope.f  = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types);
6,337✔
356

357
  typeart_alloc_omp.f        = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types);
6,337✔
358
  typeart_alloc_stacks_omp.f = decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types);
6,337✔
359
  typeart_free_omp.f         = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types);
6,337✔
360

361
  typeart_leave_scope_omp.f = decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types);
6,337✔
362

363
  typeart_alloc_cuda.f = decl.make_function(IFunc::heap_cuda, typeart_alloc_cuda.name, alloc_arg_types);
6,337✔
364
  typeart_free_cuda.f  = decl.make_function(IFunc::free_cuda, typeart_free_cuda.name, free_arg_types);
6,337✔
365
  decl.make_function(IFunc::heap_hip, typeart_alloc_cuda.name, alloc_arg_types);
6,337✔
366
  decl.make_function(IFunc::free_hip, typeart_free_cuda.name, free_arg_types);
6,337✔
367

368
  typeart_alloc_omp_mty.f =
6,337✔
369
      decl_alternatives.make_function(IFunc::heap_omp, typeart_alloc_omp_mty.name, alloc_arg_types_mty);
6,337✔
370
  typeart_alloc_stacks_omp_mty.f =
6,337✔
371
      decl_alternatives.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp_mty.name, alloc_arg_types_mty);
6,337✔
372

373
  typeart_alloc_cuda_mty.f =
6,337✔
374
      decl_alternatives.make_function(IFunc::heap_cuda, typeart_alloc_cuda_mty.name, alloc_arg_types_mty);
6,337✔
375
  decl_alternatives.make_function(IFunc::heap_hip, typeart_alloc_cuda_mty.name, alloc_arg_types_mty);
6,337✔
376

377
  return std::make_unique<TAFunctionAlternatives>(functions, functions_alternative);
6,337✔
378
}
6,337✔
379

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