diff --git a/gcc/testsuite/g++.dg/opt/pr110515.C b/gcc/testsuite/g++.dg/opt/pr110515.C new file mode 100644 index 00000000000..7a75cea3b4b --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr110515.C @@ -0,0 +1,223 @@ +// { dg-do run } +// { dg-require-effective-target c++11 } +// { dg-options "-O2" } + +typedef __UINT64_TYPE__ u64; + +struct SmallDenseMap { + static constexpr u64 EmptyKey = 0xC0FFEUL; + struct V { u64 v; }; + + bool contains(u64 Val) { + V *TheSlot = nullptr; + return (LookupSlotFor(Val, TheSlot) ? 1 : 0); + } + + void try_emplace(u64 Key) { + V *TheSlot = nullptr; + if (LookupSlotFor(Key, TheSlot)) + return; + + // Otherwise, insert the new element. + InsertIntoSlot(TheSlot, Key); + } + + void moveFromOldSlots(V *OldSlotsBegin, V *OldSlotsEnd) { + Size = 0; + + V *B_ = u.o.Slots; + V *E_ = B_ + u.o.Capacity; + for (; B_ != E_; ++B_) + B_->v = EmptyKey; + + // Insert all the old elements. + V *O = OldSlotsBegin; + V *E = OldSlotsEnd; + for (; O != E; ++O) { + if (O->v != EmptyKey) { + // Insert the key/value into the new table. + V * N = nullptr; + LookupSlotFor(O->v, N); + N->v = O->v; + Size++; + } + } + } + + void InsertIntoSlot(V *TheSlot, u64 Key) { + unsigned NewSize = Size + 1; + unsigned Capacity = getCapacity(); + // Make sure we always keep at least one Empty value + if (NewSize >= Capacity) { + //fprintf(stderr, "GROW: size=%u capacity=%u -> ...\n", Size, Capacity); + grow(); + LookupSlotFor(Key, TheSlot); + Capacity = getCapacity(); + //fprintf(stderr, "GROW: ... -> size=%u capacity=%u\n", NewSize, Capacity); + } + + Size++; + + TheSlot->v = Key; + } + + bool LookupSlotFor(u64 Val, + V *&FoundSlot) { + V *SlotsPtr = getSlots(); + const unsigned Capacity = getCapacity(); + + for (unsigned i = 0; i < Capacity; ++i) { + V *ThisSlot = SlotsPtr + i; + if (Val == ThisSlot->v) { + FoundSlot = ThisSlot; + return true; + } + + if (ThisSlot->v == EmptyKey) { + FoundSlot = ThisSlot; + return false; + } + } + // Guarantee that within an array there is a match + // or Empty value where to insert a new vaue. + __builtin_trap(); + } + + // Needs to bea at least 1 to hld one empty value + static constexpr unsigned InlineSlots = 2; + + bool Small; + unsigned Size; + + struct LargeRep { + V *Slots; + unsigned Capacity; + }; + + union { + V i[InlineSlots]; // Small = true + LargeRep o; // Small = false + } u; + + explicit SmallDenseMap() : Small(true), Size(0) { + Size = 0; + + V *B = u.i; + V *E = B + InlineSlots; + for (; B != E; ++B) + B->v = EmptyKey; + } + + void grow() { + // assert: + if (!Small) __builtin_trap(); + + // First move the inline Slots into a temporary storage. + V TmpStorage[InlineSlots]; + V *TmpBegin = TmpStorage; + V *TmpEnd = TmpBegin; + + // Loop over the Slots, moving non-empty, non-tombstones into the + // temporary storage. Have the loop move the TmpEnd forward as it goes. + V *P = u.i; + V *E = P + InlineSlots; + for (; P != E; ++P) { + if (P->v != EmptyKey) { + TmpEnd->v = P->v; + ++TmpEnd; + } + } + + Small = false; + u.o = LargeRep{new V[128], 128}; + moveFromOldSlots(TmpBegin, TmpEnd); + } + + V *getSlots() { + if (Small) { + V * inl = u.i; + return inl; + } + else { + LargeRep * rep = &u.o; + return rep->Slots; + } + } + + unsigned getCapacity() { + if (Small) { + return InlineSlots; + } + else { + LargeRep * rep = &u.o; + return rep->Capacity; + } + } +}; + +#pragma GCC optimize(0) + +struct P { + u64 f; + bool s; +}; + +static u64 ws = 0; +static P WorkList[128]; + +__attribute__((noipa)) +static void popupateIni() { + for (u64 Var : (u64[]){8,7,6,5,4,3,0}) { + WorkList[ws++] = P{Var, false}; + } +} + +__attribute__((noipa)) +static void checkCycle(u64 Var) { + // Detect cycles. + static bool seen[256]; + if (Var >= 256 || seen[Var]) __builtin_trap(); + seen[Var] = true; +} + + +__attribute__((noipa)) +static void populateDeps(u64 Var) { + + WorkList[ws++] = P{Var, true}; + if (Var == 8) + WorkList[ws++] = P{0, false}; +} + + +__attribute__((noipa)) __attribute__((optimize(3))) +static void bug() { + + // triggers growth on insert + SmallDenseMap Visited; + + popupateIni(); + + while (ws > 0) { + P Item = WorkList[--ws]; + u64 Var = Item.f; + bool visitedAllDependencies = Item.s; + + if (Visited.contains(Var)) { + continue; + } + + if (visitedAllDependencies) { + Visited.try_emplace(Var); + continue; + } + + checkCycle(Var); + populateDeps(Var); + } +} + +__attribute__((noipa)) +int main() { + bug(); +} diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc index 37cad36f2de..7bc96ba95fa 100644 --- a/gcc/tree-ssa-pre.cc +++ b/gcc/tree-ssa-pre.cc @@ -4209,6 +4209,7 @@ compute_avail (function *fun) else { ref->set = 0; + ref->base_set = 0; if (ref1->opcode == MEM_REF) ref1->op0 = wide_int_to_tree (ptr_type_node,