Index: lib/Transform/DeLICM.cpp =================================================================== --- lib/Transform/DeLICM.cpp +++ lib/Transform/DeLICM.cpp @@ -374,6 +374,15 @@ return singleton(UMap, ResultSpace); } +/// Create a domain-to-unknown value mapping. +/// +/// @param Domain { Domain[] } +/// +/// @return { Domain[] -> ValInst[] } +isl::union_map makeUnknownForDomain(isl::union_set Domain) { + return give(isl_union_map_from_domain(Domain.take())); +} + /// If InputVal is not defined in the stmt itself, return the MemoryAccess that /// reads the scalar. Return nullptr otherwise (if the value is defined in the /// scop, or is synthesizable). @@ -621,15 +630,49 @@ } #endif - // Are the new lifetimes required for Proposed unused in Existing? - if (isl_union_set_is_subset(Proposed.Occupied.keep(), - Existing.Unused.keep()) != isl_bool_true) { + // Do the Existing and Proposed lifetimes conflicting? + // In order to not conflict, one of the following conditions must apply for + // each element/lifetime interval: + // + // 1. If occupied in one of the knowledges, it is unused in the other. + // + // - or - + // + // 2. Both contain the same value. + // + // Instead of partitioning the lifetimes into a part occupied by both and + // checking the conditions separately, we check only the second conditions + // and ensure that it will also apply when then first condition is true. + // This is done by adding another "the value occupying Proposed" to + // Proposed.Known and to Existing.Unused such that these match while looking + // for a common known value. Note that we use "unknown value" for this + // purpose such that we can re-use Existing.Unused to also match unknown + // values in Proposed.Written in a later check. + auto ProposedOccupiedAnyVal = makeUnknownForDomain(Proposed.Occupied); + auto ProposedValues = Proposed.Known.unite(ProposedOccupiedAnyVal); + + auto ExistingUnusedAnyVal = makeUnknownForDomain(Existing.Unused); + auto ExistingValues = Existing.Known.unite(ExistingUnusedAnyVal); + + auto SomeVal = ExistingValues.intersect(ProposedValues); + auto SomeValDomain = SomeVal.domain(); + + if (!Proposed.Occupied.is_subset(SomeValDomain)) { if (OS) { - auto ConflictingLifetimes = give(isl_union_set_subtract( - Proposed.Occupied.copy(), Existing.Unused.copy())); - OS->indent(Indent) << "Proposed lifetimes are not unused in existing\n"; - OS->indent(Indent) << "Conflicting lifetimes: " << ConflictingLifetimes - << "\n"; + auto Conflicting = Proposed.Occupied.subtract(SomeValDomain); + auto ExistingConflictingKnown = + Existing.Known.intersect_domain(Conflicting); + auto ProposedConflictingKnown = + Proposed.Known.intersect_domain(Conflicting); + + OS->indent(Indent) << "Proposed lifetime conflicting with Existing's\n"; + OS->indent(Indent) << "Conflicting occupied: " << Conflicting << "\n"; + if (!ExistingConflictingKnown.is_empty()) + OS->indent(Indent) + << "Existing Known: " << ExistingConflictingKnown << "\n"; + if (!ProposedConflictingKnown.is_empty()) + OS->indent(Indent) + << "Proposed Known: " << ProposedConflictingKnown << "\n"; } return true; } Index: unittests/DeLICM/DeLICMTest.cpp =================================================================== --- unittests/DeLICM/DeLICMTest.cpp +++ unittests/DeLICM/DeLICMTest.cpp @@ -232,6 +232,16 @@ EXPECT_FALSE(checkIsConflicting({"{ Dom[i] : i != 0 }", nullptr, "{}"}, {"{ Dom[0] }", nullptr, "{}"})); + // Check occupied vs. occupied with known values. + EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"}, + {"{ Dom[i] -> Val[] }", nullptr, "{}"})); + EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> ValA[] }", nullptr, "{}"}, + {"{ Dom[i] -> ValB[] }", nullptr, "{}"})); + EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"}, + {"{ Dom[i] -> [] }", nullptr, "{}"})); + EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[0] -> Val[] }", nullptr, "{}"}, + {nullptr, "{ Dom[0] }", "{}"})); + // Check occupied vs. written. EXPECT_TRUE( checkIsConflicting({nullptr, "{}", "{}"}, {"{}", nullptr, "{ Dom[0] }"}));