<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Thank you. <div><br><div><div><div>On Mar 18, 2013, at 1:36 AM, Chandler Carruth <<a href="mailto:chandlerc@gmail.com">chandlerc@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">Author: chandlerc<br>Date: Mon Mar 18 03:36:46 2013<br>New Revision: 177259<br><br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project?rev=177259&view=rev">http://llvm.org/viewvc/llvm-project?rev=177259&view=rev</a><br>Log:<br>Mark internal classes as POD-like to get better behavior out of<br>SmallVector and DenseMap.<br><br>This speeds up SROA by 25% on PR15412.<br><br>Modified:<br> llvm/trunk/lib/Transforms/Scalar/SROA.cpp<br><br>Modified: llvm/trunk/lib/Transforms/Scalar/SROA.cpp<br>URL:<span class="Apple-converted-space"> </span><a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SROA.cpp?rev=177259&r1=177258&r2=177259&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SROA.cpp?rev=177259&r1=177258&r2=177259&view=diff</a><br>==============================================================================<br>--- llvm/trunk/lib/Transforms/Scalar/SROA.cpp (original)<br>+++ llvm/trunk/lib/Transforms/Scalar/SROA.cpp Mon Mar 18 03:36:46 2013<br>@@ -69,123 +69,130 @@ static cl::opt<bool><br>ForceSSAUpdater("force-ssa-updater", cl::init(false), cl::Hidden);<br><br>namespace {<br>-/// \brief Alloca partitioning representation.<br>-///<br>-/// This class represents a partitioning of an alloca into slices, and<br>-/// information about the nature of uses of each slice of the alloca. The goal<br>-/// is that this information is sufficient to decide if and how to split the<br>-/// alloca apart and replace slices with scalars. It is also intended that this<br>-/// structure can capture the relevant information needed both to decide about<br>-/// and to enact these transformations.<br>-class AllocaPartitioning {<br>-public:<br>- /// \brief A common base class for representing a half-open byte range.<br>- struct ByteRange {<br>- /// \brief The beginning offset of the range.<br>- uint64_t BeginOffset;<br>-<br>- /// \brief The ending offset, not included in the range.<br>- uint64_t EndOffset;<br>-<br>- ByteRange() : BeginOffset(), EndOffset() {}<br>- ByteRange(uint64_t BeginOffset, uint64_t EndOffset)<br>- : BeginOffset(BeginOffset), EndOffset(EndOffset) {}<br>-<br>- /// \brief Support for ordering ranges.<br>- ///<br>- /// This provides an ordering over ranges such that start offsets are<br>- /// always increasing, and within equal start offsets, the end offsets are<br>- /// decreasing. Thus the spanning range comes first in a cluster with the<br>- /// same start position.<br>- bool operator<(const ByteRange &RHS) const {<br>- if (BeginOffset < RHS.BeginOffset) return true;<br>- if (BeginOffset > RHS.BeginOffset) return false;<br>- if (EndOffset > RHS.EndOffset) return true;<br>- return false;<br>- }<br>-<br>- /// \brief Support comparison with a single offset to allow binary searches.<br>- friend bool operator<(const ByteRange &LHS, uint64_t RHSOffset) {<br>- return LHS.BeginOffset < RHSOffset;<br>- }<br>+/// \brief A common base class for representing a half-open byte range.<br>+struct ByteRange {<br>+ /// \brief The beginning offset of the range.<br>+ uint64_t BeginOffset;<br><br>- friend LLVM_ATTRIBUTE_UNUSED bool operator<(uint64_t LHSOffset,<br>- const ByteRange &RHS) {<br>- return LHSOffset < RHS.BeginOffset;<br>- }<br>+ /// \brief The ending offset, not included in the range.<br>+ uint64_t EndOffset;<br><br>- bool operator==(const ByteRange &RHS) const {<br>- return BeginOffset == RHS.BeginOffset && EndOffset == RHS.EndOffset;<br>- }<br>- bool operator!=(const ByteRange &RHS) const { return !operator==(RHS); }<br>- };<br>+ ByteRange() : BeginOffset(), EndOffset() {}<br>+ ByteRange(uint64_t BeginOffset, uint64_t EndOffset)<br>+ : BeginOffset(BeginOffset), EndOffset(EndOffset) {}<br><br>- /// \brief A partition of an alloca.<br>+ /// \brief Support for ordering ranges.<br> ///<br>- /// This structure represents a contiguous partition of the alloca. These are<br>- /// formed by examining the uses of the alloca. During formation, they may<br>- /// overlap but once an AllocaPartitioning is built, the Partitions within it<br>- /// are all disjoint.<br>- struct Partition : public ByteRange {<br>- /// \brief Whether this partition is splittable into smaller partitions.<br>- ///<br>- /// We flag partitions as splittable when they are formed entirely due to<br>- /// accesses by trivially splittable operations such as memset and memcpy.<br>- bool IsSplittable;<br>+ /// This provides an ordering over ranges such that start offsets are<br>+ /// always increasing, and within equal start offsets, the end offsets are<br>+ /// decreasing. Thus the spanning range comes first in a cluster with the<br>+ /// same start position.<br>+ bool operator<(const ByteRange &RHS) const {<br>+ if (BeginOffset < RHS.BeginOffset) return true;<br>+ if (BeginOffset > RHS.BeginOffset) return false;<br>+ if (EndOffset > RHS.EndOffset) return true;<br>+ return false;<br>+ }<br><br>- /// \brief Test whether a partition has been marked as dead.<br>- bool isDead() const {<br>- if (BeginOffset == UINT64_MAX) {<br>- assert(EndOffset == UINT64_MAX);<br>- return true;<br>- }<br>- return false;<br>- }<br>+ /// \brief Support comparison with a single offset to allow binary searches.<br>+ friend bool operator<(const ByteRange &LHS, uint64_t RHSOffset) {<br>+ return LHS.BeginOffset < RHSOffset;<br>+ }<br><br>- /// \brief Kill a partition.<br>- /// This is accomplished by setting both its beginning and end offset to<br>- /// the maximum possible value.<br>- void kill() {<br>- assert(!isDead() && "He's Dead, Jim!");<br>- BeginOffset = EndOffset = UINT64_MAX;<br>- }<br>+ friend LLVM_ATTRIBUTE_UNUSED bool operator<(uint64_t LHSOffset,<br>+ const ByteRange &RHS) {<br>+ return LHSOffset < RHS.BeginOffset;<br>+ }<br><br>- Partition() : ByteRange(), IsSplittable() {}<br>- Partition(uint64_t BeginOffset, uint64_t EndOffset, bool IsSplittable)<br>- : ByteRange(BeginOffset, EndOffset), IsSplittable(IsSplittable) {}<br>- };<br>+ bool operator==(const ByteRange &RHS) const {<br>+ return BeginOffset == RHS.BeginOffset && EndOffset == RHS.EndOffset;<br>+ }<br>+ bool operator!=(const ByteRange &RHS) const { return !operator==(RHS); }<br>+};<br><br>- /// \brief A particular use of a partition of the alloca.<br>- ///<br>- /// This structure is used to associate uses of a partition with it. They<br>- /// mark the range of bytes which are referenced by a particular instruction,<br>- /// and includes a handle to the user itself and the pointer value in use.<br>- /// The bounds of these uses are determined by intersecting the bounds of the<br>- /// memory use itself with a particular partition. As a consequence there is<br>- /// intentionally overlap between various uses of the same partition.<br>- class PartitionUse : public ByteRange {<br>- /// \brief Combined storage for both the Use* and split state.<br>- PointerIntPair<Use*, 1, bool> UsePtrAndIsSplit;<br>-<br>- public:<br>- PartitionUse() : ByteRange(), UsePtrAndIsSplit() {}<br>- PartitionUse(uint64_t BeginOffset, uint64_t EndOffset, Use *U,<br>- bool IsSplit)<br>- : ByteRange(BeginOffset, EndOffset), UsePtrAndIsSplit(U, IsSplit) {}<br>-<br>- /// \brief The use in question. Provides access to both user and used value.<br>- ///<br>- /// Note that this may be null if the partition use is *dead*, that is, it<br>- /// should be ignored.<br>- Use *getUse() const { return UsePtrAndIsSplit.getPointer(); }<br>+/// \brief A partition of an alloca.<br>+///<br>+/// This structure represents a contiguous partition of the alloca. These are<br>+/// formed by examining the uses of the alloca. During formation, they may<br>+/// overlap but once an AllocaPartitioning is built, the Partitions within it<br>+/// are all disjoint.<br>+struct Partition : public ByteRange {<br>+ /// \brief Whether this partition is splittable into smaller partitions.<br>+ ///<br>+ /// We flag partitions as splittable when they are formed entirely due to<br>+ /// accesses by trivially splittable operations such as memset and memcpy.<br>+ bool IsSplittable;<br>+<br>+ /// \brief Test whether a partition has been marked as dead.<br>+ bool isDead() const {<br>+ if (BeginOffset == UINT64_MAX) {<br>+ assert(EndOffset == UINT64_MAX);<br>+ return true;<br>+ }<br>+ return false;<br>+ }<br>+<br>+ /// \brief Kill a partition.<br>+ /// This is accomplished by setting both its beginning and end offset to<br>+ /// the maximum possible value.<br>+ void kill() {<br>+ assert(!isDead() && "He's Dead, Jim!");<br>+ BeginOffset = EndOffset = UINT64_MAX;<br>+ }<br>+<br>+ Partition() : ByteRange(), IsSplittable() {}<br>+ Partition(uint64_t BeginOffset, uint64_t EndOffset, bool IsSplittable)<br>+ : ByteRange(BeginOffset, EndOffset), IsSplittable(IsSplittable) {}<br>+};<br><br>- /// \brief Set the use for this partition use range.<br>- void setUse(Use *U) { UsePtrAndIsSplit.setPointer(U); }<br>+/// \brief A particular use of a partition of the alloca.<br>+///<br>+/// This structure is used to associate uses of a partition with it. They<br>+/// mark the range of bytes which are referenced by a particular instruction,<br>+/// and includes a handle to the user itself and the pointer value in use.<br>+/// The bounds of these uses are determined by intersecting the bounds of the<br>+/// memory use itself with a particular partition. As a consequence there is<br>+/// intentionally overlap between various uses of the same partition.<br>+class PartitionUse : public ByteRange {<br>+ /// \brief Combined storage for both the Use* and split state.<br>+ PointerIntPair<Use*, 1, bool> UsePtrAndIsSplit;<br><br>- /// \brief Whether this use is split across multiple partitions.<br>- bool isSplit() const { return UsePtrAndIsSplit.getInt(); }<br>- };<br>+public:<br>+ PartitionUse() : ByteRange(), UsePtrAndIsSplit() {}<br>+ PartitionUse(uint64_t BeginOffset, uint64_t EndOffset, Use *U,<br>+ bool IsSplit)<br>+ : ByteRange(BeginOffset, EndOffset), UsePtrAndIsSplit(U, IsSplit) {}<br>+<br>+ /// \brief The use in question. Provides access to both user and used value.<br>+ ///<br>+ /// Note that this may be null if the partition use is *dead*, that is, it<br>+ /// should be ignored.<br>+ Use *getUse() const { return UsePtrAndIsSplit.getPointer(); }<br>+<br>+ /// \brief Set the use for this partition use range.<br>+ void setUse(Use *U) { UsePtrAndIsSplit.setPointer(U); }<br>+<br>+ /// \brief Whether this use is split across multiple partitions.<br>+ bool isSplit() const { return UsePtrAndIsSplit.getInt(); }<br>+};<br>+}<br><br>+namespace llvm {<br>+template <> struct isPodLike<Partition> : llvm::true_type {};<br>+template <> struct isPodLike<PartitionUse> : llvm::true_type {};<br>+}<br>+<br>+namespace {<br>+/// \brief Alloca partitioning representation.<br>+///<br>+/// This class represents a partitioning of an alloca into slices, and<br>+/// information about the nature of uses of each slice of the alloca. The goal<br>+/// is that this information is sufficient to decide if and how to split the<br>+/// alloca apart and replace slices with scalars. It is also intended that this<br>+/// structure can capture the relevant information needed both to decide about<br>+/// and to enact these transformations.<br>+class AllocaPartitioning {<br>+public:<br> /// \brief Construct a partitioning of a particular alloca.<br> ///<br> /// Construction does most of the work for partitioning the alloca. This<br>@@ -1389,7 +1396,7 @@ public:<br> // may be grown during speculation. However, we never need to re-visit the<br> // new uses, and so we can use the initial size bound.<br> for (unsigned Idx = 0, Size = P.use_size(PI); Idx != Size; ++Idx) {<br>- const AllocaPartitioning::PartitionUse &PU = P.getUse(PI, Idx);<br>+ const PartitionUse &PU = P.getUse(PI, Idx);<br> if (!PU.getUse())<br> continue; // Skip dead use.<br><br>@@ -1594,7 +1601,7 @@ private:<br> IRBuilder<> IRB(&SI);<br> Use *Ops[2] = { &SI.getOperandUse(1), &SI.getOperandUse(2) };<br> AllocaPartitioning::iterator PIs[2];<br>- AllocaPartitioning::PartitionUse PUs[2];<br>+ PartitionUse PUs[2];<br> for (unsigned i = 0, e = 2; i != e; ++i) {<br> PIs[i] = P.findPartitionForPHIOrSelectOperand(Ops[i]);<br> if (PIs[i] != P.end()) {<br><br><br>_______________________________________________<br>llvm-commits mailing list<br><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br><a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a></div></blockquote></div><br></div></div></body></html>