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

tudasc / TypeART / 12904858633

22 Jan 2025 09:11AM UTC coverage: 90.735% (+0.005%) from 90.73%
12904858633

Pull #149

github

web-flow
Merge f0a5eda87 into 37d7f8cb1
Pull Request #149: Replace llvm::Optional with std::optional

88 of 102 new or added lines in 23 files covered. (86.27%)

1 existing line in 1 file now uncovered.

3829 of 4220 relevant lines covered (90.73%)

117945.73 hits per line

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

83.53
/lib/passes/typegen/ir/TypeManager.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2025 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/Logger.h"
19
#include "support/TypeUtil.h"
20
#include "support/Util.h"
21
#include "typelib/TypeInterface.h"
22

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

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

42
namespace typeart {
43

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

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

51
using namespace llvm;
52

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

56
  switch (type->getTypeID()) {
7,278✔
57
    case llvm::Type::IntegerTyID: {
58
      if (type == Type::getInt8Ty(c)) {
4,807✔
59
        return TYPEART_INT_8;
2,306✔
60
      }
61
      if (type == Type::getInt16Ty(c)) {
2,501✔
62
        return TYPEART_INT_16;
30✔
63
      }
64
      if (type == Type::getInt32Ty(c)) {
2,471✔
65
        return TYPEART_INT_32;
1,954✔
66
      }
67
      if (type == Type::getInt64Ty(c)) {
517✔
68
        return TYPEART_INT_64;
511✔
69
      }
70
      return TYPEART_UNKNOWN_TYPE;
6✔
71
    }
72
    case llvm::Type::HalfTyID:
73
      return TYPEART_FLOAT_16;
×
74
    case llvm::Type::FloatTyID:
75
      return TYPEART_FLOAT_32;
130✔
76
    case llvm::Type::DoubleTyID:
77
      return TYPEART_FLOAT_64;
208✔
78
    case llvm::Type::X86_FP80TyID:
79
    case llvm::Type::FP128TyID:
80
      return TYPEART_FLOAT_128;
×
81
    case llvm::Type::PointerTyID:
82
      return TYPEART_POINTER;
604✔
83
    default:
84
      return {};
1,529✔
85
  }
86
}
7,278✔
87

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

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

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

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

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

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

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

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

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

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

126
  // size_t usableBytes = vector_size * elementSize;
127

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

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

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

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

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

185
  return TYPEART_UNKNOWN_TYPE;
×
186
}
63✔
187

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

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

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

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

220
  const auto name = handle.getName();
871✔
221

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

225
  size_t n = type->getStructNumElements();
871✔
226

227
  std::vector<size_t> offsets;
871✔
228
  std::vector<size_t> arraySizes;
871✔
229
  std::vector<int> memberTypeIDs;
871✔
230

231
  const StructLayout* layout = dl.getStructLayout(type);
871✔
232

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

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

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

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

267
  size_t numBytes = layout->getSizeInBytes();
871✔
268

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

272
  structMap.insert({name, id});
871✔
273
  return id;
871✔
274
}
1,496✔
275

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

281
  int typeId = getOrRegisterType(malloc_call->getType()->getPointerElementType(),
918✔
282
                                 dl);  // retrieveTypeID(tu::getVoidType(c));
459✔
283
  if (typeId == TYPEART_UNKNOWN_TYPE) {
459✔
284
    LOG_ERROR("Unknown heap type. Not instrumenting. " << util::dump(*malloc_call));
×
285
    // TODO notify caller that we skipped: via lambda callback function
286
    return {};
×
287
  };
288

289
  // Number of bytes per element, 1 for void*
290
  unsigned typeSize = tu::getTypeSizeInBytes(malloc_call->getType()->getPointerElementType(), dl);
459✔
291

292
  // Use the first cast as the determining type (if there is any)
293
  if (primaryBitcast != nullptr) {
459✔
294
    auto* dstPtrType = primaryBitcast->getDestTy()->getPointerElementType();
405✔
295

296
    typeSize = tu::getTypeSizeInBytes(dstPtrType, dl);
405✔
297

298
    // Resolve arrays
299
    // TODO: Write tests for this case
300
    if (dstPtrType->isArrayTy()) {
405✔
301
      dstPtrType = tu::getArrayElementType(dstPtrType);
3✔
302
    }
3✔
303

304
    typeId = getOrRegisterType(dstPtrType, dl);
405✔
305
    if (typeId == TYPEART_UNKNOWN_TYPE) {
405✔
306
      LOG_ERROR("Target type of casted allocation is unknown. Not instrumenting. " << util::dump(*malloc_call));
3✔
307
      LOG_ERROR("Cast: " << util::dump(*primaryBitcast));
3✔
308
      LOG_ERROR("Target type: " << util::dump(*dstPtrType));
3✔
309
    }
3✔
310
  } else {
405✔
311
    LOG_WARNING("Primary bitcast is null. malloc: " << util::dump(*malloc_call))
54✔
312
  }
313
  return {typeId, 0};
459✔
314
}
459✔
315

316
TypeIdentifier TypeManager::getOrRegisterType(const AllocaData& adata) {
2,966✔
317
  auto alloca                = adata.alloca;
2,966✔
318
  const llvm::DataLayout& dl = alloca->getModule()->getDataLayout();
2,966✔
319
  Type* elementType          = alloca->getAllocatedType();
2,966✔
320

321
  auto arraySize = adata.array_size == 0 ? 1 : adata.array_size;
2,966✔
322
  if (elementType->isArrayTy()) {
2,966✔
323
    arraySize   = arraySize * tu::getArrayLengthFlattened(elementType);
106✔
324
    elementType = tu::getArrayElementType(elementType);
106✔
325
  }
106✔
326

327
  int typeId = getOrRegisterType(elementType, dl);
2,966✔
328

329
  return {typeId, arraySize};
2,966✔
330
}
331

332
TypeIdentifier TypeManager::getOrRegisterType(const GlobalData& gdata) {
1,767✔
333
  auto global                = gdata.global;
1,767✔
334
  const llvm::DataLayout& dl = global->getParent()->getDataLayout();
1,767✔
335
  auto type                  = global->getValueType();
1,767✔
336

337
  size_t num_elements{1};
1,767✔
338
  if (type->isArrayTy()) {
1,767✔
339
    num_elements = tu::getArrayLengthFlattened(type);
1,625✔
340
    type         = tu::getArrayElementType(type);
1,625✔
341
  }
1,625✔
342

343
  int typeId = getOrRegisterType(type, dl);
1,767✔
344
  return {typeId, num_elements};
1,767✔
345
}
346

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