diff --git a/src/coreclr/jit/jitstd/vector.h b/src/coreclr/jit/jitstd/vector.h index 69f67817ecb6e9..78dadd3651e87a 100644 --- a/src/coreclr/jit/jitstd/vector.h +++ b/src/coreclr/jit/jitstd/vector.h @@ -145,6 +145,7 @@ class vector // cctors vector(const vector& vec); + vector(vector&& vec); template explicit vector(const vector& vec); @@ -195,6 +196,8 @@ class vector template vector& operator=(const vector& vec); + vector& operator=(vector&& vec); + reference operator[](size_type n); const_reference operator[](size_type n) const; @@ -328,6 +331,18 @@ vector::vector(const vector& vec) } } +template +vector::vector(vector&& vec) + : m_allocator(vec.m_allocator) + , m_pArray(vec.m_pArray) + , m_nSize(vec.m_nSize) + , m_nCapacity(vec.m_nCapacity) +{ + vec.m_pArray = nullptr; + vec.m_nSize = 0; + vec.m_nCapacity = 0; +} + template vector::~vector() { @@ -578,6 +593,20 @@ vector& vector::operator=(const vector return *this; } +template +vector& vector::operator=(vector&& vec) +{ + m_allocator = vec.m_allocator; + m_pArray = vec.m_pArray; + m_nSize = vec.m_nSize; + m_nCapacity = vec.m_nCapacity; + + vec.m_pArray = nullptr; + vec.m_nSize = 0; + vec.m_nCapacity = 0; + + return *this; +} template typename vector::reference vector::operator[](size_type n) diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index 52163f4db0cceb..5d1155b701f616 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -1229,19 +1229,18 @@ class LocalsUseVisitor : public GenTreeVisitor } #endif - StructSegments unpromotedParts = - m_prom->SignificantSegments(m_compiler->lvaGetDesc(agg->LclNum)->GetLayout()); + agg->Unpromoted = m_prom->SignificantSegments(m_compiler->lvaGetDesc(agg->LclNum)->GetLayout()); for (Replacement& rep : reps) { - unpromotedParts.Subtract(StructSegments::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType))); + agg->Unpromoted.Subtract(StructSegments::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType))); } JITDUMP(" Unpromoted remainder: "); - DBEXEC(m_compiler->verbose, unpromotedParts.Dump()); + DBEXEC(m_compiler->verbose, agg->Unpromoted.Dump()); JITDUMP("\n\n"); StructSegments::Segment unpromotedSegment; - if (unpromotedParts.CoveringSegment(&unpromotedSegment)) + if (agg->Unpromoted.CoveringSegment(&unpromotedSegment)) { agg->UnpromotedMin = unpromotedSegment.Start; agg->UnpromotedMax = unpromotedSegment.End; @@ -1495,6 +1494,31 @@ bool StructSegments::Segment::IntersectsOrAdjacent(const Segment& other) const return true; } +//------------------------------------------------------------------------ +// Intersects: +// Check if this segment intersects another segment. +// +// Parameters: +// other - The other segment. +// +// Returns: +// True if so. +// +bool StructSegments::Segment::Intersects(const Segment& other) const +{ + if (End <= other.Start) + { + return false; + } + + if (other.End <= Start) + { + return false; + } + + return true; +} + //------------------------------------------------------------------------ // Contains: // Check if this segment contains another segment. @@ -1586,7 +1610,7 @@ void StructSegments::Subtract(const Segment& segment) return; } - assert(m_segments[index].IntersectsOrAdjacent(segment)); + assert(m_segments[index].Intersects(segment)); if (m_segments[index].Contains(segment)) { @@ -1679,6 +1703,46 @@ bool StructSegments::CoveringSegment(Segment* result) return true; } +//------------------------------------------------------------------------ +// Intersects: +// Check if a segment intersects with any segment in this segment tree. +// +// Parameters: +// segment - The segment. +// +// Returns: +// True if the input segment intersects with any segment in the tree; +// otherwise false. +// +bool StructSegments::Intersects(const Segment& segment) +{ + size_t index = Promotion::BinarySearch(m_segments, segment.Start); + if ((ssize_t)index < 0) + { + index = ~index; + } + else + { + // Start == segment[index].End, which makes it non-interesting. + index++; + } + + if (index >= m_segments.size()) + { + return false; + } + + // Here we know Start < segment[index].End. Do they not intersect at all? + if (m_segments[index].Start >= segment.End) + { + // Does not intersect any segment. + return false; + } + + assert(m_segments[index].Intersects(segment)); + return true; +} + #ifdef DEBUG //------------------------------------------------------------------------ // Dump: diff --git a/src/coreclr/jit/promotion.h b/src/coreclr/jit/promotion.h index 0efde03da59256..c421b019bc8f99 100644 --- a/src/coreclr/jit/promotion.h +++ b/src/coreclr/jit/promotion.h @@ -60,6 +60,7 @@ class StructSegments } bool IntersectsOrAdjacent(const Segment& other) const; + bool Intersects(const Segment& other) const; bool Contains(const Segment& other) const; void Merge(const Segment& other); }; @@ -68,7 +69,7 @@ class StructSegments jitstd::vector m_segments; public: - StructSegments(CompAllocator allocator) : m_segments(allocator) + explicit StructSegments(CompAllocator allocator) : m_segments(allocator) { } @@ -76,6 +77,7 @@ class StructSegments void Subtract(const Segment& segment); bool IsEmpty(); bool CoveringSegment(Segment* result); + bool Intersects(const Segment& segment); #ifdef DEBUG void Dump(); @@ -87,12 +89,14 @@ struct AggregateInfo { jitstd::vector Replacements; unsigned LclNum; + // Unpromoted parts of the struct local. + StructSegments Unpromoted; // Min offset in the struct local of the unpromoted part. unsigned UnpromotedMin = 0; // Max offset in the struct local of the unpromoted part. unsigned UnpromotedMax = 0; - AggregateInfo(CompAllocator alloc, unsigned lclNum) : Replacements(alloc), LclNum(lclNum) + AggregateInfo(CompAllocator alloc, unsigned lclNum) : Replacements(alloc), LclNum(lclNum), Unpromoted(alloc) { } diff --git a/src/coreclr/jit/promotionliveness.cpp b/src/coreclr/jit/promotionliveness.cpp index 5f9fffdb95a291..77078bddb4c297 100644 --- a/src/coreclr/jit/promotionliveness.cpp +++ b/src/coreclr/jit/promotionliveness.cpp @@ -242,9 +242,8 @@ void PromotionLiveness::MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, Bit } bool isFullDefOfRemainder = isDef && (agg->UnpromotedMin >= offs) && (agg->UnpromotedMax <= (offs + size)); - // TODO-CQ: We could also try to figure out if a use actually touches the remainder, e.g. in some cases - // a struct use may consist only of promoted fields and does not actually use the remainder. - MarkIndex(baseIndex, isUse, isFullDefOfRemainder, useSet, defSet); + bool isUseOfRemainder = isUse && agg->Unpromoted.Intersects(StructSegments::Segment(offs, offs + size)); + MarkIndex(baseIndex, isUseOfRemainder, isFullDefOfRemainder, useSet, defSet); } } else @@ -609,11 +608,9 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, GenTre } else { - // TODO-CQ: We could also try to figure out if a use actually touches the remainder, e.g. in some cases - // a struct use may consist only of promoted fields and does not actually use the remainder. BitVecOps::AddElemD(&aggTraits, aggDeaths, 0); - if (isUse) + if (isUse && agg->Unpromoted.Intersects(StructSegments::Segment(offs, offs + size))) { BitVecOps::AddElemD(m_bvTraits, life, baseIndex); }