@@ -934,38 +934,101 @@ struct TempMDNodeDeleter {
934934// / If an unresolved node is part of a cycle, \a resolveCycles() needs
935935// / to be called on some member of the cycle once all temporary nodes have been
936936// / replaced.
937+ // /
938+ // / MDNodes can be large or small, as well as resizable or non-resizable.
939+ // / Large MDNodes' operands are allocated in a separate storage vector,
940+ // / whereas small MDNodes' operands are co-allocated. Distinct and temporary
941+ // / MDnodes are resizable, but only MDTuples support this capability.
942+ // /
943+ // / Clients can add operands to resizable MDNodes using push_back().
937944class MDNode : public Metadata {
938945 friend class ReplaceableMetadataImpl ;
939946 friend class LLVMContextImpl ;
940947 friend class DIArgList ;
941948
942- // / The header that is coallocated with an MDNode, along with the operands.
943- // / It is located immediately before the main body of the node. The operands
944- // / are in turn located immediately before the header.
949+ // / The header that is coallocated with an MDNode along with its "small"
950+ // / operands. It is located immediately before the main body of the node.
951+ // / The operands are in turn located immediately before the header.
952+ // / For resizable MDNodes, the space for the storage vector is also allocated
953+ // / immediately before the header, overlapping with the operands.
945954 struct Header {
946- unsigned NumOperands;
955+ bool IsResizable : 1 ;
956+ bool IsLarge : 1 ;
957+ size_t SmallSize : 4 ;
958+ size_t SmallNumOps : 4 ;
959+ size_t : sizeof (size_t ) * CHAR_BIT - 10 ;
960+
947961 unsigned NumUnresolved = 0 ;
962+ using LargeStorageVector = SmallVector<MDOperand, 0 >;
963+
964+ static constexpr size_t NumOpsFitInVector =
965+ sizeof (LargeStorageVector) / sizeof (MDOperand);
966+ static_assert (
967+ NumOpsFitInVector * sizeof (MDOperand) == sizeof(LargeStorageVector),
968+ "sizeof(LargeStorageVector) must be a multiple of sizeof(MDOperand)");
969+
970+ static constexpr size_t MaxSmallSize = 15 ;
948971
949972 static constexpr size_t getOpSize (unsigned NumOps) {
950973 return sizeof (MDOperand) * NumOps;
951974 }
952- static constexpr size_t getAllocSize (unsigned NumOps) {
953- return getOpSize (NumOps) + sizeof (Header);
975+ // / Returns the number of operands the node has space for based on its
976+ // / allocation characteristics.
977+ static size_t getSmallSize (size_t NumOps, bool IsResizable, bool IsLarge) {
978+ return IsLarge ? NumOpsFitInVector
979+ : std::max (NumOps, NumOpsFitInVector * IsResizable);
980+ }
981+ // / Returns the number of bytes allocated for operands and header.
982+ static size_t getAllocSize (StorageType Storage, size_t NumOps) {
983+ return getOpSize (
984+ getSmallSize (NumOps, isResizable (Storage), isLarge (NumOps))) +
985+ sizeof (Header);
986+ }
987+
988+ // / Only temporary and distinct nodes are resizable.
989+ static bool isResizable (StorageType Storage) { return Storage != Uniqued; }
990+ static bool isLarge (size_t NumOps) { return NumOps > MaxSmallSize; }
991+
992+ size_t getAllocSize () const {
993+ return getOpSize (SmallSize) + sizeof (Header);
954994 }
955995 void *getAllocation () {
956996 return reinterpret_cast <char *>(this + 1 ) -
957- alignTo (getAllocSize (NumOperands), alignof (uint64_t ));
997+ alignTo (getAllocSize (), alignof (uint64_t ));
998+ }
999+
1000+ void *getLargePtr () const ;
1001+ void *getSmallPtr ();
1002+
1003+ LargeStorageVector &getLarge () {
1004+ assert (IsLarge);
1005+ return *reinterpret_cast <LargeStorageVector *>(getLargePtr ());
9581006 }
9591007
960- explicit Header (unsigned NumOperands);
1008+ const LargeStorageVector &getLarge () const {
1009+ assert (IsLarge);
1010+ return *reinterpret_cast <const LargeStorageVector *>(getLargePtr ());
1011+ }
1012+
1013+ void resizeSmall (size_t NumOps);
1014+ void resizeSmallToLarge (size_t NumOps);
1015+ void resize (size_t NumOps);
1016+
1017+ explicit Header (size_t NumOps, StorageType Storage);
9611018 ~Header ();
1019+
9621020 MutableArrayRef<MDOperand> operands () {
1021+ if (IsLarge)
1022+ return getLarge ();
9631023 return makeMutableArrayRef (
964- reinterpret_cast <MDOperand *>(this ) - NumOperands, NumOperands );
1024+ reinterpret_cast <MDOperand *>(this ) - SmallSize, SmallNumOps );
9651025 }
1026+
9661027 ArrayRef<MDOperand> operands () const {
967- return makeArrayRef (
968- reinterpret_cast <const MDOperand *>(this ) - NumOperands, NumOperands);
1028+ if (IsLarge)
1029+ return getLarge ();
1030+ return makeArrayRef (reinterpret_cast <const MDOperand *>(this ) - SmallSize,
1031+ SmallNumOps);
9691032 }
9701033 };
9711034
@@ -982,7 +1045,7 @@ class MDNode : public Metadata {
9821045 ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> Ops2 = None);
9831046 ~MDNode () = default ;
9841047
985- void *operator new (size_t Size, unsigned NumOps, StorageType Storage);
1048+ void *operator new (size_t Size, size_t NumOps, StorageType Storage);
9861049 void operator delete (void *Mem);
9871050
9881051 // / Required by std, but never called.
@@ -1146,6 +1209,17 @@ class MDNode : public Metadata {
11461209 static T *storeImpl (T *N, StorageType Storage, StoreT &Store);
11471210 template <class T > static T *storeImpl (T *N, StorageType Storage);
11481211
1212+ // / Resize the node to hold \a NumOps operands.
1213+ // /
1214+ // / \pre \a isTemporary() or \a isDistinct()
1215+ // / \pre MetadataID == MDTupleKind
1216+ void resize (size_t NumOps) {
1217+ assert (!isUniqued () && " Resizing is not supported for uniqued nodes" );
1218+ assert (getMetadataID () == MDTupleKind &&
1219+ " Resizing is not supported for this node kind" );
1220+ getHeader ().resize (NumOps);
1221+ }
1222+
11491223private:
11501224 void handleChangedOperand (void *Ref, Metadata *New);
11511225
@@ -1207,7 +1281,7 @@ class MDNode : public Metadata {
12071281 }
12081282
12091283 // / Return number of MDNode operands.
1210- unsigned getNumOperands () const { return getHeader ().NumOperands ; }
1284+ unsigned getNumOperands () const { return getHeader ().operands (). size () ; }
12111285
12121286 // / Methods for support type inquiry through isa, cast, and dyn_cast:
12131287 static bool classof (const Metadata *MD) {
@@ -1292,6 +1366,16 @@ class MDTuple : public MDNode {
12921366 // / Return a (temporary) clone of this.
12931367 TempMDTuple clone () const { return cloneImpl (); }
12941368
1369+ // / Append an element to the tuple. This will resize the node.
1370+ void push_back (Metadata *MD) {
1371+ size_t NumOps = getNumOperands ();
1372+ resize (NumOps + 1 );
1373+ setOperand (NumOps, MD);
1374+ }
1375+
1376+ // / Shrink the operands by 1.
1377+ void pop_back () { resize (getNumOperands () - 1 ); }
1378+
12951379 static bool classof (const Metadata *MD) {
12961380 return MD->getMetadataID () == MDTupleKind;
12971381 }
0 commit comments