Index: lib/Transform/DeLICM.cpp =================================================================== --- lib/Transform/DeLICM.cpp +++ lib/Transform/DeLICM.cpp @@ -677,7 +677,12 @@ return true; } - // Do the writes in Existing only overwrite unused values in Proposed? + // Do the writes in Existing conflict with occupied values in Proposed? + // In order to not conflict, it must either write to unused lifetime or + // write the same value. To check, we remove the writes that write into + // Proposed.Unused (they never conflict) and then see whether the written + // value is already in Proposed.Known. + // // We convert here the set of lifetimes to actual timepoints. A lifetime is // in conflict with a set of write timepoints, if either a live timepoint is // clearly within the lifetime or if a write happens at the beginning of the @@ -688,41 +693,72 @@ // Knowledge to check this property also for accesses to MemoryKind::Array. auto ProposedFixedDefs = convertZoneToTimepoints(Proposed.Occupied, true, false); - auto ExistingWrittenDomain = - isl::manage(isl_union_map_domain(Existing.Written.copy())); - if (isl_union_set_is_disjoint(ExistingWrittenDomain.keep(), - ProposedFixedDefs.keep()) != isl_bool_true) { + auto ProposedFixedKnown = + convertZoneToTimepoints(Proposed.Known, isl::dim::in, true, false); + + auto ExistingConflictingWrites = + Existing.Written.intersect_domain(ProposedFixedDefs); + auto ExistingConflictingWritesDomain = ExistingConflictingWrites.domain(); + + auto SomeWrittenVal = + ProposedFixedKnown.intersect(ExistingConflictingWrites); + auto SomeWrittenValDomain = SomeWrittenVal.domain(); + + if (!ExistingConflictingWritesDomain.is_subset(SomeWrittenValDomain)) { if (OS) { - auto ConflictingWrites = give(isl_union_set_intersect( - ExistingWrittenDomain.copy(), ProposedFixedDefs.copy())); - OS->indent(Indent) << "Proposed writes into range used by existing\n"; - OS->indent(Indent) << "Conflicting writes: " << ConflictingWrites - << "\n"; + auto ExistingConflictingWritten = + ExistingConflictingWrites.subtract_domain(SomeWrittenValDomain); + auto ProposedConflictingKnown = ProposedFixedKnown.subtract_domain( + ExistingConflictingWritten.domain()); + + OS->indent(Indent) + << "Proposed a lifetime where there is an Existing write into it\n"; + OS->indent(Indent) << "Existing conflicting writes: " + << ExistingConflictingWritten << "\n"; + if (!ProposedConflictingKnown.is_empty()) + OS->indent(Indent) + << "Proposed conflicting known: " << ProposedConflictingKnown + << "\n"; } return true; } - // Do the new writes in Proposed only overwrite unused values in Existing? - auto ExistingAvailableDefs = - convertZoneToTimepoints(Existing.Unused, true, false); - auto ProposedWrittenDomain = - isl::manage(isl_union_map_domain(Proposed.Written.copy())); - if (isl_union_set_is_subset(ProposedWrittenDomain.keep(), - ExistingAvailableDefs.keep()) != - isl_bool_true) { + // Do the writes in Proposed conflict with occupied values in Existing? + // We use the same trick with unknown values to save a subtract operation. + auto ExistingValuesFixedDefs = + convertZoneToTimepoints(ExistingValues, isl::dim::in, true, false); + + auto ProposedWrittenDomain = Proposed.Written.domain(); + auto ProposedWrittenAnyVal = + Proposed.Written.unite(makeUnknownForDomain(ProposedWrittenDomain)); + auto ProposedWrittenSomeVal = + ProposedWrittenAnyVal.intersect(ExistingValuesFixedDefs); + auto ProposedWrittenSomeValDomain = ProposedWrittenSomeVal.domain(); + + if (!ProposedWrittenDomain.is_subset(ProposedWrittenSomeValDomain)) { if (OS) { - auto ConflictingWrites = give(isl_union_set_subtract( - ProposedWrittenDomain.copy(), ExistingAvailableDefs.copy())); - OS->indent(Indent) - << "Proposed a lifetime where there is an Existing write into it\n"; - OS->indent(Indent) << "Conflicting writes: " << ConflictingWrites - << "\n"; + auto Conflicting = + ProposedWrittenDomain.subtract(ProposedWrittenSomeValDomain); + auto ExistingConflictingKnown = + ExistingValuesFixedDefs.intersect_domain(Conflicting); + auto ProposedConflictingWritten = + Proposed.Written.intersect_domain(Conflicting); + + OS->indent(Indent) << "Proposed writes into range used by Existing\n"; + OS->indent(Indent) << "Proposed conflicting writes: " + << ProposedConflictingWritten << "\n"; + if (!ExistingConflictingKnown.is_empty()) + OS->indent(Indent) + << "Existing conflicting known: " << ExistingConflictingKnown + << "\n"; } return true; } // Does Proposed write at the same time as Existing already does (order of // writes is undefined)? + auto ExistingWrittenDomain = + isl::manage(isl_union_map_domain(Existing.Written.copy())); if (isl_union_set_is_disjoint(ExistingWrittenDomain.keep(), ProposedWrittenDomain.keep()) != isl_bool_true) { Index: unittests/DeLICM/DeLICMTest.cpp =================================================================== --- unittests/DeLICM/DeLICMTest.cpp +++ unittests/DeLICM/DeLICMTest.cpp @@ -261,6 +261,16 @@ EXPECT_FALSE(checkIsConflicting({"{ Dom[i] : i != 1 }", nullptr, "{}"}, {"{}", nullptr, "{ Dom[0] }"})); + // Check occupied vs. written with known values. + EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"}, + {"{}", nullptr, "{ Dom[0] -> Val[] }"})); + EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> ValA[] }", nullptr, "{}"}, + {"{}", nullptr, "{ Dom[0] -> ValB[] }"})); + EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"}, + {"{}", nullptr, "{ Dom[0] -> [] }"})); + EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> [] }", nullptr, "{}"}, + {"{}", nullptr, "{ Dom[0] -> Val[] }"})); + // Check written vs. written. EXPECT_TRUE(checkIsConflicting({"{}", nullptr, "{ Dom[0] }"}, {"{}", nullptr, "{ Dom[0] }"}));