Enzyme main
Loading...
Searching...
No Matches
TypeTree.h
Go to the documentation of this file.
1//===- TypeTree.cpp - Declaration of Type Analysis Type Trees -----------===//
2//
3// Enzyme Project
4//
5// Part of the Enzyme Project, under the Apache License v2.0 with LLVM
6// Exceptions. See https://llvm.org/LICENSE.txt for license information.
7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8//
9// If using this code in an academic setting, please cite the following:
10// @incollection{enzymeNeurips,
11// title = {Instead of Rewriting Foreign Code for Machine Learning,
12// Automatically Synthesize Fast Gradients},
13// author = {Moses, William S. and Churavy, Valentin},
14// booktitle = {Advances in Neural Information Processing Systems 33},
15// year = {2020},
16// note = {To appear in},
17// }
18//
19//===----------------------------------------------------------------------===//
20//
21// This file contains the declaration of TypeTrees -- a class
22// representing all of the underlying types of a particular LLVM value. This
23// consists of a map of memory offsets to an underlying ConcreteType. This
24// permits TypeTrees to represent distinct underlying types at different
25// locations. Presently, TypeTree's have both a fixed depth of memory lookups
26// and a maximum offset to ensure that Type Analysis eventually terminates.
27// In the future this should be modified to better represent recursive types
28// rather than limiting the depth.
29//
30//===----------------------------------------------------------------------===//
31#ifndef ENZYME_TYPE_ANALYSIS_TYPE_TREE_H
32#define ENZYME_TYPE_ANALYSIS_TYPE_TREE_H 1
33
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/raw_ostream.h"
36#include <map>
37#include <set>
38#include <string>
39#include <vector>
40
41#include "../Utils.h"
42#include "BaseType.h"
43#include "ConcreteType.h"
44
45/// Maximum offset for type trees to keep
46extern "C" {
47extern llvm::cl::opt<int> MaxTypeOffset;
48extern llvm::cl::opt<bool> EnzymeTypeWarning;
49extern llvm::cl::opt<unsigned> EnzymeMaxTypeDepth;
50}
51
52/// Helper function to print a vector of ints to a string
53static inline std::string to_string(const std::vector<int> x) {
54 std::string out = "[";
55 for (unsigned i = 0; i < x.size(); ++i) {
56 if (i != 0)
57 out += ",";
58 out += std::to_string(x[i]);
59 }
60 out += "]";
61 return out;
62}
63
64class TypeTree;
65
66typedef std::shared_ptr<const TypeTree> TypeResult;
67typedef std::map<const std::vector<int>, ConcreteType> ConcreteTypeMapType;
68typedef std::map<const std::vector<int>, const TypeResult> TypeTreeMapType;
69
70/// Class representing the underlying types of values as
71/// sequences of offsets to a ConcreteType
72class TypeTree : public std::enable_shared_from_this<TypeTree> {
73private:
74 // mapping of known indices to type if one exists
75 ConcreteTypeMapType mapping;
76 std::vector<int> minIndices;
77
78public:
81 if (dat != ConcreteType(BaseType::Unknown)) {
82 mapping.insert(std::pair<const std::vector<int>, ConcreteType>({}, dat));
83 }
84 }
85
86 static TypeTree parse(llvm::StringRef str, llvm::LLVMContext &ctx) {
87 using namespace llvm;
88 assert(str[0] == '{');
89 str = str.substr(1);
90
91 TypeTree Result;
92 while (true) {
93 while (str[0] == ' ')
94 str = str.substr(1);
95 if (str[0] == '}')
96 break;
97
98 assert(str[0] == '[');
99 str = str.substr(1);
100
101 std::vector<int> idxs;
102 while (true) {
103 while (str[0] == ' ')
104 str = str.substr(1);
105 if (str[0] == ']') {
106 str = str.substr(1);
107 break;
108 }
109
110 int idx;
111 bool failed = str.consumeInteger(10, idx);
112 (void)failed;
113 assert(!failed);
114 idxs.push_back(idx);
115
116 while (str[0] == ' ')
117 str = str.substr(1);
118
119 if (str[0] == ',') {
120 str = str.substr(1);
121 }
122 }
123
124 while (str[0] == ' ')
125 str = str.substr(1);
126
127 assert(str[0] == ':');
128 str = str.substr(1);
129
130 while (str[0] == ' ')
131 str = str.substr(1);
132
133 auto endval = str.find(',');
134 auto endval2 = str.find('}');
135 auto endval3 = str.find(' ');
136
137 if (endval2 != StringRef::npos &&
138 (endval == StringRef::npos || endval2 < endval))
139 endval = endval2;
140 if (endval3 != StringRef::npos &&
141 (endval == StringRef::npos || endval3 < endval))
142 endval = endval3;
143 assert(endval != StringRef::npos);
144
145 auto tystr = str.substr(0, endval);
146 str = str.substr(endval);
147
148 ConcreteType CT(tystr, ctx);
149 Result.mapping.emplace(idxs, CT);
150 if (Result.minIndices.size() < idxs.size()) {
151 for (size_t i = Result.minIndices.size(), end = idxs.size(); i < end;
152 ++i) {
153 Result.minIndices.push_back(idxs[i]);
154 }
155 }
156 for (size_t i = 0, end = idxs.size(); i < end; ++i) {
157 if (idxs[i] < Result.minIndices[i])
158 Result.minIndices[i] = idxs[i];
159 }
160
161 while (str[0] == ' ')
162 str = str.substr(1);
163
164 if (str[0] == ',') {
165 str = str.substr(1);
166 }
167 }
168
169 return Result;
170 }
171
172 /// Utility helper to lookup the mapping
173 const ConcreteTypeMapType &getMapping() const { return mapping; }
174
175 /// Lookup the underlying ConcreteType at a given offset sequence
176 /// or Unknown if none exists
177 ConcreteType operator[](const std::vector<int> Seq) const {
178 auto Found0 = mapping.find(Seq);
179 if (Found0 != mapping.end())
180 return Found0->second;
181 size_t Len = Seq.size();
182 if (Len == 0)
183 return BaseType::Unknown;
184
185 std::vector<std::vector<int>> todo[2];
186 todo[0].push_back({});
187 int parity = 0;
188 for (size_t i = 0, Len = Seq.size(); i < Len - 1; ++i) {
189 for (auto prev : todo[parity]) {
190 prev.push_back(-1);
191 if (mapping.find(prev) != mapping.end())
192 todo[1 - parity].push_back(prev);
193 if (Seq[i] != -1) {
194 prev.back() = Seq[i];
195 if (mapping.find(prev) != mapping.end())
196 todo[1 - parity].push_back(prev);
197 }
198 }
199 todo[parity].clear();
200 parity = 1 - parity;
201 }
202
203 size_t i = Len - 1;
204 for (auto prev : todo[parity]) {
205 prev.push_back(-1);
206 auto Found = mapping.find(prev);
207 if (Found != mapping.end())
208 return Found->second;
209 if (Seq[i] != -1) {
210 prev.back() = Seq[i];
211 Found = mapping.find(prev);
212 if (Found != mapping.end())
213 return Found->second;
214 }
215 }
216 return BaseType::Unknown;
217 }
218
219 // Return true if this type tree is fully known (i.e. there
220 // is no more information which could be added).
221 bool IsFullyDetermined() const {
222 std::vector<int> offsets = {-1};
223 while (1) {
224 auto found = mapping.find(offsets);
225 if (found == mapping.end())
226 return false;
227 if (found->second != BaseType::Pointer)
228 return true;
229 offsets.push_back(-1);
230 }
231 }
232
233 /// Return if changed
234 bool insert(const std::vector<int> Seq, ConcreteType CT,
235 bool PointerIntSame = false) {
236 size_t SeqSize = Seq.size();
237 if (SeqSize > EnzymeMaxTypeDepth) {
238 if (EnzymeTypeWarning) {
239 if (CustomErrorHandler) {
240 CustomErrorHandler("TypeAnalysisDepthLimit", nullptr,
241 ErrorType::TypeDepthExceeded, this, nullptr,
242 nullptr);
243 } else
244 llvm::errs() << "not handling more than " << EnzymeMaxTypeDepth
245 << " pointer lookups deep dt:" << str()
246 << " adding v: " << to_string(Seq) << ": " << CT.str()
247 << "\n";
248 }
249 return false;
250 }
251 if (SeqSize == 0) {
252 mapping.insert(std::pair<const std::vector<int>, ConcreteType>(Seq, CT));
253 return true;
254 }
255
256 // check types at lower pointer offsets are either pointer or
257 // anything. Don't insert into an anything
258 {
259 std::vector<int> tmp(Seq);
260 while (tmp.size() > 0) {
261 tmp.erase(tmp.end() - 1);
262 auto found = mapping.find(tmp);
263 if (found != mapping.end()) {
264 if (found->second == BaseType::Anything)
265 return false;
266 if (found->second != BaseType::Pointer) {
267 llvm::errs() << "FAILED CT: " << str()
268 << " adding Seq: " << to_string(Seq) << ": "
269 << CT.str() << "\n";
270 }
271 assert(found->second == BaseType::Pointer);
272 }
273 }
274 }
275
276 bool changed = false;
277 // Check if there is an existing match, e.g. [-1, -1, -1] and inserting
278 // [-1, 8, -1]
279 {
280 for (const auto &pair : llvm::make_early_inc_range(mapping)) {
281 if (pair.first.size() == SeqSize) {
282 // Whether the the inserted val (e.g. [-1, 0] or [0, 0]) is at least
283 // as general as the existing map val (e.g. [0, 0]).
284 bool newMoreGeneralThanOld = true;
285 // Whether the the existing val (e.g. [-1, 0] or [0, 0]) is at least
286 // as general as the inserted map val (e.g. [0, 0]).
287 bool oldMoreGeneralThanNew = true;
288 for (unsigned i = 0; i < SeqSize; i++) {
289 if (pair.first[i] == Seq[i])
290 continue;
291 if (Seq[i] == -1) {
292 oldMoreGeneralThanNew = false;
293 } else if (pair.first[i] == -1) {
294 newMoreGeneralThanOld = false;
295 } else {
296 oldMoreGeneralThanNew = false;
297 newMoreGeneralThanOld = false;
298 break;
299 }
300 }
301
302 if (oldMoreGeneralThanNew) {
303 // Inserting an existing or less general version
304 if (CT == pair.second)
305 return false;
306
307 // Inserting an existing or less general version (with pointer-int
308 // equivalence)
309 if (PointerIntSame)
310 if ((CT == BaseType::Pointer &&
311 pair.second == BaseType::Integer) ||
312 (CT == BaseType::Integer && pair.second == BaseType::Pointer))
313 return false;
314
315 // Inserting into an anything. Since from above we know this is not
316 // an anything, the inserted value contains no new information
317 if (pair.second == BaseType::Anything)
318 return false;
319
320 // Inserting say a [0]:anything into a [-1]:Float
321 if (CT == BaseType::Anything)
322 continue;
323
324 // Otherwise, inserting a non-equivalent pair into a more general
325 // slot. This is invalid.
326 llvm::errs() << "inserting into : " << str() << " with "
327 << to_string(Seq) << " of " << CT.str() << "\n";
328 llvm_unreachable("illegal insertion");
329 } else if (newMoreGeneralThanOld) {
330 // This new is strictly more general than the old. If they were
331 // equivalent, the case above would have been hit.
332
333 if (CT == BaseType::Anything || CT == pair.second) {
334 // previous equivalent values or values overwritten by
335 // an anything are removed
336 changed = true;
337 mapping.erase(pair.first);
338 continue;
339 }
340
341 // Inserting an existing or less general version (with pointer-int
342 // equivalence)
343 if (PointerIntSame)
344 if ((CT == BaseType::Pointer &&
345 pair.second == BaseType::Integer) ||
346 (CT == BaseType::Integer &&
347 pair.second == BaseType::Pointer)) {
348 changed = true;
349 mapping.erase(pair.first);
350 continue;
351 }
352
353 // Keep lingering anythings if not being overwritten, even if this
354 // (e.g. Float) applies to more locations. Therefore it is legal to
355 // have [-1]:Float, [8]:Anything
356 if (CT != BaseType::Anything && pair.second == BaseType::Anything)
357 continue;
358
359 // Otherwise, inserting a more general non-equivalent pair. This is
360 // invalid.
361 llvm::errs() << "inserting into : " << str() << " with "
362 << to_string(Seq) << " of " << CT.str() << "\n";
363 llvm_unreachable("illegal insertion");
364 }
365 }
366 }
367 }
368
369 bool possibleDeletion = false;
370 size_t minLen =
371 (minIndices.size() <= SeqSize) ? minIndices.size() : SeqSize;
372 for (size_t i = 0; i < minLen; i++) {
373 if (minIndices[i] > Seq[i]) {
374 if (minIndices[i] > MaxTypeOffset)
375 possibleDeletion = true;
376 minIndices[i] = Seq[i];
377 }
378 }
379
380 if (minIndices.size() < SeqSize) {
381 for (size_t i = minIndices.size(), end = SeqSize; i < end; ++i) {
382 minIndices.push_back(Seq[i]);
383 }
384 }
385
386 if (possibleDeletion) {
387 for (const auto &pair : llvm::make_early_inc_range(mapping)) {
388 size_t i = 0;
389 bool mustKeep = false;
390 bool considerErase = false;
391 for (int val : pair.first) {
392 if (val > MaxTypeOffset) {
393 if (val == minIndices[i]) {
394 mustKeep = true;
395 break;
396 }
397 considerErase = true;
398 }
399 ++i;
400 }
401 if (!mustKeep && considerErase) {
402 mapping.erase(pair.first);
403 changed = true;
404 }
405 }
406 }
407
408 size_t i = 0;
409 bool keep = false;
410 bool considerErase = false;
411 for (auto val : Seq) {
412 if (val > MaxTypeOffset) {
413 if (val == minIndices[i]) {
414 keep = true;
415 break;
416 }
417 considerErase = true;
418 }
419 i++;
420 }
421 if (considerErase && !keep)
422 return changed;
423 mapping.insert(std::pair<const std::vector<int>, ConcreteType>(Seq, CT));
424 return true;
425 }
426
427 /// How this TypeTree compares with another
428 bool operator<(const TypeTree &vd) const { return mapping < vd.mapping; }
429
430 /// Whether this TypeTree contains any information
431 bool isKnown() const {
432#ifndef NDEBUG
433 for (const auto &pair : mapping) {
434 // we should assert here as we shouldn't keep any unknown maps for
435 // efficiency
436 assert(pair.second.isKnown());
437 }
438#endif
439 return mapping.size() != 0;
440 }
441
442 /// Whether this TypeTree knows any non-pointer information
443 bool isKnownPastPointer() const {
444 for (auto &pair : mapping) {
445 // we should assert here as we shouldn't keep any unknown maps for
446 // efficiency
447 assert(pair.second.isKnown());
448 if (pair.first.size() == 0) {
449 assert(pair.second == BaseType::Pointer ||
450 pair.second == BaseType::Anything);
451 continue;
452 }
453 return true;
454 }
455 return false;
456 }
457
458 /// Select only the Integer ConcreteTypes
460 TypeTree vd;
461 for (auto &pair : mapping) {
462 if (pair.second == BaseType::Integer) {
463 vd.insert(pair.first, pair.second);
464 }
465 }
466
467 return vd;
468 }
469
470 /// Prepend an offset to all mappings
471 TypeTree Only(int Off, llvm::Instruction *orig) const {
472 TypeTree Result;
473 Result.minIndices.reserve(1 + minIndices.size());
474 Result.minIndices.push_back(Off);
475 for (auto midx : minIndices)
476 Result.minIndices.push_back(midx);
477
478 if (Result.minIndices.size() > EnzymeMaxTypeDepth) {
479 Result.minIndices.pop_back();
480 if (EnzymeTypeWarning) {
481 if (CustomErrorHandler) {
482 CustomErrorHandler("TypeAnalysisDepthLimit", wrap(orig),
483 ErrorType::TypeDepthExceeded, this, nullptr,
484 nullptr);
485 } else if (orig) {
486 EmitWarning("TypeAnalysisDepthLimit", *orig, *orig,
487 " not handling more than ", EnzymeMaxTypeDepth,
488 " pointer lookups deep dt: ", str(), " only(", Off, ")");
489 } else {
490 llvm::errs() << "not handling more than " << EnzymeMaxTypeDepth
491 << " pointer lookups deep dt:" << str() << " only("
492 << Off << "): "
493 << "\n";
494 }
495 }
496 }
497
498 for (const auto &pair : mapping) {
499 if (pair.first.size() == EnzymeMaxTypeDepth)
500 continue;
501 std::vector<int> Vec;
502 Vec.reserve(pair.first.size() + 1);
503 Vec.push_back(Off);
504 for (auto Val : pair.first)
505 Vec.push_back(Val);
506 Result.mapping.insert(
507 std::pair<const std::vector<int>, ConcreteType>(Vec, pair.second));
508 }
509 return Result;
510 }
511
512 /// Peel off the outermost index at offset 0
513 TypeTree Data0() const {
514 TypeTree Result;
515
516 for (const auto &pair : mapping) {
517 if (pair.first.size() == 0) {
518 llvm::errs() << str() << "\n";
519 }
520 assert(pair.first.size() != 0);
521
522 if (pair.first[0] == -1) {
523 std::vector<int> next(pair.first.begin() + 1, pair.first.end());
524 Result.mapping.insert(
525 std::pair<const std::vector<int>, ConcreteType>(next, pair.second));
526 for (size_t i = 0, Len = next.size(); i < Len; ++i) {
527 if (i == Result.minIndices.size())
528 Result.minIndices.push_back(next[i]);
529 else if (next[i] < Result.minIndices[i])
530 Result.minIndices[i] = next[i];
531 }
532 }
533 }
534 for (const auto &pair : mapping) {
535 if (pair.first[0] == 0) {
536 std::vector<int> next(pair.first.begin() + 1, pair.first.end());
537 // We do insertion like this to force an error
538 // on the orIn operation if there is an incompatible
539 // merge. The insert operation does not error.
540 Result.orIn(next, pair.second);
541 }
542 }
543
544 return Result;
545 }
546
547 /// Optimized version of Data0()[{}]
549 ConcreteType CT = operator[]({-1});
550 CT |= operator[]({0});
551 return CT;
552 }
553
554 /// Remove any mappings in the range [start, end) or [len, inf)
555 /// This function has special handling for -1's
556 TypeTree Clear(size_t start, size_t end, size_t len) const {
557 TypeTree Result;
558
559 // Note that below do insertion with the orIn operator
560 // to force an error if there is an incompatible
561 // merge. The insert operation does not error.
562
563 for (const auto &pair : mapping) {
564 assert(pair.first.size() != 0);
565
566 if (pair.first[0] == -1) {
567 // For "all index" calculations, explicitly
568 // add mappings for regions in range
569 auto next = pair.first;
570 for (size_t i = 0; i < start; ++i) {
571 next[0] = i;
572 Result.orIn(next, pair.second);
573 }
574 for (size_t i = end; i < len; ++i) {
575 next[0] = i;
576 Result.orIn(next, pair.second);
577 }
578 } else if ((size_t)pair.first[0] < start ||
579 ((size_t)pair.first[0] >= end &&
580 (size_t)pair.first[0] < len)) {
581 // Otherwise simply check that the given offset is in range
582
583 Result.insert(pair.first, pair.second);
584 }
585 }
586
587 // TODO canonicalize this
588 return Result;
589 }
590
591 /// Select all submappings whose first index is in range [0, len) and remove
592 /// the first index. This is the inverse of the `Only` operation
593 TypeTree Lookup(size_t len, const llvm::DataLayout &dl) const {
594
595 // Map of indices[1:] => ( End => possible Index[0] )
596 std::map<std::vector<int>, std::map<ConcreteType, std::set<int>>> staging;
597
598 for (const auto &pair : mapping) {
599 assert(pair.first.size() != 0);
600
601 // Pointer is at offset 0 from this object
602 if (pair.first[0] != 0 && pair.first[0] != -1)
603 continue;
604
605 if (pair.first.size() == 1) {
606 assert(pair.second == ConcreteType(BaseType::Pointer) ||
607 pair.second == ConcreteType(BaseType::Anything));
608 continue;
609 }
610
611 if (pair.first[1] == -1) {
612 } else {
613 if ((size_t)pair.first[1] >= len)
614 continue;
615 }
616
617 std::vector<int> next(pair.first.begin() + 2, pair.first.end());
618
619 staging[next][pair.second].insert(pair.first[1]);
620 }
621
622 TypeTree Result;
623 for (auto &pair : staging) {
624 auto &pnext = pair.first;
625 for (auto &pair2 : pair.second) {
626 auto dt = pair2.first;
627 const auto &set = pair2.second;
628
629 bool legalCombine = set.count(-1);
630
631 // See if we can canonicalize the outermost index into a -1
632 if (!legalCombine) {
633 size_t chunk = 1;
634 // Implicit pointer
635 if (pnext.size() > 0) {
636 chunk = dl.getPointerSizeInBits() / 8;
637 } else {
638 if (auto flt = dt.isFloat()) {
639 chunk = dl.getTypeSizeInBits(flt) / 8;
640 } else if (dt == BaseType::Pointer) {
641 chunk = dl.getPointerSizeInBits() / 8;
642 }
643 }
644
645 legalCombine = true;
646 for (size_t i = 0; i < len; i += chunk) {
647 if (!set.count(i)) {
648 legalCombine = false;
649 break;
650 }
651 }
652 }
653
654 std::vector<int> next;
655 next.reserve(pnext.size() + 1);
656 next.push_back(-1);
657 for (auto v : pnext)
658 next.push_back(v);
659
660 if (legalCombine) {
661 Result.insert(next, dt, /*intsAreLegalPointerSub*/ true);
662 } else {
663 for (auto e : set) {
664 next[0] = e;
665 Result.insert(next, dt);
666 }
667 }
668 }
669 }
670
671 return Result;
672 }
673
674 /// Given that this tree represents something of at most size len,
675 /// canonicalize this, creating -1's where possible
676 void CanonicalizeInPlace(size_t len, const llvm::DataLayout &dl) {
677 bool canonicalized = true;
678 for (const auto &pair : mapping) {
679 assert(pair.first.size() != 0);
680 if (pair.first[0] != -1) {
681 canonicalized = false;
682 break;
683 }
684 }
685 if (canonicalized)
686 return;
687
688 // Map of indices[1:] => ( End => possible Index[0] )
689 std::map<const std::vector<int>, std::map<ConcreteType, std::set<int>>>
690 staging;
691
692 for (const auto &pair : mapping) {
693
694 std::vector<int> next(pair.first.begin() + 1, pair.first.end());
695 if (pair.first[0] != -1) {
696 if ((size_t)pair.first[0] >= len) {
697 llvm::errs() << str() << "\n";
698 llvm::errs() << " canonicalizing " << len << "\n";
699 llvm::report_fatal_error("Canonicalization failed");
700 }
701 }
702 staging[next][pair.second].insert(pair.first[0]);
703 }
704
705 // TypeTree mappings which did not get combined
706 std::map<const std::vector<int>, ConcreteType> unCombinedToAdd;
707
708 // TypeTree mappings which did get combined into an outer -1
709 std::map<const std::vector<int>, ConcreteType> combinedToAdd;
710
711 for (const auto &pair : staging) {
712 auto &pnext = pair.first;
713 for (const auto &pair2 : pair.second) {
714 auto dt = pair2.first;
715 const auto &set = pair2.second;
716
717 bool legalCombine = false;
718
719 // See if we can canonicalize the outermost index into a -1
720 if (!set.count(-1)) {
721 size_t chunk = 1;
722 if (pnext.size() > 0) {
723 chunk = dl.getPointerSizeInBits() / 8;
724 } else {
725 if (auto flt = dt.isFloat()) {
726 chunk = dl.getTypeSizeInBits(flt) / 8;
727 } else if (dt == BaseType::Pointer) {
728 chunk = dl.getPointerSizeInBits() / 8;
729 }
730 }
731
732 legalCombine = true;
733 for (size_t i = 0; i < len; i += chunk) {
734 if (!set.count(i)) {
735 legalCombine = false;
736 break;
737 }
738 }
739 }
740
741 std::vector<int> next;
742 next.reserve(pnext.size() + 1);
743 next.push_back(-1);
744 for (auto v : pnext)
745 next.push_back(v);
746
747 if (legalCombine) {
748 combinedToAdd.emplace(next, dt);
749 } else {
750 for (auto e : set) {
751 next[0] = e;
752 unCombinedToAdd.emplace(next, dt);
753 }
754 }
755 }
756 }
757
758 // If we combined nothing, just return since there are no
759 // changes.
760 if (combinedToAdd.size() == 0) {
761 return;
762 }
763
764 // Non-combined ones do not conflict, since they were already in
765 // a TT which we can assume contained no conflicts.
766 mapping = std::move(unCombinedToAdd);
767 if (minIndices.size() > 0) {
768 minIndices[0] = -1;
769 }
770
771 // Fusing several terms into a minus one can create a conflict
772 // if the prior minus one was already in the map
773 // time, or also generated by fusion.
774 // E.g. {-1:Anything, [0]:Pointer} on 8 -> create a [-1]:Pointer
775 // which conflicts
776 // Alternatively [-1,-1,-1]:Pointer, and generated a [-1,0,-1] fusion
777 for (const auto &pair : combinedToAdd) {
778 insert(pair.first, pair.second);
779 }
780
781 return;
782 }
783
784 /// Keep only pointers (or anything's) to a repeated value (represented by -1)
785 TypeTree KeepMinusOne(bool &legal) const {
786 TypeTree dat;
787
788 for (const auto &pair : mapping) {
789
790 assert(pair.first.size() != 0);
791
792 // Pointer is at offset 0 from this object
793 if (pair.first[0] != 0 && pair.first[0] != -1)
794 continue;
795
796 if (pair.first.size() == 1) {
797 if (pair.second == BaseType::Pointer ||
798 pair.second == BaseType::Anything) {
799 dat.insert(pair.first, pair.second);
800 continue;
801 }
802 legal = false;
803 break;
804 }
805
806 if (pair.first[1] == -1) {
807 dat.insert(pair.first, pair.second);
808 }
809 }
810
811 return dat;
812 }
813
814 llvm::Type *IsAllFloat(const size_t size, const llvm::DataLayout &dl) const {
815 auto m1 = TypeTree::operator[]({-1});
816 if (auto FT = m1.isFloat())
817 return FT;
818
819 auto m0 = TypeTree::operator[]({0});
820
821 if (auto flt = m0.isFloat()) {
822 size_t chunk = dl.getTypeSizeInBits(flt) / 8;
823 for (size_t i = chunk; i < size; i += chunk) {
824 auto mx = TypeTree::operator[]({(int)i});
825 if (auto f2 = mx.isFloat()) {
826 if (f2 != flt)
827 return nullptr;
828 } else
829 return nullptr;
830 }
831 return flt;
832 } else {
833 return nullptr;
834 }
835 }
836
837 /// Replace mappings in the range in [offset, offset+maxSize] with those in
838 // [addOffset, addOffset + maxSize]. In other words, select all mappings in
839 // [offset, offset+maxSize] then add `addOffset`
840 TypeTree ShiftIndices(const llvm::DataLayout &dl, const int offset,
841 const int maxSize, size_t addOffset = 0) const {
842
843 // If we have no terms 1+ layer deep return the current result as a shift
844 // won't change anything. This also makes the latercode simpler as it
845 // can assume at least a first index exists.
846 if (minIndices.size() == 0)
847 return *this;
848
849 // If we have no size in return, simply return an empty type tree. Again
850 // this simplifies later code which can assume that a minus one expantion
851 // will always result in an added variable (which would not be the case
852 // on a size == 0).
853 if (maxSize == 0)
854 return TypeTree();
855
856 TypeTree Result;
857
858 // The normal orIn / insert methods do collision checking, which is slow
859 // (and presently O(n)). This is because an expansion of a -1 which could
860 // conflict with a fixed value. Consider calling this
861 // ShiftIndicies(offset=0, maxSize=2, addOffset=0, tt={[-1]:Integer,
862 // [1]:Anything}) the -1 would expand to [0]:Int, [1]:Int, which would need
863 // to be merged with [1]:Anything
864 //
865 // The only possible values which can cause a conflict are minus -1's.
866 // As a result, we start with a fast insertion (aka without check) of
867 // non-expanded values, since they just do a literal shift which needs no
868 // extra checking, besides bounds checks.
869 //
870 // Since we're doing things manually, we also need to manually preserve TT
871 // invariants. Specifically, TT limits all values to have offsets <
872 // MAX_OFFSET, unless it is the smallest offset at that depth. (e.g. so we
873 // can still hava typetree {[123456]:Int}, even if limit is 100).
874 //
875 // First compute the minimum 0th index to be kept.
876 Result.minIndices.resize(minIndices.size(), INT_MAX);
877
878 for (const auto &pair : mapping) {
879 if (pair.first.size() == 0) {
880 if (pair.second == BaseType::Pointer ||
881 pair.second == BaseType::Anything) {
882 Result.mapping.emplace(pair.first, pair.second);
883 continue;
884 }
885
886 llvm::errs() << "could not unmerge " << str() << "\n";
887 assert(0 && "ShiftIndices called on a nonpointer/anything");
888 llvm_unreachable("ShiftIndices called on a nonpointer/anything");
889 }
890
891 int next0 = pair.first[0];
892
893 if (next0 == -1) {
894 if (maxSize == -1) {
895 // Max size does not clip the next index
896
897 // If we have a follow up offset add, we lose the -1 since we only
898 // represent [0, inf) with -1 not the [addOffset, inf) required here
899 if (addOffset != 0) {
900 next0 = addOffset;
901 }
902
903 } else {
904 // We're going to insert addOffset + 0...maxSize so the new minIndex
905 // is addOffset
906 Result.minIndices[0] = addOffset;
907 for (size_t i = 1, sz = pair.first.size(); i < sz; i++)
908 if (pair.first[i] < Result.minIndices[i])
909 Result.minIndices[i] = pair.first[i];
910 continue;
911 }
912 } else {
913 // Too small for range
914 if (next0 < offset) {
915 continue;
916 }
917 next0 -= offset;
918
919 if (maxSize != -1) {
920 if (next0 >= maxSize)
921 continue;
922 }
923
924 next0 += addOffset;
925 }
926 if (next0 < Result.minIndices[0])
927 Result.minIndices[0] = next0;
928 for (size_t i = 1, sz = pair.first.size(); i < sz; i++)
929 if (pair.first[i] < Result.minIndices[i])
930 Result.minIndices[i] = pair.first[i];
931 }
932
933 // Max depth of actual inserted values
934 size_t maxInsertedDepth = 0;
935
936 // Insert all
937 for (const auto &pair : mapping) {
938 if (pair.first.size() == 0)
939 continue;
940
941 int next0 = pair.first[0];
942
943 if (next0 == -1) {
944 if (maxSize == -1) {
945 // Max size does not clip the next index
946
947 // If we have a follow up offset add, we lose the -1 since we only
948 // represent [0, inf) with -1 not the [addOffset, inf) required here
949 if (addOffset != 0) {
950 next0 = addOffset;
951 }
952
953 } else {
954 // This needs to become 0...maxSize handled separately as it is the
955 // only insertion that could have collisions
956 continue;
957 }
958 } else {
959 // Too small for range
960 if (next0 < offset) {
961 continue;
962 }
963 next0 -= offset;
964
965 if (maxSize != -1) {
966 if (next0 >= maxSize)
967 continue;
968 }
969
970 next0 += addOffset;
971 }
972
973 // If after moving this would not merit being kept for being a min index
974 // or being within the max type offset, skip it.
975 if (next0 > MaxTypeOffset) {
976 bool minIndex = next0 == Result.minIndices[0];
977 if (!minIndex)
978 for (size_t i = 1; i < pair.first.size(); i++) {
979 if (pair.first[i] == Result.minIndices[i]) {
980 minIndex = true;
981 break;
982 }
983 }
984 if (!minIndex)
985 continue;
986 }
987
988 std::vector<int> next(pair.first);
989 next[0] = next0;
990 Result.mapping.emplace(next, pair.second);
991 if (next.size() > maxInsertedDepth)
992 maxInsertedDepth = next.size();
993 }
994
995 // Insert and expand the minus one, if needed
996 if (maxSize != -1)
997 for (const auto &pair : mapping) {
998 if (pair.first.size() == 0)
999 continue;
1000 if (pair.first[0] != -1)
1001 continue;
1002
1003 size_t chunk = 1;
1004 std::vector<int> next(pair.first);
1005 auto op = operator[]({next[0]});
1006 if (auto flt = op.isFloat()) {
1007 chunk = dl.getTypeSizeInBits(flt) / 8;
1008 } else if (op == BaseType::Pointer) {
1009 chunk = dl.getPointerSizeInBits() / 8;
1010 }
1011 auto offincr = (chunk - offset % chunk) % chunk;
1012 bool inserted = false;
1013 for (int i = offincr; i < maxSize; i += chunk) {
1014 next[0] = i + addOffset;
1015 ConcreteType prev(pair.second);
1016 // We can use faster checks here, since we know there can be no
1017 // -1's that we would conflict with, only conflicts from previous
1018 // fixed value insertions.
1019 auto found = Result.mapping.find(next);
1020 if (found != Result.mapping.end()) {
1021 // orIn returns if changed, update the value in the map if so
1022 // with the new value.
1023 if (prev.orIn(found->second, /*pointerIntSame*/ false))
1024 found->second = prev;
1025 } else {
1026 Result.mapping.emplace(next, pair.second);
1027 }
1028 inserted = true;
1029 }
1030 if (inserted && next.size() > maxInsertedDepth)
1031 maxInsertedDepth = next.size();
1032 }
1033
1034 // Resize minIndices down if we dropped any higher-depth indices for being
1035 // out of scope.
1036 Result.minIndices.resize(maxInsertedDepth);
1037 return Result;
1038 }
1039
1040 /// Keep only mappings where the type is not an `Anything`
1042 TypeTree Result;
1043 Result.minIndices.reserve(minIndices.size());
1044 for (const auto &pair : mapping) {
1045 if (pair.second == ConcreteType(BaseType::Anything))
1046 continue;
1047 Result.mapping.insert(pair);
1048 for (size_t i = 0, Len = pair.first.size(); i < Len; ++i) {
1049 if (i == Result.minIndices.size())
1050 Result.minIndices.push_back(pair.first[i]);
1051 else if (pair.first[i] < Result.minIndices[i])
1052 Result.minIndices[i] = pair.first[i];
1053 }
1054 }
1055 return Result;
1056 }
1057
1058 /// Replace -1 with 0
1060 TypeTree dat;
1061 for (const auto &pair : mapping) {
1062 if (pair.second == ConcreteType(BaseType::Anything))
1063 continue;
1064 std::vector<int> nex = pair.first;
1065 for (auto &v : nex)
1066 if (v == -1)
1067 v = 0;
1068 dat.insert(nex, pair.second);
1069 }
1070 return dat;
1071 }
1072
1073 /// Replace all integer subtypes with anything
1075 for (auto &pair : mapping) {
1076 if (pair.second == BaseType::Integer) {
1077 pair.second = BaseType::Anything;
1078 }
1079 }
1080 }
1081
1082 /// Keep only mappings where the type is an `Anything`
1084 TypeTree dat;
1085 for (const auto &pair : mapping) {
1086 if (pair.second != ConcreteType(BaseType::Anything))
1087 continue;
1088 dat.insert(pair.first, pair.second);
1089 }
1090 return dat;
1091 }
1092
1093 /// Chceck equality of two TypeTrees
1094 bool operator==(const TypeTree &RHS) const { return mapping == RHS.mapping; }
1095
1096 /// Set this to another TypeTree, returning if this was changed
1097 bool operator=(const TypeTree &RHS) {
1098 if (*this == RHS)
1099 return false;
1100 minIndices = RHS.minIndices;
1101 mapping.clear();
1102 for (const auto &elems : RHS.mapping) {
1103 mapping.emplace(elems);
1104 }
1105 return true;
1106 }
1107
1108 bool checkedOrIn(const std::vector<int> &Seq, ConcreteType RHS,
1109 bool PointerIntSame, bool &LegalOr) {
1110 assert(RHS != BaseType::Unknown);
1111 ConcreteType CT = operator[](Seq);
1112
1113 bool subchanged = CT.checkedOrIn(RHS, PointerIntSame, LegalOr);
1114 if (!subchanged)
1115 return false;
1116 if (!LegalOr)
1117 return subchanged;
1118
1119 auto SeqSize = Seq.size();
1120
1121 if (SeqSize > 0) {
1122 // check pointer abilities from before
1123 for (size_t i = 0; i < SeqSize; ++i) {
1124 std::vector<int> tmp(Seq.begin(), Seq.end() - 1 - i);
1125 auto found = mapping.find(tmp);
1126 if (found != mapping.end()) {
1127 if (!(found->second == BaseType::Pointer ||
1128 found->second == BaseType::Anything)) {
1129 LegalOr = false;
1130 return false;
1131 }
1132 }
1133 }
1134
1135 // Check if there is an existing match, e.g. [-1, -1, -1] and inserting
1136 // [-1, 8, -1]
1137 {
1138 for (const auto &pair : llvm::make_early_inc_range(mapping)) {
1139 if (pair.first.size() == SeqSize) {
1140 // Whether the the inserted val (e.g. [-1, 0] or [0, 0]) is at least
1141 // as general as the existing map val (e.g. [0, 0]).
1142 bool newMoreGeneralThanOld = true;
1143 // Whether the the existing val (e.g. [-1, 0] or [0, 0]) is at least
1144 // as general as the inserted map val (e.g. [0, 0]).
1145 bool oldMoreGeneralThanNew = true;
1146 for (unsigned i = 0; i < SeqSize; i++) {
1147 if (pair.first[i] == Seq[i])
1148 continue;
1149 if (Seq[i] == -1) {
1150 oldMoreGeneralThanNew = false;
1151 } else if (pair.first[i] == -1) {
1152 newMoreGeneralThanOld = false;
1153 } else {
1154 oldMoreGeneralThanNew = false;
1155 newMoreGeneralThanOld = false;
1156 break;
1157 }
1158 }
1159
1160 if (oldMoreGeneralThanNew) {
1161 // Inserting an existing or less general version
1162 if (CT == pair.second)
1163 return false;
1164
1165 // Inserting an existing or less general version (with pointer-int
1166 // equivalence)
1167 if (PointerIntSame)
1168 if ((CT == BaseType::Pointer &&
1169 pair.second == BaseType::Integer) ||
1170 (CT == BaseType::Integer &&
1171 pair.second == BaseType::Pointer))
1172 return false;
1173
1174 // Inserting into an anything. Since from above we know this is
1175 // not an anything, the inserted value contains no new information
1176 if (pair.second == BaseType::Anything)
1177 return false;
1178
1179 // Inserting say a [0]:anything into a [-1]:Float
1180 if (CT == BaseType::Anything) {
1181 // If both at same index, remove old index
1182 if (newMoreGeneralThanOld)
1183 mapping.erase(pair.first);
1184 continue;
1185 }
1186
1187 // Otherwise, inserting a non-equivalent pair into a more general
1188 // slot. This is invalid.
1189 LegalOr = false;
1190 return false;
1191 } else if (newMoreGeneralThanOld) {
1192 // This new is strictly more general than the old. If they were
1193 // equivalent, the case above would have been hit.
1194
1195 if (CT == BaseType::Anything || CT == pair.second) {
1196 // previous equivalent values or values overwritten by
1197 // an anything are removed
1198 mapping.erase(pair.first);
1199 continue;
1200 }
1201
1202 // Inserting an existing or less general version (with pointer-int
1203 // equivalence)
1204 if (PointerIntSame)
1205 if ((CT == BaseType::Pointer &&
1206 pair.second == BaseType::Integer) ||
1207 (CT == BaseType::Integer &&
1208 pair.second == BaseType::Pointer)) {
1209 mapping.erase(pair.first);
1210 continue;
1211 }
1212
1213 // Keep lingering anythings if not being overwritten, even if this
1214 // (e.g. Float) applies to more locations. Therefore it is legal
1215 // to have [-1]:Float, [8]:Anything
1216 if (CT != BaseType::Anything && pair.second == BaseType::Anything)
1217 continue;
1218
1219 // Otherwise, inserting a more general non-equivalent pair. This
1220 // is invalid.
1221 LegalOr = false;
1222 return false;
1223 }
1224 }
1225 }
1226 }
1227 }
1228
1229 return insert(Seq, CT);
1230 }
1231
1232 bool orIn(const std::vector<int> &Seq, ConcreteType RHS,
1233 bool PointerIntSame = false) {
1234 bool LegalOr = true;
1235 bool Result = checkedOrIn(Seq, RHS, PointerIntSame, LegalOr);
1236 assert(LegalOr);
1237 return Result;
1238 }
1239
1240 /// Set this to the logical or of itself and RHS, returning whether this value
1241 /// changed Setting `PointerIntSame` considers pointers and integers as
1242 /// equivalent If this is an illegal operation, `LegalOr` will be set to false
1243 bool checkedOrIn(const TypeTree &RHS, bool PointerIntSame, bool &LegalOr) {
1244 // TODO detect recursive merge and simplify
1245
1246 bool changed = false;
1247 for (auto &pair : RHS.mapping) {
1248 changed |= checkedOrIn(pair.first, pair.second, PointerIntSame, LegalOr);
1249 }
1250 return changed;
1251 }
1252
1253 /// Set this to the logical or of itself and RHS, returning whether this value
1254 /// changed Setting `PointerIntSame` considers pointers and integers as
1255 /// equivalent This function will error if doing an illegal Operation
1256 bool orIn(const TypeTree &RHS, bool PointerIntSame) {
1257 bool Legal = true;
1258 bool Result = checkedOrIn(RHS, PointerIntSame, Legal);
1259 if (!Legal) {
1260 llvm::errs() << "Illegal orIn: " << str() << " right: " << RHS.str()
1261 << " PointerIntSame=" << PointerIntSame << "\n";
1262 assert(0 && "Performed illegal ConcreteType::orIn");
1263 llvm_unreachable("Performed illegal ConcreteType::orIn");
1264 }
1265 return Result;
1266 }
1267
1268 /// Set this to the logical or of itself and RHS, returning whether this value
1269 /// changed Setting `PointerIntSame` considers pointers and integers as
1270 /// equivalent This function will error if doing an illegal Operation
1271 bool orIn(const std::vector<int> Seq, ConcreteType CT, bool PointerIntSame) {
1272 bool Legal = true;
1273 bool Result = checkedOrIn(Seq, CT, PointerIntSame, Legal);
1274 if (!Legal) {
1275 llvm::errs() << "Illegal orIn: " << str() << " right: " << to_string(Seq)
1276 << " CT: " << CT.str()
1277 << " PointerIntSame=" << PointerIntSame << "\n";
1278 assert(0 && "Performed illegal ConcreteType::orIn");
1279 llvm_unreachable("Performed illegal ConcreteType::orIn");
1280 }
1281 return Result;
1282 }
1283
1284 /// Set this to the logical or of itself and RHS, returning whether this value
1285 /// changed This assumes that pointers and integers are distinct This function
1286 /// will error if doing an illegal Operation
1287 bool operator|=(const TypeTree &RHS) {
1288 return orIn(RHS, /*PointerIntSame*/ false);
1289 }
1290
1291 /// Set this to the logical and of itself and RHS, returning whether this
1292 /// value changed If this and RHS are incompatible at an index, the result
1293 /// will be BaseType::Unknown
1294 bool andIn(const TypeTree &RHS) {
1295 bool changed = false;
1296
1297 for (auto &pair : llvm::make_early_inc_range(mapping)) {
1299 auto fd = RHS.mapping.find(pair.first);
1300 if (fd != RHS.mapping.end()) {
1301 other = fd->second;
1302 }
1303 changed = (pair.second &= other);
1304 if (pair.second == BaseType::Unknown) {
1305 mapping.erase(pair.first);
1306 }
1307 }
1308
1309 return changed;
1310 }
1311
1312 /// Set this to the logical and of itself and RHS, returning whether this
1313 /// value changed If this and RHS are incompatible at an index, the result
1314 /// will be BaseType::Unknown
1315 bool operator&=(const TypeTree &RHS) { return andIn(RHS); }
1316
1317 /// Set this to the logical `binop` of itself and RHS, using the Binop Op,
1318 /// returning true if this was changed.
1319 /// This function will error on an invalid type combination
1320 bool binopIn(bool &Legal, const TypeTree &RHS,
1321 llvm::BinaryOperator::BinaryOps Op) {
1322 bool changed = false;
1323
1324 for (auto &pair : llvm::make_early_inc_range(mapping)) {
1325 // TODO propagate non-first level operands:
1326 // Special handling is necessary here because a pointer to an int
1327 // binop with something should not apply the binop rules to the
1328 // underlying data but instead a different rule
1329 if (pair.first.size() > 0) {
1330 mapping.erase(pair.first);
1331 continue;
1332 }
1333
1334 ConcreteType CT(pair.second);
1336
1337 // Mutual mappings
1338 auto found = RHS.mapping.find(pair.first);
1339 if (found != RHS.mapping.end()) {
1340 RightCT = found->second;
1341 }
1342 bool SubLegal = true;
1343 changed |= CT.binopIn(SubLegal, RightCT, Op);
1344 if (!SubLegal) {
1345 Legal = false;
1346 return changed;
1347 }
1348 if (CT == BaseType::Unknown) {
1349 mapping.erase(pair.first);
1350 } else {
1351 pair.second = CT;
1352 }
1353 }
1354
1355 // mapings just on the right
1356 for (auto &pair : RHS.mapping) {
1357 // TODO propagate non-first level operands:
1358 // Special handling is necessary here because a pointer to an int
1359 // binop with something should not apply the binop rules to the
1360 // underlying data but instead a different rule
1361 if (pair.first.size() > 0) {
1362 continue;
1363 }
1364
1365 if (mapping.find(pair.first) == RHS.mapping.end()) {
1367 bool SubLegal = true;
1368 changed |= CT.binopIn(SubLegal, pair.second, Op);
1369 if (!SubLegal) {
1370 Legal = false;
1371 return changed;
1372 }
1373 if (CT != BaseType::Unknown) {
1374 mapping.insert(std::make_pair(pair.first, CT));
1375 }
1376 }
1377 }
1378
1379 return changed;
1380 }
1381
1382 /// Returns a string representation of this TypeTree
1383 std::string str() const {
1384 std::string out = "{";
1385 bool first = true;
1386 for (auto &pair : mapping) {
1387 if (!first) {
1388 out += ", ";
1389 }
1390 out += "[";
1391 for (unsigned i = 0; i < pair.first.size(); ++i) {
1392 if (i != 0)
1393 out += ",";
1394 out += std::to_string(pair.first[i]);
1395 }
1396 out += "]:" + pair.second.str();
1397 first = false;
1398 }
1399 out += "}";
1400 return out;
1401 }
1402
1403 llvm::MDNode *toMD(llvm::LLVMContext &ctx) {
1404 llvm::SmallVector<llvm::Metadata *, 1> subMD;
1405 std::map<int, TypeTree> todo;
1407 for (auto &pair : mapping) {
1408 if (pair.first.size() == 0) {
1409 base = pair.second;
1410 continue;
1411 }
1412 auto next(pair.first);
1413 next.erase(next.begin());
1414 todo[pair.first[0]].mapping.insert(std::make_pair(next, pair.second));
1415 }
1416 subMD.push_back(llvm::MDString::get(ctx, base.str()));
1417 for (auto pair : todo) {
1418 subMD.push_back(llvm::ConstantAsMetadata::get(
1419 llvm::ConstantInt::get(llvm::IntegerType::get(ctx, 32), pair.first)));
1420 subMD.push_back(pair.second.toMD(ctx));
1421 }
1422 return llvm::MDNode::get(ctx, subMD);
1423 };
1424
1425 void insertFromMD(llvm::MDNode *md, const std::vector<int> &prev = {}) {
1426 ConcreteType base(
1427 llvm::cast<llvm::MDString>(md->getOperand(0))->getString(),
1428 md->getContext());
1429 if (base != BaseType::Unknown)
1430 mapping.insert(std::make_pair(prev, base));
1431 for (size_t i = 1; i < md->getNumOperands(); i += 2) {
1432 auto off = llvm::cast<llvm::ConstantInt>(
1433 llvm::cast<llvm::ConstantAsMetadata>(md->getOperand(i))
1434 ->getValue())
1435 ->getSExtValue();
1436 auto next(prev);
1437 next.push_back((int)off);
1438 insertFromMD(llvm::cast<llvm::MDNode>(md->getOperand(i + 1)), next);
1439 }
1440 }
1441
1442 static TypeTree fromMD(llvm::MDNode *md) {
1443 TypeTree ret;
1444 std::vector<int> off;
1445 ret.insertFromMD(md, off);
1446 return ret;
1447 }
1448};
1449
1450#endif
std::map< const std::vector< int >, const TypeResult > TypeTreeMapType
Definition TypeTree.h:68
llvm::cl::opt< unsigned > EnzymeMaxTypeDepth
static std::string to_string(const std::vector< int > x)
Helper function to print a vector of ints to a string.
Definition TypeTree.h:53
std::map< const std::vector< int >, ConcreteType > ConcreteTypeMapType
Definition TypeTree.h:67
llvm::cl::opt< bool > EnzymeTypeWarning
llvm::cl::opt< int > MaxTypeOffset
Maximum offset for type trees to keep.
std::shared_ptr< const TypeTree > TypeResult
Definition TypeTree.h:66
LLVMValueRef(* CustomErrorHandler)(const char *, LLVMValueRef, ErrorType, const void *, LLVMValueRef, LLVMBuilderRef)
Definition Utils.cpp:62
void EmitWarning(llvm::StringRef RemarkName, const llvm::DiagnosticLocation &Loc, const llvm::BasicBlock *BB, const Args &...args)
Definition Utils.h:133
@ TypeDepthExceeded
Concrete SubType of a given value.
bool binopIn(bool &Legal, const ConcreteType RHS, llvm::BinaryOperator::BinaryOps Op)
Set this to the logical binop of itself and RHS, using the Binop Op, returning true if this was chang...
std::string str() const
Convert the ConcreteType to a string.
bool checkedOrIn(const ConcreteType CT, bool PointerIntSame, bool &LegalOr)
Set this to the logical or of itself and CT, returning whether this value changed Setting PointerIntS...
bool orIn(const ConcreteType CT, bool PointerIntSame)
Set this to the logical or of itself and CT, returning whether this value changed Setting PointerIntS...
Class representing the underlying types of values as sequences of offsets to a ConcreteType.
Definition TypeTree.h:72
bool orIn(const TypeTree &RHS, bool PointerIntSame)
Set this to the logical or of itself and RHS, returning whether this value changed Setting PointerInt...
Definition TypeTree.h:1256
TypeTree Only(int Off, llvm::Instruction *orig) const
Prepend an offset to all mappings.
Definition TypeTree.h:471
bool operator&=(const TypeTree &RHS)
Set this to the logical and of itself and RHS, returning whether this value changed If this and RHS a...
Definition TypeTree.h:1315
TypeTree Data0() const
Peel off the outermost index at offset 0.
Definition TypeTree.h:513
ConcreteType operator[](const std::vector< int > Seq) const
Lookup the underlying ConcreteType at a given offset sequence or Unknown if none exists.
Definition TypeTree.h:177
bool andIn(const TypeTree &RHS)
Set this to the logical and of itself and RHS, returning whether this value changed If this and RHS a...
Definition TypeTree.h:1294
const ConcreteTypeMapType & getMapping() const
Utility helper to lookup the mapping.
Definition TypeTree.h:173
static TypeTree parse(llvm::StringRef str, llvm::LLVMContext &ctx)
Definition TypeTree.h:86
bool checkedOrIn(const TypeTree &RHS, bool PointerIntSame, bool &LegalOr)
Set this to the logical or of itself and RHS, returning whether this value changed Setting PointerInt...
Definition TypeTree.h:1243
TypeTree ShiftIndices(const llvm::DataLayout &dl, const int offset, const int maxSize, size_t addOffset=0) const
Replace mappings in the range in [offset, offset+maxSize] with those in.
Definition TypeTree.h:840
TypeTree Lookup(size_t len, const llvm::DataLayout &dl) const
Select all submappings whose first index is in range [0, len) and remove the first index.
Definition TypeTree.h:593
void ReplaceIntWithAnything()
Replace all integer subtypes with anything.
Definition TypeTree.h:1074
llvm::MDNode * toMD(llvm::LLVMContext &ctx)
Definition TypeTree.h:1403
ConcreteType Inner0() const
Optimized version of Data0()[{}].
Definition TypeTree.h:548
bool operator|=(const TypeTree &RHS)
Set this to the logical or of itself and RHS, returning whether this value changed This assumes that ...
Definition TypeTree.h:1287
TypeTree ReplaceMinus() const
Replace -1 with 0.
Definition TypeTree.h:1059
bool operator==(const TypeTree &RHS) const
Chceck equality of two TypeTrees.
Definition TypeTree.h:1094
llvm::Type * IsAllFloat(const size_t size, const llvm::DataLayout &dl) const
Definition TypeTree.h:814
static TypeTree fromMD(llvm::MDNode *md)
Definition TypeTree.h:1442
bool isKnownPastPointer() const
Whether this TypeTree knows any non-pointer information.
Definition TypeTree.h:443
TypeTree Clear(size_t start, size_t end, size_t len) const
Remove any mappings in the range [start, end) or [len, inf) This function has special handling for -1...
Definition TypeTree.h:556
TypeTree KeepMinusOne(bool &legal) const
Keep only pointers (or anything's) to a repeated value (represented by -1)
Definition TypeTree.h:785
bool orIn(const std::vector< int > Seq, ConcreteType CT, bool PointerIntSame)
Set this to the logical or of itself and RHS, returning whether this value changed Setting PointerInt...
Definition TypeTree.h:1271
TypeTree JustInt() const
Select only the Integer ConcreteTypes.
Definition TypeTree.h:459
TypeTree JustAnything() const
Keep only mappings where the type is an Anything
Definition TypeTree.h:1083
bool checkedOrIn(const std::vector< int > &Seq, ConcreteType RHS, bool PointerIntSame, bool &LegalOr)
Definition TypeTree.h:1108
TypeTree()
Definition TypeTree.h:79
void CanonicalizeInPlace(size_t len, const llvm::DataLayout &dl)
Given that this tree represents something of at most size len, canonicalize this, creating -1's where...
Definition TypeTree.h:676
std::string str() const
Returns a string representation of this TypeTree.
Definition TypeTree.h:1383
bool isKnown() const
Whether this TypeTree contains any information.
Definition TypeTree.h:431
bool orIn(const std::vector< int > &Seq, ConcreteType RHS, bool PointerIntSame=false)
Definition TypeTree.h:1232
bool insert(const std::vector< int > Seq, ConcreteType CT, bool PointerIntSame=false)
Return if changed.
Definition TypeTree.h:234
void insertFromMD(llvm::MDNode *md, const std::vector< int > &prev={})
Definition TypeTree.h:1425
bool binopIn(bool &Legal, const TypeTree &RHS, llvm::BinaryOperator::BinaryOps Op)
Set this to the logical binop of itself and RHS, using the Binop Op, returning true if this was chang...
Definition TypeTree.h:1320
TypeTree(ConcreteType dat)
Definition TypeTree.h:80
bool operator<(const TypeTree &vd) const
How this TypeTree compares with another.
Definition TypeTree.h:428
TypeTree PurgeAnything() const
Keep only mappings where the type is not an Anything
Definition TypeTree.h:1041
bool operator=(const TypeTree &RHS)
Set this to another TypeTree, returning if this was changed.
Definition TypeTree.h:1097
bool IsFullyDetermined() const
Definition TypeTree.h:221