Jlm
Loading...
Searching...
No Matches
types.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
8#include <jlm/util/Hash.hpp>
9#include <jlm/util/Math.hpp>
10#include <jlm/util/strfmt.hpp>
11
12#include <numeric>
13#include <unordered_map>
14
15namespace jlm::llvm
16{
17
18PointerType::~PointerType() noexcept = default;
19
20std::string
21PointerType::debug_string() const
22{
23 return "ptr";
24}
25
26bool
27PointerType::operator==(const jlm::rvsdg::Type & other) const noexcept
28{
29 return jlm::rvsdg::is<PointerType>(other);
30}
31
32std::size_t
34{
35 return typeid(PointerType).hash_code();
36}
37
39PointerType::Kind() const noexcept
40{
42}
43
44std::shared_ptr<const PointerType>
46{
47 static const PointerType instance;
48 return std::shared_ptr<const PointerType>(std::shared_ptr<void>(), &instance);
49}
50
51ArrayType::~ArrayType() noexcept = default;
52
53std::string
54ArrayType::debug_string() const
55{
56 return util::strfmt("[ ", nelements(), " x ", type_->debug_string(), " ]");
57}
58
59bool
60ArrayType::operator==(const Type & other) const noexcept
61{
62 const auto type = dynamic_cast<const ArrayType *>(&other);
63 return type && type->element_type() == element_type() && type->nelements() == nelements();
64}
65
66std::size_t
67ArrayType::ComputeHash() const noexcept
68{
69 const auto typeHash = typeid(ArrayType).hash_code();
70 const auto numElementsHash = std::hash<std::size_t>()(nelements_);
71 return util::CombineHashes(typeHash, type_->ComputeHash(), numElementsHash);
72}
73
75ArrayType::Kind() const noexcept
76{
78}
79
80FloatingPointType::~FloatingPointType() noexcept = default;
81
82std::string
83FloatingPointType::debug_string() const
84{
85 static std::unordered_map<fpsize, std::string> map({ { fpsize::half, "half" },
86 { fpsize::flt, "float" },
87 { fpsize::dbl, "double" },
88 { fpsize::x86fp80, "x86fp80" },
89 { fpsize::fp128, "fp128" } });
90
91 JLM_ASSERT(map.find(size()) != map.end());
92 return map[size()];
93}
94
95bool
96FloatingPointType::operator==(const Type & other) const noexcept
97{
98 const auto type = dynamic_cast<const FloatingPointType *>(&other);
99 return type && type->size() == size();
100}
101
102std::size_t
104{
105 const auto typeHash = typeid(FloatingPointType).hash_code();
106 const auto sizeHash = std::hash<fpsize>()(size_);
107 return util::CombineHashes(typeHash, sizeHash);
108}
109
112{
114}
115
116std::shared_ptr<const FloatingPointType>
118{
119 switch (size)
120 {
121 case fpsize::half:
122 {
123 static const FloatingPointType instance(fpsize::half);
124 return std::shared_ptr<const FloatingPointType>(std::shared_ptr<void>(), &instance);
125 }
126 case fpsize::flt:
127 {
128 static const FloatingPointType instance(fpsize::flt);
129 return std::shared_ptr<const FloatingPointType>(std::shared_ptr<void>(), &instance);
130 }
131 case fpsize::dbl:
132 {
133 static const FloatingPointType instance(fpsize::dbl);
134 return std::shared_ptr<const FloatingPointType>(std::shared_ptr<void>(), &instance);
135 }
136 case fpsize::x86fp80:
137 {
138 static const FloatingPointType instance(fpsize::x86fp80);
139 return std::shared_ptr<const FloatingPointType>(std::shared_ptr<void>(), &instance);
140 }
141 case fpsize::fp128:
142 {
143 static const FloatingPointType instance(fpsize::fp128);
144 return std::shared_ptr<const FloatingPointType>(std::shared_ptr<void>(), &instance);
145 }
146 default:
147 {
148 JLM_UNREACHABLE("unknown fpsize");
149 }
150 }
151}
152
154
155bool
156VariableArgumentType::operator==(const Type & other) const noexcept
157{
158 return dynamic_cast<const VariableArgumentType *>(&other) != nullptr;
159}
160
161std::size_t
163{
164 return typeid(VariableArgumentType).hash_code();
165}
166
169{
171}
172
173std::string
175{
176 return "vararg";
177}
178
179std::shared_ptr<const VariableArgumentType>
181{
182 static const VariableArgumentType instance;
183 return std::shared_ptr<const VariableArgumentType>(std::shared_ptr<void>(), &instance);
184}
185
186StructType::~StructType() noexcept = default;
187
188bool
189StructType::operator==(const Type & other) const noexcept
190{
191 const auto type = dynamic_cast<const StructType *>(&other);
192 if (!type || type->isPacked_ != isPacked_ || type->isLiteral_ != isLiteral_
193 || type->name_ != name_ || type->numElements() != numElements())
194 return false;
195
196 for (size_t n = 0; n < numElements(); n++)
197 {
198 if (*types_[n] != *type->types_[n])
199 return false;
200 }
201
202 return true;
203}
204
205std::size_t
207{
208 const auto typeHash = typeid(StructType).hash_code();
209 const auto isLiteralHash = std::hash<bool>()(isLiteral_);
210 const auto isPackedHash = std::hash<bool>()(isPacked_);
211 const auto nameHash = std::hash<std::string>()(name_);
212
213 auto hash = util::CombineHashes(typeHash, isLiteralHash, isPackedHash, nameHash);
214 for (auto & type : types_)
215 {
216 hash = util::CombineHashes(hash, type->ComputeHash());
217 }
218
219 return hash;
220}
221
223StructType::Kind() const noexcept
224{
226}
227
228std::string
230{
231 return "struct";
232}
233
234size_t
235StructType::GetFieldOffset(size_t fieldIndex) const
236{
237 const auto isPacked = IsPacked();
238
239 size_t offset = 0;
240
241 for (size_t i = 0; i < numElements(); i++)
242 {
243 auto field = getElementType(i);
244
245 // First round up to the alignment of the field
246 auto fieldAlignment = isPacked ? 1 : GetTypeAlignment(*field);
247 offset = util::RoundUpToMultipleOf(offset, fieldAlignment);
248
249 if (i == fieldIndex)
250 return offset;
251
252 // Add the size of the field
253 offset += GetTypeAllocSize(*field);
254 }
255
256 JLM_UNREACHABLE("Invalid fieldIndex in GetStructFieldOffset");
257}
258
259bool
260VectorType::operator==(const rvsdg::Type & other) const noexcept
261{
262 const auto type = dynamic_cast<const VectorType *>(&other);
263 return type && type->size_ == size_ && *type->type_ == *type_;
264}
265
267VectorType::Kind() const noexcept
268{
270}
271
272FixedVectorType::~FixedVectorType() noexcept = default;
273
274bool
275FixedVectorType::operator==(const jlm::rvsdg::Type & other) const noexcept
276{
277 return VectorType::operator==(other);
278}
279
280std::size_t
282{
283 auto typeHash = typeid(FixedVectorType).hash_code();
284 auto sizeHash = std::hash<size_t>()(size());
285 return util::CombineHashes(typeHash, sizeHash, Type()->ComputeHash());
286}
287
288std::string
290{
291 return util::strfmt("fixedvector[", type().debug_string(), ":", size(), "]");
292}
293
294ScalableVectorType::~ScalableVectorType() noexcept = default;
295
296bool
297ScalableVectorType::operator==(const jlm::rvsdg::Type & other) const noexcept
298{
299 return VectorType::operator==(other);
300}
301
302std::size_t
304{
305 const auto typeHash = typeid(ScalableVectorType).hash_code();
306 const auto sizeHash = std::hash<size_t>()(size());
307 return util::CombineHashes(typeHash, sizeHash, Type()->ComputeHash());
308}
309
310std::string
312{
313 return util::strfmt("scalablevector[", type().debug_string(), ":", size(), "]");
314}
315
316IOStateType::~IOStateType() noexcept = default;
317
318bool
319IOStateType::operator==(const Type & other) const noexcept
320{
321 return jlm::rvsdg::is<IOStateType>(other);
322}
323
324std::size_t
326{
327 return typeid(IOStateType).hash_code();
328}
329
331IOStateType::Kind() const noexcept
332{
334}
335
336std::string
338{
339 return "iostate";
340}
341
342std::shared_ptr<const IOStateType>
344{
345 static const IOStateType instance;
346 return std::shared_ptr<const IOStateType>(std::shared_ptr<void>(), &instance);
347}
348
352MemoryStateType::~MemoryStateType() noexcept = default;
353
354std::string
355MemoryStateType::debug_string() const
356{
357 return "mem";
358}
359
360bool
362{
364}
365
366std::size_t
368{
369 return typeid(MemoryStateType).hash_code();
370}
371
373MemoryStateType::Kind() const noexcept
374{
376}
377
378std::shared_ptr<const MemoryStateType>
380{
381 static const MemoryStateType instance;
382 return std::shared_ptr<const MemoryStateType>(std::shared_ptr<void>(), &instance);
383}
384
385size_t
387{
388 if (const auto bits = dynamic_cast<const rvsdg::BitType *>(&type))
389 {
390 // Assume 8 bits per byte, and round up to nearest whole byte
391 const auto bytes = (bits->nbits() + 7) / 8;
392 return bytes;
393 }
395 {
396 // FIXME: Use the target information in the module to find the actual size of pointers
397 return 8;
398 }
399 if (const auto arrayType = dynamic_cast<const ArrayType *>(&type))
400 {
401 return arrayType->nelements() * GetTypeAllocSize(*arrayType->GetElementType());
402 }
403 if (const auto floatType = dynamic_cast<const FloatingPointType *>(&type))
404 {
405 switch (floatType->size())
406 {
407 case fpsize::half:
408 return 2;
409 case fpsize::flt:
410 return 4;
411 case fpsize::dbl:
412 return 8;
413 case fpsize::fp128:
414 return 16;
415 case fpsize::x86fp80:
416 return 10;
417 default:
418 JLM_UNREACHABLE("Unknown float size");
419 }
420 }
421 if (const auto structType = dynamic_cast<const StructType *>(&type))
422 {
423 size_t totalSize = 0;
424 size_t alignment = 1;
425
426 // A packed struct has alignment 1, and all fields are tightly packed
427 const auto isPacked = structType->IsPacked();
428
429 for (size_t i = 0; i < structType->numElements(); i++)
430 {
431 auto field = structType->getElementType(i);
432
433 // Note: It is correct to use the TypeAllocSize here.
434 // An unpacked LLVM struct { i8, i33, i8 } takes up 24 bytes in store size.
435 // Even in a packed struct <{ i8, i33, i8 }>, it still takes up 10 bytes.
436 auto fieldSize = GetTypeAllocSize(*field);
437 auto fieldAlignment = isPacked ? 1 : GetTypeAlignment(*field);
438
439 // First add any padding needed to align the start of the field
440 totalSize = util::RoundUpToMultipleOf(totalSize, fieldAlignment);
441 // Add the size of the field
442 totalSize += fieldSize;
443
444 // The struct as a whole must be at least as aligned as each field
445 alignment = std::lcm(alignment, fieldAlignment);
446 }
447
448 // Round size up to a multiple of alignment
449 totalSize = util::RoundUpToMultipleOf(totalSize, alignment);
450
451 // If the struct has 0 fields, its size becomes 0.
452 // In C++, where types of size 0 are forbidden, clang will have inserted a dummy i8 field.
453
454 return totalSize;
455 }
456 if (const auto vectorType = dynamic_cast<const VectorType *>(&type))
457 {
458 // In LLVM, vectors always have alignment >= the number of bytes of data stored in the vector
459 const auto bytesNeeded = vectorType->size() * GetTypeAllocSize(*vectorType->Type());
460 return bytesNeeded;
461 }
463 {
464 // Functions should never read from or written to, so give them size 0
465 // Note: this is not the same as a function pointer, which is a PointerType
466 return 0;
467 }
468
469 JLM_UNREACHABLE(util::strfmt("Unknown type: ", typeid(type).name()).c_str());
470}
471
472size_t
474{
476 {
477 // These types already have aligned store size, so skip calculating alignment
478 return GetTypeStoreSize(type);
479 }
480
482}
483
484size_t
486{
489 {
490 // These types all have alignment equal to their byte size, rounded up to a power of two
492 }
493 if (const auto arrayType = dynamic_cast<const ArrayType *>(&type))
494 {
495 return GetTypeAlignment(*arrayType->GetElementType());
496 }
497 if (const auto structType = dynamic_cast<const StructType *>(&type))
498 {
499 // A packed struct has alignment 1, and all fields are tightly packed
500 if (structType->IsPacked())
501 return 1;
502
503 size_t alignment = 1;
504
505 for (size_t i = 0; i < structType->numElements(); i++)
506 {
507 auto field = structType->getElementType(i);
508 auto fieldAlignment = GetTypeAlignment(*field);
509
510 // The struct as a whole must be at least as aligned as each field
511 alignment = std::lcm(alignment, fieldAlignment);
512 }
513
514 return alignment;
515 }
517 {
518 // While the ABI might enforce some sort of function alignment,
519 // this is irrelevant to memory operations in the program or struct layouts
520 return 1;
521 }
522
523 JLM_UNREACHABLE("Unknown type");
524}
525
526}
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:75
const rvsdg::Type & element_type() const noexcept
Definition types.hpp:86
std::shared_ptr< const rvsdg::Type > type_
Definition types.hpp:105
std::size_t ComputeHash() const noexcept override
Definition types.cpp:67
~ArrayType() noexcept override
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition types.cpp:60
std::string debug_string() const override
Definition types.cpp:289
~FixedVectorType() noexcept override
std::size_t ComputeHash() const noexcept override
Definition types.cpp:281
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition types.cpp:96
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
~FloatingPointType() noexcept override
const fpsize & size() const noexcept
Definition types.hpp:141
std::size_t ComputeHash() const noexcept override
Definition types.cpp:103
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:111
Input/Output state type.
Definition types.hpp:449
constexpr IOStateType() noexcept=default
~IOStateType() noexcept override
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
std::string debug_string() const override
Definition types.cpp:337
std::size_t ComputeHash() const noexcept override
Definition types.cpp:325
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:331
Memory state type class.
Definition types.hpp:477
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:373
constexpr MemoryStateType() noexcept=default
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition types.cpp:361
~MemoryStateType() noexcept override
std::size_t ComputeHash() const noexcept override
Definition types.cpp:367
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
PointerType class.
Definition types.hpp:25
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
~PointerType() noexcept override
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition types.cpp:27
std::size_t ComputeHash() const noexcept override
Definition types.cpp:33
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:39
std::string debug_string() const override
Definition types.cpp:311
std::size_t ComputeHash() const noexcept override
Definition types.cpp:303
~ScalableVectorType() noexcept override
StructType class.
Definition types.hpp:184
std::size_t ComputeHash() const noexcept override
Definition types.cpp:206
std::string debug_string() const override
Definition types.cpp:229
size_t numElements() const noexcept
Definition types.hpp:230
std::string name_
Definition types.hpp:341
std::shared_ptr< const Type > getElementType(const size_t index) const noexcept
Definition types.hpp:236
bool IsPacked() const noexcept
Definition types.hpp:273
std::vector< std::shared_ptr< const Type > > types_
Definition types.hpp:342
size_t GetFieldOffset(size_t fieldIndex) const
Definition types.cpp:235
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:223
~StructType() noexcept override
~VariableArgumentType() noexcept override
std::size_t ComputeHash() const noexcept override
Definition types.cpp:162
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:168
std::string debug_string() const override
Definition types.cpp:174
constexpr VariableArgumentType()=default
static std::shared_ptr< const VariableArgumentType > Create()
Definition types.cpp:180
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition types.cpp:260
size_t size() const noexcept
Definition types.hpp:372
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition types.cpp:267
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition types.hpp:384
const rvsdg::Type & type() const noexcept
Definition types.hpp:378
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
Global memory state passed between functions.
size_t GetTypeAlignment(const rvsdg::Type &type)
Definition types.cpp:485
size_t GetTypeAllocSize(const rvsdg::Type &type)
Definition types.cpp:473
size_t GetTypeStoreSize(const rvsdg::Type &type)
Definition types.cpp:386
TypeKind
The kinds of types supported in rvsdg.
Definition type.hpp:22
@ State
Designate a state type.
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35
static constexpr T RoundUpToMultipleOf(T value, T multiple)
Definition Math.hpp:75
static constexpr T RoundUpToPowerOf2(T value)
Definition Math.hpp:51
std::size_t CombineHashes(std::size_t hash, Args... args)
Definition Hash.hpp:63