OLD | NEW |
1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// | 1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// This file defines aspects of the compilation that persist across | 11 /// This file defines aspects of the compilation that persist across multiple |
12 /// multiple functions. | 12 /// functions. |
13 /// | 13 /// |
14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
15 | 15 |
16 #include "IceGlobalContext.h" | 16 #include "IceGlobalContext.h" |
17 | 17 |
18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
20 #include "IceClFlags.h" | 20 #include "IceClFlags.h" |
21 #include "IceDefs.h" | 21 #include "IceDefs.h" |
22 #include "IceELFObjectWriter.h" | 22 #include "IceELFObjectWriter.h" |
(...skipping 18 matching lines...) Expand all Loading... |
41 return hash<Ice::IceString>()(Key.Name) + | 41 return hash<Ice::IceString>()(Key.Name) + |
42 hash<Ice::RelocOffsetT>()(Key.Offset); | 42 hash<Ice::RelocOffsetT>()(Key.Offset); |
43 } | 43 } |
44 }; | 44 }; |
45 } // end of namespace std | 45 } // end of namespace std |
46 | 46 |
47 namespace Ice { | 47 namespace Ice { |
48 | 48 |
49 namespace { | 49 namespace { |
50 | 50 |
51 // Define the key comparison function for the constant pool's | 51 // Define the key comparison function for the constant pool's unordered_map, |
52 // unordered_map, but only for key types of interest: integer types, | 52 // but only for key types of interest: integer types, floating point types, and |
53 // floating point types, and the special RelocatableTuple. | 53 // the special RelocatableTuple. |
54 template <typename KeyType, class Enable = void> struct KeyCompare {}; | 54 template <typename KeyType, class Enable = void> struct KeyCompare {}; |
55 | 55 |
56 template <typename KeyType> | 56 template <typename KeyType> |
57 struct KeyCompare<KeyType, | 57 struct KeyCompare<KeyType, |
58 typename std::enable_if< | 58 typename std::enable_if< |
59 std::is_integral<KeyType>::value || | 59 std::is_integral<KeyType>::value || |
60 std::is_same<KeyType, RelocatableTuple>::value>::type> { | 60 std::is_same<KeyType, RelocatableTuple>::value>::type> { |
61 bool operator()(const KeyType &Value1, const KeyType &Value2) const { | 61 bool operator()(const KeyType &Value1, const KeyType &Value2) const { |
62 return Value1 == Value2; | 62 return Value1 == Value2; |
63 } | 63 } |
64 }; | 64 }; |
65 template <typename KeyType> | 65 template <typename KeyType> |
66 struct KeyCompare<KeyType, typename std::enable_if< | 66 struct KeyCompare<KeyType, typename std::enable_if< |
67 std::is_floating_point<KeyType>::value>::type> { | 67 std::is_floating_point<KeyType>::value>::type> { |
68 bool operator()(const KeyType &Value1, const KeyType &Value2) const { | 68 bool operator()(const KeyType &Value1, const KeyType &Value2) const { |
69 return !memcmp(&Value1, &Value2, sizeof(KeyType)); | 69 return !memcmp(&Value1, &Value2, sizeof(KeyType)); |
70 } | 70 } |
71 }; | 71 }; |
72 | 72 |
73 // Define a key comparison function for sorting the constant pool's | 73 // Define a key comparison function for sorting the constant pool's values |
74 // values after they are dumped to a vector. This covers integer | 74 // after they are dumped to a vector. This covers integer types, floating point |
75 // types, floating point types, and ConstantRelocatable values. | 75 // types, and ConstantRelocatable values. |
76 template <typename ValueType, class Enable = void> struct KeyCompareLess {}; | 76 template <typename ValueType, class Enable = void> struct KeyCompareLess {}; |
77 | 77 |
78 template <typename ValueType> | 78 template <typename ValueType> |
79 struct KeyCompareLess<ValueType, | 79 struct KeyCompareLess<ValueType, |
80 typename std::enable_if<std::is_floating_point< | 80 typename std::enable_if<std::is_floating_point< |
81 typename ValueType::PrimType>::value>::type> { | 81 typename ValueType::PrimType>::value>::type> { |
82 bool operator()(const Constant *Const1, const Constant *Const2) const { | 82 bool operator()(const Constant *Const1, const Constant *Const2) const { |
83 using CompareType = uint64_t; | 83 using CompareType = uint64_t; |
84 static_assert(sizeof(typename ValueType::PrimType) <= sizeof(CompareType), | 84 static_assert(sizeof(typename ValueType::PrimType) <= sizeof(CompareType), |
85 "Expected floating-point type of width 64-bit or less"); | 85 "Expected floating-point type of width 64-bit or less"); |
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 } | 594 } |
595 } | 595 } |
596 if (Found) { | 596 if (Found) { |
597 NewName[NewPos++] = OldName[OldPos++]; // 'S' | 597 NewName[NewPos++] = OldName[OldPos++]; // 'S' |
598 size_t Length = Last - OldPos; | 598 size_t Length = Last - OldPos; |
599 // NewPos and OldPos point just past the 'S'. | 599 // NewPos and OldPos point just past the 'S'. |
600 assert(NewName[NewPos - 1] == 'S'); | 600 assert(NewName[NewPos - 1] == 'S'); |
601 assert(OldName[OldPos - 1] == 'S'); | 601 assert(OldName[OldPos - 1] == 'S'); |
602 assert(OldName[OldPos + Length] == '_'); | 602 assert(OldName[OldPos + Length] == '_'); |
603 if (AllZs) { | 603 if (AllZs) { |
604 // Replace N 'Z' characters with a '0' (if N=0) or '1' (if | 604 // Replace N 'Z' characters with a '0' (if N=0) or '1' (if N>0) |
605 // N>0) followed by N '0' characters. | 605 // followed by N '0' characters. |
606 NewName[NewPos++] = (Length ? '1' : '0'); | 606 NewName[NewPos++] = (Length ? '1' : '0'); |
607 for (size_t i = 0; i < Length; ++i) { | 607 for (size_t i = 0; i < Length; ++i) { |
608 NewName[NewPos++] = '0'; | 608 NewName[NewPos++] = '0'; |
609 } | 609 } |
610 } else { | 610 } else { |
611 // Iterate right-to-left and increment the base-36 number. | 611 // Iterate right-to-left and increment the base-36 number. |
612 bool Carry = true; | 612 bool Carry = true; |
613 for (size_t i = 0; i < Length; ++i) { | 613 for (size_t i = 0; i < Length; ++i) { |
614 size_t Offset = Length - 1 - i; | 614 size_t Offset = Length - 1 - i; |
615 char Ch = OldName[OldPos + Offset]; | 615 char Ch = OldName[OldPos + Offset]; |
(...skipping 19 matching lines...) Expand all Loading... |
635 OldPos = Last; | 635 OldPos = Last; |
636 // Fall through and let the '_' be copied across. | 636 // Fall through and let the '_' be copied across. |
637 } | 637 } |
638 } | 638 } |
639 NewName[NewPos] = OldName[OldPos]; | 639 NewName[NewPos] = OldName[OldPos]; |
640 } | 640 } |
641 assert(NewName[NewPos] == '\0'); | 641 assert(NewName[NewPos] == '\0'); |
642 OldName = NewName; | 642 OldName = NewName; |
643 } | 643 } |
644 | 644 |
645 // In this context, name mangling means to rewrite a symbol using a | 645 // In this context, name mangling means to rewrite a symbol using a given |
646 // given prefix. For a C++ symbol, nest the original symbol inside | 646 // prefix. For a C++ symbol, nest the original symbol inside the "prefix" |
647 // the "prefix" namespace. For other symbols, just prepend the | 647 // namespace. For other symbols, just prepend the prefix. |
648 // prefix. | |
649 IceString GlobalContext::mangleName(const IceString &Name) const { | 648 IceString GlobalContext::mangleName(const IceString &Name) const { |
650 // An already-nested name like foo::bar() gets pushed down one | 649 // An already-nested name like foo::bar() gets pushed down one level, making |
651 // level, making it equivalent to Prefix::foo::bar(). | 650 // it equivalent to Prefix::foo::bar(). |
652 // _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz | 651 // _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz |
653 // A non-nested but mangled name like bar() gets nested, making it | 652 // A non-nested but mangled name like bar() gets nested, making it equivalent |
654 // equivalent to Prefix::bar(). | 653 // to Prefix::bar(). |
655 // _Z3barxyz ==> ZN6Prefix3barExyz | 654 // _Z3barxyz ==> ZN6Prefix3barExyz |
656 // An unmangled, extern "C" style name, gets a simple prefix: | 655 // An unmangled, extern "C" style name, gets a simple prefix: |
657 // bar ==> Prefixbar | 656 // bar ==> Prefixbar |
658 if (!BuildDefs::dump() || getFlags().getTestPrefix().empty()) | 657 if (!BuildDefs::dump() || getFlags().getTestPrefix().empty()) |
659 return Name; | 658 return Name; |
660 | 659 |
661 const IceString &TestPrefix = getFlags().getTestPrefix(); | 660 const IceString &TestPrefix = getFlags().getTestPrefix(); |
662 unsigned PrefixLength = TestPrefix.length(); | 661 unsigned PrefixLength = TestPrefix.length(); |
663 ManglerVector NameBase(1 + Name.length()); | 662 ManglerVector NameBase(1 + Name.length()); |
664 const size_t BufLen = 30 + Name.length() + PrefixLength; | 663 const size_t BufLen = 30 + Name.length() + PrefixLength; |
665 ManglerVector NewName(BufLen); | 664 ManglerVector NewName(BufLen); |
666 uint32_t BaseLength = 0; // using uint32_t due to sscanf format string | 665 uint32_t BaseLength = 0; // using uint32_t due to sscanf format string |
667 | 666 |
668 int ItemsParsed = sscanf(Name.c_str(), "_ZN%s", NameBase.data()); | 667 int ItemsParsed = sscanf(Name.c_str(), "_ZN%s", NameBase.data()); |
669 if (ItemsParsed == 1) { | 668 if (ItemsParsed == 1) { |
670 // Transform _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz | 669 // Transform _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz |
671 // (splice in "6Prefix") ^^^^^^^ | 670 // (splice in "6Prefix") ^^^^^^^ |
672 snprintf(NewName.data(), BufLen, "_ZN%u%s%s", PrefixLength, | 671 snprintf(NewName.data(), BufLen, "_ZN%u%s%s", PrefixLength, |
673 TestPrefix.c_str(), NameBase.data()); | 672 TestPrefix.c_str(), NameBase.data()); |
674 // We ignore the snprintf return value (here and below). If we | 673 // We ignore the snprintf return value (here and below). If we somehow |
675 // somehow miscalculated the output buffer length, the output will | 674 // miscalculated the output buffer length, the output will be truncated, |
676 // be truncated, but it will be truncated consistently for all | 675 // but it will be truncated consistently for all mangleName() calls on the |
677 // mangleName() calls on the same input string. | 676 // same input string. |
678 incrementSubstitutions(NewName); | 677 incrementSubstitutions(NewName); |
679 return NewName.data(); | 678 return NewName.data(); |
680 } | 679 } |
681 | 680 |
682 // Artificially limit BaseLength to 9 digits (less than 1 billion) | 681 // Artificially limit BaseLength to 9 digits (less than 1 billion) because |
683 // because sscanf behavior is undefined on integer overflow. If | 682 // sscanf behavior is undefined on integer overflow. If there are more than 9 |
684 // there are more than 9 digits (which we test by looking at the | 683 // digits (which we test by looking at the beginning of NameBase), then we |
685 // beginning of NameBase), then we consider this a failure to parse | 684 // consider this a failure to parse a namespace mangling, and fall back to |
686 // a namespace mangling, and fall back to the simple prefixing. | 685 // the simple prefixing. |
687 ItemsParsed = sscanf(Name.c_str(), "_Z%9u%s", &BaseLength, NameBase.data()); | 686 ItemsParsed = sscanf(Name.c_str(), "_Z%9u%s", &BaseLength, NameBase.data()); |
688 if (ItemsParsed == 2 && BaseLength <= strlen(NameBase.data()) && | 687 if (ItemsParsed == 2 && BaseLength <= strlen(NameBase.data()) && |
689 !isdigit(NameBase[0])) { | 688 !isdigit(NameBase[0])) { |
690 // Transform _Z3barxyz ==> _ZN6Prefix3barExyz | 689 // Transform _Z3barxyz ==> _ZN6Prefix3barExyz |
691 // ^^^^^^^^ ^ | 690 // ^^^^^^^^ ^ |
692 // (splice in "N6Prefix", and insert "E" after "3bar") | 691 // (splice in "N6Prefix", and insert "E" after "3bar") But an "I" after the |
693 // But an "I" after the identifier indicates a template argument | 692 // identifier indicates a template argument list terminated with "E"; |
694 // list terminated with "E"; insert the new "E" before/after the | 693 // insert the new "E" before/after the old "E". E.g.: |
695 // old "E". E.g.: | |
696 // Transform _Z3barIabcExyz ==> _ZN6Prefix3barIabcEExyz | 694 // Transform _Z3barIabcExyz ==> _ZN6Prefix3barIabcEExyz |
697 // ^^^^^^^^ ^ | 695 // ^^^^^^^^ ^ |
698 // (splice in "N6Prefix", and insert "E" after "3barIabcE") | 696 // (splice in "N6Prefix", and insert "E" after "3barIabcE") |
699 ManglerVector OrigName(Name.length()); | 697 ManglerVector OrigName(Name.length()); |
700 ManglerVector OrigSuffix(Name.length()); | 698 ManglerVector OrigSuffix(Name.length()); |
701 uint32_t ActualBaseLength = BaseLength; | 699 uint32_t ActualBaseLength = BaseLength; |
702 if (NameBase[ActualBaseLength] == 'I') { | 700 if (NameBase[ActualBaseLength] == 'I') { |
703 ++ActualBaseLength; | 701 ++ActualBaseLength; |
704 while (NameBase[ActualBaseLength] != 'E' && | 702 while (NameBase[ActualBaseLength] != 'E' && |
705 NameBase[ActualBaseLength] != '\0') | 703 NameBase[ActualBaseLength] != '\0') |
(...skipping 17 matching lines...) Expand all Loading... |
723 GlobalContext::~GlobalContext() { | 721 GlobalContext::~GlobalContext() { |
724 llvm::DeleteContainerPointers(AllThreadContexts); | 722 llvm::DeleteContainerPointers(AllThreadContexts); |
725 LockedPtr<DestructorArray> Dtors = getDestructors(); | 723 LockedPtr<DestructorArray> Dtors = getDestructors(); |
726 // Destructors are invoked in the opposite object construction order. | 724 // Destructors are invoked in the opposite object construction order. |
727 for (auto DtorIter = Dtors->crbegin(); DtorIter != Dtors->crend(); | 725 for (auto DtorIter = Dtors->crbegin(); DtorIter != Dtors->crend(); |
728 ++DtorIter) { | 726 ++DtorIter) { |
729 (*DtorIter)(); | 727 (*DtorIter)(); |
730 } | 728 } |
731 } | 729 } |
732 | 730 |
733 // TODO(stichnot): Consider adding thread-local caches of constant | 731 // TODO(stichnot): Consider adding thread-local caches of constant pool entries |
734 // pool entries to reduce contention. | 732 // to reduce contention. |
735 | 733 |
736 // All locking is done by the getConstantInt[0-9]+() target function. | 734 // All locking is done by the getConstantInt[0-9]+() target function. |
737 Constant *GlobalContext::getConstantInt(Type Ty, int64_t Value) { | 735 Constant *GlobalContext::getConstantInt(Type Ty, int64_t Value) { |
738 switch (Ty) { | 736 switch (Ty) { |
739 case IceType_i1: | 737 case IceType_i1: |
740 return getConstantInt1(Value); | 738 return getConstantInt1(Value); |
741 case IceType_i8: | 739 case IceType_i8: |
742 return getConstantInt8(Value); | 740 return getConstantInt8(Value); |
743 case IceType_i16: | 741 case IceType_i16: |
744 return getConstantInt16(Value); | 742 return getConstantInt16(Value); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
868 } | 866 } |
869 llvm_unreachable("Unknown type"); | 867 llvm_unreachable("Unknown type"); |
870 } | 868 } |
871 | 869 |
872 ConstantList GlobalContext::getConstantExternSyms() { | 870 ConstantList GlobalContext::getConstantExternSyms() { |
873 return getConstPool()->ExternRelocatables.getConstantPool(); | 871 return getConstPool()->ExternRelocatables.getConstantPool(); |
874 } | 872 } |
875 | 873 |
876 JumpTableDataList GlobalContext::getJumpTables() { | 874 JumpTableDataList GlobalContext::getJumpTables() { |
877 JumpTableDataList JumpTables(*getJumpTableList()); | 875 JumpTableDataList JumpTables(*getJumpTableList()); |
878 // Make order deterministic by sorting into functions and then ID of the | 876 // Make order deterministic by sorting into functions and then ID of the jump |
879 // jump table within that function. | 877 // table within that function. |
880 std::sort(JumpTables.begin(), JumpTables.end(), | 878 std::sort(JumpTables.begin(), JumpTables.end(), |
881 [](const JumpTableData &A, const JumpTableData &B) { | 879 [](const JumpTableData &A, const JumpTableData &B) { |
882 if (A.getFunctionName() != B.getFunctionName()) | 880 if (A.getFunctionName() != B.getFunctionName()) |
883 return A.getFunctionName() < B.getFunctionName(); | 881 return A.getFunctionName() < B.getFunctionName(); |
884 return A.getId() < B.getId(); | 882 return A.getId() < B.getId(); |
885 }); | 883 }); |
886 | 884 |
887 if (getFlags().shouldReorderPooledConstants()) { | 885 if (getFlags().shouldReorderPooledConstants()) { |
888 // If reorder-pooled-constants option is set to true, we also shuffle the | 886 // If reorder-pooled-constants option is set to true, we also shuffle the |
889 // jump tables before emitting them. | 887 // jump tables before emitting them. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
939 Timers->at(StackID).reset(); | 937 Timers->at(StackID).reset(); |
940 } | 938 } |
941 | 939 |
942 void GlobalContext::setTimerName(TimerStackIdT StackID, | 940 void GlobalContext::setTimerName(TimerStackIdT StackID, |
943 const IceString &NewName) { | 941 const IceString &NewName) { |
944 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; | 942 auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
945 assert(StackID < Timers->size()); | 943 assert(StackID < Timers->size()); |
946 Timers->at(StackID).setName(NewName); | 944 Timers->at(StackID).setName(NewName); |
947 } | 945 } |
948 | 946 |
949 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr | 947 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr at the |
950 // at the interface to take and transfer ownership, but they | 948 // interface to take and transfer ownership, but they internally store the raw |
951 // internally store the raw Cfg pointer in the work queue. This | 949 // Cfg pointer in the work queue. This allows e.g. future queue optimizations |
952 // allows e.g. future queue optimizations such as the use of atomics | 950 // such as the use of atomics to modify queue elements. |
953 // to modify queue elements. | |
954 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { | 951 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { |
955 assert(Func); | 952 assert(Func); |
956 OptQ.blockingPush(Func.release()); | 953 OptQ.blockingPush(Func.release()); |
957 if (getFlags().isSequential()) | 954 if (getFlags().isSequential()) |
958 translateFunctions(); | 955 translateFunctions(); |
959 } | 956 } |
960 | 957 |
961 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { | 958 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { |
962 return std::unique_ptr<Cfg>(OptQ.blockingPop()); | 959 return std::unique_ptr<Cfg>(OptQ.blockingPop()); |
963 } | 960 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 Ctx = Func->getContext(); | 1009 Ctx = Func->getContext(); |
1013 Active = | 1010 Active = |
1014 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); | 1011 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
1015 if (Active) | 1012 if (Active) |
1016 Ctx->pushTimer(ID, StackID); | 1013 Ctx->pushTimer(ID, StackID); |
1017 } | 1014 } |
1018 | 1015 |
1019 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); | 1016 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
1020 | 1017 |
1021 } // end of namespace Ice | 1018 } // end of namespace Ice |
OLD | NEW |