• 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

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

13
#include "TypeManager.h"
14

15
#include "IRTypeGen.h"
16
#include "StructTypeHandler.h"
17
#include "VectorTypeHandler.h"
18
#include "support/GpuUtil.h"
19
#include "support/Logger.h"
20
#include "support/TypeUtil.h"
21
#include "support/Util.h"
22
#include "typelib/TypeInterface.h"
23

24
#include "llvm/ADT/StringMap.h"
25
#include "llvm/ADT/StringRef.h"
26
#include "llvm/IR/Constants.h"
27
#include "llvm/IR/DataLayout.h"
28
#include "llvm/IR/DerivedTypes.h"
29
#include "llvm/IR/Instructions.h"
30
#include "llvm/IR/Module.h"
31
#include "llvm/IR/Type.h"
32
#include "llvm/Support/Casting.h"
33
#include "llvm/Support/TypeSize.h"
34
#include "llvm/Support/raw_ostream.h"
35

36
#include <cassert>
37
#include <cstddef>
38
#include <optional>
39
#include <string>
40
#include <utility>
41
#include <vector>
42

43
namespace typeart {
44

45
namespace tu = typeart::util::type;
46

47
std::unique_ptr<TypeGenerator> make_ir_typeidgen(std::string_view file,
703✔
48
                                                 std::unique_ptr<TypeDatabase> database_of_types) {
49
  return std::make_unique<TypeManager>(std::string{file}, std::move(database_of_types));
703✔
50
}
×
51

52
using namespace llvm;
53

54
std::optional<typeart_builtin_type> get_builtin_typeid(llvm::Type* type) {
6,856✔
55
  auto& c = type->getContext();
6,856✔
56

57
  switch (type->getTypeID()) {
6,856✔
58
    case llvm::Type::IntegerTyID: {
59
      if (type == Type::getInt8Ty(c)) {
4,507✔
60
        return TYPEART_INT_8;
2,089✔
61
      }
62
      if (type == Type::getInt16Ty(c)) {
2,418✔
63
        return TYPEART_INT_16;
30✔
64
      }
65
      if (type == Type::getInt32Ty(c)) {
2,388✔
66
        return TYPEART_INT_32;
1,889✔
67
      }
68
      if (type == Type::getInt64Ty(c)) {
499✔
69
        return TYPEART_INT_64;
493✔
70
      }
71
      return TYPEART_UNKNOWN_TYPE;
6✔
72
    }
73
    case llvm::Type::HalfTyID:
74
      return TYPEART_FLOAT_16;
×
75
    case llvm::Type::FloatTyID:
76
      return TYPEART_FLOAT_32;
133✔
77
    case llvm::Type::DoubleTyID:
78
      return TYPEART_FLOAT_64;
221✔
79
    case llvm::Type::X86_FP80TyID:
80
    case llvm::Type::FP128TyID:
81
      return TYPEART_FLOAT_128;
×
82
    case llvm::Type::PointerTyID:
83
      return TYPEART_POINTER;
672✔
84
    default:
85
      return {};
1,323✔
86
  }
87
}
6,856✔
88

89
int TypeManager::getOrRegisterVector(llvm::VectorType* type, const llvm::DataLayout& dl) {
33✔
90
  namespace tu = typeart::util;
91

92
  VectorTypeHandler handler{&structMap, typeDB.get(), type, dl, *this};
33✔
93
  const auto type_id = handler.getID();
33✔
94
  if (type_id) {
33✔
95
    return type_id.value();
18✔
96
  }
97

98
  // Type is not registered - reserve new ID and create struct info object:
99

100
  auto element_data = handler.getElementData();
15✔
101
  if (!element_data) {
15✔
102
    return TYPEART_UNKNOWN_TYPE;
×
103
  }
104

105
  auto vector_data = handler.getVectorData();
15✔
106
  if (!vector_data) {
15✔
107
    return TYPEART_UNKNOWN_TYPE;
×
108
  }
109

110
  const int id = reserveNextTypeId();
15✔
111

112
  const auto [element_id, element_type, element_name] = element_data.value();
81✔
113
  const auto [vector_name, vector_bytes, vector_size] = vector_data.value();
96✔
114

115
  std::vector<int> memberTypeIDs;
15✔
116
  std::vector<size_t> arraySizes;
15✔
117
  std::vector<size_t> offsets;
15✔
118

119
  size_t elementSize = tu::type::getTypeSizeInBytes(element_type, dl);
15✔
120

121
  for (unsigned long i = 0; i < vector_size; ++i) {
66✔
122
    memberTypeIDs.push_back(element_id);
51✔
123
    arraySizes.push_back(1);
51✔
124
    offsets.push_back(i * elementSize);
51✔
125
  }
51✔
126

127
  // size_t usableBytes = vector_size * elementSize;
128

129
  // Add padding bytes explicitly
130
  // if (vector_bytes > usableBytes) {
131
  //   size_t padding = vector_bytes - usableBytes;
132
  //   memberTypeIDs.push_back(TYPEART_INT8);
133
  //   arraySizes.push_back(padding);
134
  //   offsets.push_back(usableBytes);
135
  // }
136

137
  StructTypeInfo vecTypeInfo{id,      vector_name,   vector_bytes, memberTypeIDs.size(),
30✔
138
                             offsets, memberTypeIDs, arraySizes,   StructTypeFlag::LLVM_VECTOR};
15✔
139
  typeDB->registerStruct(vecTypeInfo);
15✔
140
  structMap.insert({vector_name, id});
30✔
141
  return id;
15✔
142
}
33✔
143

144
// TypeManager::TypeManager(std::string file, std::unique_ptr<TypeDatabase> database_of_types)
145
//     : types::TypeIDGenerator(std::move(file), std::move(database_of_types)) {
146
// }
147

148
int TypeManager::getTypeID(llvm::Type* type, const DataLayout& dl) const {
63✔
149
  auto builtin_id = get_builtin_typeid(type);
63✔
150
  if (builtin_id) {
63✔
151
    return builtin_id.value();
63✔
152
  }
153

154
  switch (type->getTypeID()) {
×
155
#if LLVM_VERSION_MAJOR < 11
156
    case llvm::Type::VectorTyID:
157
#else
158
    case llvm::Type::FixedVectorTyID:
159
#endif
160
    {
161
      VectorTypeHandler handle{&structMap, typeDB.get(), dyn_cast<VectorType>(type), dl, *this};
×
162
      const auto type_id = handle.getID();
×
163
      if (type_id) {
×
164
        return type_id.value();
×
165
      }
166
      break;
×
167
    }
168
    case llvm::Type::StructTyID: {
169
      StructTypeHandler handle{&structMap, typeDB.get(), dyn_cast<StructType>(type)};
×
170
      const auto type_id = handle.getID();
×
171
      if (type_id) {
×
172
        return type_id.value();
×
173
      }
174
      break;
×
175
    }
176
#if LLVM_VERSION_MAJOR > 10
177
    case llvm::Type::ScalableVectorTyID: {
178
      LOG_ERROR("Scalable SIMD vectors are unsupported.")
×
179
      break;
×
180
    }
181
#endif
182
    default:
183
      break;
×
184
  }
185

186
  return TYPEART_UNKNOWN_TYPE;
×
187
}
63✔
188

189
int TypeManager::getOrRegisterType(llvm::Type* type, const llvm::DataLayout& dl) {
6,793✔
190
  auto builtin_id = get_builtin_typeid(type);
6,793✔
191
  if (builtin_id) {
6,793✔
192
    return builtin_id.value();
5,470✔
193
  }
194

195
  switch (type->getTypeID()) {
1,323✔
196
#if LLVM_VERSION_MAJOR < 11
197
    case llvm::Type::VectorTyID:
198
#else
199
    case llvm::Type::FixedVectorTyID:
200
#endif
201
    {
202
      return getOrRegisterVector(dyn_cast<VectorType>(type), dl);
33✔
203
    }
204
    case llvm::Type::StructTyID:
205
      return getOrRegisterStruct(dyn_cast<StructType>(type), dl);
1,290✔
206
    default:
207
      break;
×
208
  }
209
  return TYPEART_UNKNOWN_TYPE;
×
210
}
6,793✔
211

212
int TypeManager::getOrRegisterStruct(llvm::StructType* type, const llvm::DataLayout& dl) {
1,290✔
213
  namespace tu = typeart::util;
214

215
  StructTypeHandler handle{&structMap, typeDB.get(), type};
1,290✔
216
  const auto type_id = handle.getID();
1,290✔
217
  if (type_id) {
1,290✔
218
    return type_id.value();
466✔
219
  }
220

221
  const auto name = handle.getName();
824✔
222

223
  // Get next ID and register struct:
224
  const int id = reserveNextTypeId();
824✔
225

226
  size_t n = type->getStructNumElements();
824✔
227

228
  std::vector<size_t> offsets;
824✔
229
  std::vector<size_t> arraySizes;
824✔
230
  std::vector<int> memberTypeIDs;
824✔
231

232
  const StructLayout* layout = dl.getStructLayout(type);
824✔
233

234
  for (unsigned i = 0; i < n; ++i) {
2,612✔
235
    llvm::Type* memberType = type->getStructElementType(i);
1,788✔
236
    int memberID           = TYPEART_UNKNOWN_TYPE;
1,788✔
237
    size_t arraySize       = 1;
1,788✔
238

239
    if (memberType->isArrayTy()) {
1,788✔
240
      // Note that clang does not allow VLAs inside of structs (GCC does)
241
      arraySize  = tu::type::getArrayLengthFlattened(memberType);
145✔
242
      memberType = tu::type::getArrayElementType(memberType);
145✔
243
    }
145✔
244

245
    if (memberType->isStructTy()) {
1,788✔
246
      if (StructTypeHandler::getName(llvm::dyn_cast<StructType>(memberType)) == name) {
395✔
247
        memberID = id;
×
248
      } else {
×
249
        memberID = getOrRegisterType(memberType, dl);
395✔
250
      }
251
    } else if (memberType->isSingleValueType() || memberType->isPointerTy()) {
1,788✔
252
      memberID = getOrRegisterType(memberType, dl);
1,393✔
253
    } else {
1,393✔
254
      // clang-format off
255
      LOG_ERROR("In struct: " << tu::dump(*type)
×
256
                  << ": Encountered unhandled type: " << tu::dump(*memberType)
257
                  << " with type id: " << memberType->getTypeID());
258
      // clang-format on
259
      assert(false && "Encountered unhandled type");
×
260
    }
261

262
    size_t offset = layout->getElementOffset(i);
1,788✔
263
    offsets.push_back(offset);
1,788✔
264
    arraySizes.push_back(arraySize);
1,788✔
265
    memberTypeIDs.push_back(memberID);
1,788✔
266
  }
1,788✔
267

268
  size_t numBytes = layout->getSizeInBytes();
824✔
269

270
  StructTypeInfo structInfo{id, name, numBytes, n, offsets, memberTypeIDs, arraySizes, StructTypeFlag::USER_DEFINED};
824✔
271
  typeDB->registerStruct(structInfo);
824✔
272

273
  structMap.insert({name, id});
824✔
274
  return id;
824✔
275
}
1,290✔
276

277
TypeIdentifier TypeManager::getOrRegisterType(const MallocData& mdata) {
442✔
278
  auto malloc_call            = mdata.call;
442✔
279
  const llvm::DataLayout& dl  = malloc_call->getModule()->getDataLayout();
442✔
280
  BitCastInst* primaryBitcast = mdata.primary;
442✔
281
  llvm::Type* allocation_type = nullptr;
442✔
282

283
  if (is_kind(mdata.kind, MemOpKind::GpuMallocLike) && primaryBitcast == nullptr) {
442✔
NEW
284
    if (auto bitcast = gpu::bitcast_for(*malloc_call, mdata.kind); bitcast.has_value()) {
×
NEW
285
      primaryBitcast = *bitcast;
×
NEW
286
    }
×
NEW
287
  }
×
288

289
  if (is_kind(mdata.kind, MemOpKind::GpuMallocLike)) {
442✔
NEW
290
    allocation_type = llvm::Type::getInt8Ty(malloc_call->getContext());
×
NEW
291
  } else {
×
292
    auto pointee_type = tu::getPointerElementType(malloc_call->getType());
442✔
293
    allocation_type   = !pointee_type ? llvm::Type::getInt8Ty(malloc_call->getContext()) : *pointee_type;
442✔
294
  }
295

296
  int typeId = getOrRegisterType(allocation_type, dl);  // retrieveTypeID(tu::getVoidType(c));
442✔
297

298
  if (is_kind(mdata.kind, MemOpKind::GpuMallocLike)) {
442✔
NEW
299
    typeId = TYPEART_POINTER;
×
NEW
300
  }
×
301

302
  if (typeId == TYPEART_UNKNOWN_TYPE) {
442✔
UNCOV
303
    LOG_ERROR("Unknown heap type. Not instrumenting. " << util::dump(*malloc_call));
×
304
    // TODO notify caller that we skipped: via lambda callback function
305
    return {};
×
306
  };
307

308
  // Number of bytes per element, 1 for void*
309
  unsigned typeSize = tu::getTypeSizeInBytes(allocation_type, dl);
442✔
310

311
  if (is_kind(mdata.kind, MemOpKind::GpuMallocLike)) {
442✔
NEW
312
    typeSize = 1;
×
NEW
313
  }
×
314

315
  // Use the first cast as the determining type (if there is any)
316
  if (primaryBitcast != nullptr) {
442✔
317
    llvm::Type* dstPtrType = nullptr;
385✔
318
    if (auto pointee_type = tu::getPointerElementType(primaryBitcast->getDestTy()); pointee_type.has_value()) {
385✔
319
      dstPtrType = *pointee_type;
385✔
320
    }
385✔
321
    // Basically: getSrcTy()->getPointerElementType()->getPointerElementType():
322
    if (is_kind(mdata.kind, MemOpKind::GpuMallocLike) && dstPtrType == nullptr) {
385✔
NEW
323
      if (auto pointee_type = tu::getPointerElementType(primaryBitcast->getSrcTy()); pointee_type.has_value()) {
×
NEW
324
        dstPtrType = *pointee_type;
×
NEW
325
      }
×
NEW
326
      if (dstPtrType != nullptr && dstPtrType->isPointerTy()) {
×
NEW
327
        if (auto nested = tu::getPointerElementType(dstPtrType); nested.has_value()) {
×
NEW
328
          dstPtrType = *nested;
×
NEW
329
        }
×
NEW
330
      }
×
NEW
331
    }
×
332

333
    if (dstPtrType == nullptr) {
385✔
NEW
334
      LOG_WARNING("Could not resolve non-opaque pointee type for allocation cast. Keeping fallback type.")
×
NEW
335
      return {typeId, 0};
×
336
    }
337

338
    typeSize = tu::getTypeSizeInBytes(dstPtrType, dl);
385✔
339

340
    // Resolve arrays
341
    // TODO: Write tests for this case
342
    if (dstPtrType->isArrayTy()) {
385✔
343
      dstPtrType = tu::getArrayElementType(dstPtrType);
3✔
344
    }
3✔
345

346
    typeId = getOrRegisterType(dstPtrType, dl);
385✔
347
    if (typeId == TYPEART_UNKNOWN_TYPE) {
385✔
348
      LOG_ERROR("Target type of casted allocation is unknown. Not instrumenting. " << util::dump(*malloc_call));
3✔
349
      LOG_ERROR("Cast: " << util::dump(*primaryBitcast));
3✔
350
      LOG_ERROR("Target type: " << util::dump(*dstPtrType));
3✔
351
    }
3✔
352
  } else {
385✔
353
    LOG_WARNING("Primary bitcast is null. malloc: " << util::dump(*malloc_call))
57✔
354
  }
355
  return {typeId, 0};
442✔
356
}
442✔
357

358
TypeIdentifier TypeManager::getOrRegisterType(const AllocaData& adata) {
2,571✔
359
  auto alloca                = adata.alloca;
2,571✔
360
  const llvm::DataLayout& dl = alloca->getModule()->getDataLayout();
2,571✔
361
  Type* elementType          = alloca->getAllocatedType();
2,571✔
362

363
  auto arraySize = adata.array_size == 0 ? 1 : adata.array_size;
2,571✔
364
  if (elementType->isArrayTy()) {
2,571✔
365
    arraySize   = arraySize * tu::getArrayLengthFlattened(elementType);
104✔
366
    elementType = tu::getArrayElementType(elementType);
104✔
367
  }
104✔
368

369
  int typeId = getOrRegisterType(elementType, dl);
2,571✔
370

371
  return {typeId, arraySize};
2,571✔
372
}
373

374
TypeIdentifier TypeManager::getOrRegisterType(const GlobalData& gdata) {
1,607✔
375
  auto global                = gdata.global;
1,607✔
376
  const llvm::DataLayout& dl = global->getParent()->getDataLayout();
1,607✔
377
  auto type                  = global->getValueType();
1,607✔
378

379
  size_t num_elements{1};
1,607✔
380
  if (type->isArrayTy()) {
1,607✔
381
    num_elements = tu::getArrayLengthFlattened(type);
1,475✔
382
    type         = tu::getArrayElementType(type);
1,475✔
383
  }
1,475✔
384

385
  int typeId = getOrRegisterType(type, dl);
1,607✔
386
  return {typeId, num_elements};
1,607✔
387
}
388

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