diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 36f9e2b7..0cfac597 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -68,7 +68,7 @@ public: path_delay }; - virtual PathEnd *copy() = 0; + virtual PathEnd *copy() const = 0; virtual ~PathEnd(); void deletePath(); Path *path() { return path_; } @@ -84,6 +84,8 @@ public: PathAPIndex pathIndex(const StaState *sta) const; virtual void reportShort(const ReportPath *report) const = 0; virtual void reportFull(const ReportPath *report) const = 0; + PathGroup *pathGroup() const { return path_group_; } + void setPathGroup(PathGroup *path_group); // Predicates for PathEnd type. // Default methods overridden by respective types. @@ -216,6 +218,7 @@ protected: PathDelay *path_delay, const StaState *sta); Path *path_; + PathGroup *path_group_; }; class PathEndUnconstrained : public PathEnd @@ -224,7 +227,7 @@ public: explicit PathEndUnconstrained(Path *path); virtual Type type() const; virtual const char *typeName() const; - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual void reportShort(const ReportPath *report) const; virtual void reportFull(const ReportPath *report) const; virtual bool isUnconstrained() const; @@ -321,7 +324,7 @@ public: Path *clk_path, MultiCyclePath *mcp, const StaState *sta); - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual Type type() const; virtual const char *typeName() const; virtual void reportShort(const ReportPath *report) const; @@ -367,7 +370,7 @@ public: virtual bool isCheck() const { return false; } virtual bool isLatchCheck() const { return true; } virtual PathDelay *pathDelay() const { return path_delay_; } - virtual PathEnd *copy(); + virtual PathEnd *copy() const; Path *latchDisable(); const Path *latchDisable() const; virtual void reportShort(const ReportPath *report) const; @@ -428,7 +431,7 @@ public: Path *clk_path, MultiCyclePath *mcp, const StaState *sta); - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual Type type() const; virtual const char *typeName() const; virtual void reportShort(const ReportPath *report) const; @@ -474,7 +477,7 @@ public: MultiCyclePath *mcp, ArcDelay margin, const StaState *sta); - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual Type type() const; virtual const char *typeName() const; virtual void reportShort(const ReportPath *report) const; @@ -506,7 +509,7 @@ public: Path *data_clk_path, MultiCyclePath *mcp, const StaState *sta); - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual Type type() const; virtual const char *typeName() const; virtual void reportShort(const ReportPath *report) const; @@ -560,7 +563,7 @@ public: Path *path, OutputDelay *output_delay, const StaState *sta); - virtual PathEnd *copy(); + virtual PathEnd *copy() const; virtual Type type() const; virtual const char *typeName() const; virtual void reportShort(const ReportPath *report) const; diff --git a/include/sta/PathGroup.hh b/include/sta/PathGroup.hh index ca4ea606..93424a22 100644 --- a/include/sta/PathGroup.hh +++ b/include/sta/PathGroup.hh @@ -40,6 +40,8 @@ class PathEndVisitor; typedef PathEndSeq::Iterator PathGroupIterator; typedef Map PathGroupClkMap; typedef Map PathGroupNamedMap; +typedef std::vector PathGroupSeq; +typedef std::vector StdStringSeq; // A collection of PathEnds grouped and sorted for reporting. class PathGroup @@ -133,9 +135,9 @@ public: const MinMax *min_max) const; PathGroup *findPathGroup(const Clock *clock, const MinMax *min_max) const; - PathGroup *pathGroup(const PathEnd *path_end) const; - static std::string pathGroupName(const PathEnd *path_end, - const StaState *sta); + PathGroupSeq pathGroups(const PathEnd *path_end) const; + static StdStringSeq pathGroupNames(const PathEnd *path_end, + const StaState *sta); static const char *asyncPathGroupName() { return async_group_name_; } static const char *pathDelayGroupName() { return path_delay_group_name_; } static const char *gatedClkGroupName() { return gated_clk_group_name_; } @@ -179,8 +181,6 @@ protected: const MinMax *min_max); bool reportGroup(const char *group_name, PathGroupNameSet *group_names) const; - static GroupPath *groupPathTo(const PathEnd *path_end, - const StaState *sta); int group_path_count_; int endpoint_path_count_; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 4cfd24ac..c1e1546f 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -996,6 +996,12 @@ public: const MinMax *min_max, bool match_min_max_exactly, bool require_to_pin) const; + void groupPathsTo(const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max, + // Return value. + ExceptionPathSeq &group_paths) const; bool isCompleteTo(ExceptionState *state, const Pin *pin, const RiseFall *rf, @@ -1164,6 +1170,13 @@ protected: // Return values. ExceptionPath *&hi_priority_exception, int &hi_priority) const; + void groupPathsTo(const ExceptionPathSet *to_exceptions, + const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max, + // Return value. + ExceptionPathSeq &group_paths) const; void makeLoopPath(ExceptionThruSeq *thrus); void makeLoopException(const Pin *loop_input_pin, const Pin *loop_pin, diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 934c1006..627a4e0e 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -71,6 +71,8 @@ typedef Map VertexSlackMap; typedef Vector VertexSlackMapSeq; typedef Vector WorstSlacksSeq; typedef std::vector DelayDblSeq; +typedef Vector ExceptionPathSeq; +typedef std::vector PathGroupSeq; class Search : public StaState { @@ -165,7 +167,7 @@ public: // Clock arrival at the path source/launch point. Arrival pathClkPathArrival(const Path *path) const; - PathGroup *pathGroup(const PathEnd *path_end) const; + PathGroupSeq pathGroups(const PathEnd *path_end) const; void deletePathGroups(); void makePathGroups(int group_path_count, int endpoint_path_count, @@ -187,6 +189,7 @@ public: const MinMax *min_max, bool match_min_max_exactly, bool require_to_pin) const; + ExceptionPathSeq groupPathsTo(const PathEnd *path_end) const; FilterPath *filter() const { return filter_; } void deleteFilter(); void deleteFilteredArrivals(); diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 5b8b697c..462fff68 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -5362,6 +5362,8 @@ Sdc::exceptionThruStates(const ExceptionPathSet *exceptions, } } +//////////////////////////////////////////////////////////////// + void Sdc::exceptionTo(ExceptionPathType type, const Pin *pin, @@ -5484,6 +5486,47 @@ Sdc::isCompleteTo(ExceptionState *state, //////////////////////////////////////////////////////////////// +void +Sdc::groupPathsTo(const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max, + // Return value. + ExceptionPathSeq &group_paths) const +{ + if (!first_to_inst_exceptions_.empty()) { + Instance *inst = network_->instance(pin); + groupPathsTo(first_to_inst_exceptions_.findKey(inst), pin, rf, + clk_edge, min_max, group_paths); + } + if (!first_to_pin_exceptions_.empty()) + groupPathsTo(first_to_pin_exceptions_.findKey(pin), pin, rf, + clk_edge, min_max, group_paths); + if (clk_edge && !first_to_clk_exceptions_.empty()) + groupPathsTo(first_to_clk_exceptions_.findKey(clk_edge->clock()), + pin, rf, clk_edge, min_max, group_paths); +} + +void +Sdc::groupPathsTo(const ExceptionPathSet *to_exceptions, + const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max, + // Return value. + ExceptionPathSeq &group_paths) const +{ + if (to_exceptions) { + for (ExceptionPath *exception : *to_exceptions) { + if (exception->isGroupPath() + && exceptionMatchesTo(exception, pin, rf, clk_edge, min_max, true, false)) + group_paths.push_back(exception); + } + } +} + +//////////////////////////////////////////////////////////////// + Wireload * Sdc::wireload(const MinMax *min_max) { diff --git a/search/Path.cc b/search/Path.cc index d9a6333b..bf8fc2de 100644 --- a/search/Path.cc +++ b/search/Path.cc @@ -306,7 +306,7 @@ Path::isClock(const StaState *sta) const const MinMax * Path::minMax(const StaState *sta) const { - return pathAnalysisPt(sta)->pathMinMax(); + return tag(sta)->minMax(sta); } PathAPIndex diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 55430f32..d042ca7e 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -49,7 +49,8 @@ namespace sta { PathEnd::PathEnd(Path *path) : - path_(path) + path_(path), + path_group_(nullptr) { } @@ -65,6 +66,12 @@ PathEnd::setPath(Path *path) path_ = path; } +void +PathEnd::setPathGroup(PathGroup *path_group) +{ + path_group_ = path_group; +} + Vertex * PathEnd::vertex(const StaState *sta) const { @@ -454,7 +461,7 @@ PathEndUnconstrained::PathEndUnconstrained(Path *path) : } PathEnd * -PathEndUnconstrained::copy() +PathEndUnconstrained::copy() const { return new PathEndUnconstrained(path_); } @@ -955,7 +962,7 @@ PathEndCheck::PathEndCheck(Path *path, } PathEnd * -PathEndCheck::copy() +PathEndCheck::copy() const { return new PathEndCheck(path_, check_arc_, check_edge_, clk_path_, mcp_, crpr_, crpr_valid_); @@ -1126,7 +1133,7 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path, } PathEnd * -PathEndLatchCheck::copy() +PathEndLatchCheck::copy() const { return new PathEndLatchCheck(path_, check_arc_, check_edge_, clk_path_, disable_path_, mcp_, path_delay_, @@ -1346,7 +1353,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay, } PathEnd * -PathEndOutputDelay::copy() +PathEndOutputDelay::copy() const { return new PathEndOutputDelay(output_delay_, path_, clk_path_, mcp_, crpr_, crpr_valid_); @@ -1552,7 +1559,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref, } PathEnd * -PathEndGatedClock::copy() +PathEndGatedClock::copy() const { return new PathEndGatedClock(path_, clk_path_, check_role_, mcp_, margin_, crpr_, crpr_valid_); @@ -1668,7 +1675,7 @@ PathEndDataCheck::PathEndDataCheck(DataCheck *check, } PathEnd * -PathEndDataCheck::copy() +PathEndDataCheck::copy() const { return new PathEndDataCheck(check_, path_, data_clk_path_, clk_path_, mcp_, crpr_, crpr_valid_); @@ -1825,7 +1832,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, } PathEnd * -PathEndPathDelay::copy() +PathEndPathDelay::copy() const { return new PathEndPathDelay(path_delay_, path_, clk_path_, check_arc_, check_edge_, output_delay_, diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 79054f2c..36414909 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -168,6 +168,7 @@ PathGroup::insert(PathEnd *path_end) { LockGuard lock(lock_); path_ends_.push_back(path_end); + path_end->setPathGroup(this); if (group_path_count_ != group_path_count_max && path_ends_.size() > group_path_count_ * 2) prune(); @@ -398,37 +399,43 @@ PathGroups::reportGroup(const char *group_name, || group_names->hasKey(group_name); } -PathGroup * -PathGroups::pathGroup(const PathEnd *path_end) const +PathGroupSeq +PathGroups::pathGroups(const PathEnd *path_end) const { + PathGroupSeq path_groups; + PathGroup *path_group = nullptr; + ExceptionPathSeq group_paths = search_->groupPathsTo(path_end); const MinMax *min_max = path_end->minMax(this); int mm_index = min_max->index(); - GroupPath *group_path = groupPathTo(path_end, this); if (path_end->isUnconstrained()) - return unconstrained_[mm_index]; + path_group = unconstrained_[mm_index]; // GroupPaths have precedence. - else if (group_path) { - if (group_path->isDefault()) - return path_delay_[mm_index]; - else { - const char *group_name = group_path->name(); - return findPathGroup(group_name, min_max); - } + else if (!group_paths.empty()) { + for (ExceptionPath *group_path : group_paths) { + if (group_path->isDefault()) + path_groups.push_back(path_delay_[mm_index]); + else { + const char *group_name = group_path->name(); + PathGroup *group = findPathGroup(group_name, min_max); + if (group) + path_groups.push_back(group); + } + } } else if (path_end->isCheck() || path_end->isLatchCheck()) { const TimingRole *check_role = path_end->checkRole(this); const Clock *tgt_clk = path_end->targetClk(this); if (check_role == TimingRole::removal() || check_role == TimingRole::recovery()) - return async_[mm_index]; + path_group = async_[mm_index]; else - return findPathGroup(tgt_clk, min_max); + path_group = findPathGroup(tgt_clk, min_max); } else if (path_end->isOutputDelay() - || path_end->isDataCheck()) - return findPathGroup(path_end->targetClk(this), min_max); + || path_end->isDataCheck()) + path_group = findPathGroup(path_end->targetClk(this), min_max); else if (path_end->isGatedClock()) - return gated_clk_[mm_index]; + path_group = gated_clk_[mm_index]; else if (path_end->isPathDelay()) { // Path delays that end at timing checks are part of the target clk group // unless -ignore_clock_latency is true. @@ -436,45 +443,52 @@ PathGroups::pathGroup(const PathEnd *path_end) const const Clock *tgt_clk = path_end->targetClk(this); if (tgt_clk && !path_delay->ignoreClkLatency()) - return findPathGroup(tgt_clk, min_max); + path_group = findPathGroup(tgt_clk, min_max); else - return path_delay_[mm_index]; - } - else { - report_->critical(1390, "unknown path end type"); - return nullptr; + path_group = path_delay_[mm_index]; } + if (path_group) + path_groups.push_back(path_group); + return path_groups; } // Mirrors PathGroups::pathGroup. -std::string -PathGroups::pathGroupName(const PathEnd *path_end, - const StaState *sta) +StdStringSeq +PathGroups::pathGroupNames(const PathEnd *path_end, + const StaState *sta) { - GroupPath *group_path = groupPathTo(path_end, sta); + StdStringSeq group_names; + const char *group_name = nullptr; + const Search *search = sta->search(); + ExceptionPathSeq group_paths = search->groupPathsTo(path_end); if (path_end->isUnconstrained()) - return unconstrained_group_name_; - // GroupPaths have precedence. - else if (group_path) { - if (group_path->isDefault()) - return path_delay_group_name_; - else - return group_path->name(); + group_name = unconstrained_group_name_; + else if (!group_paths.empty()) { + // GroupPaths have precedence. + for (ExceptionPath *group_path : group_paths) { + if (group_path->isDefault()) + group_names.push_back(path_delay_group_name_); + else + group_names.push_back(group_path->name()); + } } else if (path_end->isCheck() || path_end->isLatchCheck()) { const TimingRole *check_role = path_end->checkRole(sta); const Clock *tgt_clk = path_end->targetClk(sta); if (check_role == TimingRole::removal() || check_role == TimingRole::recovery()) - return async_group_name_; + group_name = async_group_name_; else - return tgt_clk->name(); + group_name = tgt_clk->name(); } else if (path_end->isOutputDelay() - || path_end->isDataCheck()) - return path_end->targetClk(sta)->name(); + || path_end->isDataCheck()) { + const Clock *tgt_clk = path_end->targetClk(sta); + if (tgt_clk) + group_name = tgt_clk->name(); + } else if (path_end->isGatedClock()) - return gated_clk_group_name_; + group_name = gated_clk_group_name_; else if (path_end->isPathDelay()) { // Path delays that end at timing checks are part of the target clk group // unless -ignore_clock_latency is true. @@ -482,28 +496,13 @@ PathGroups::pathGroupName(const PathEnd *path_end, const Clock *tgt_clk = path_end->targetClk(sta); if (tgt_clk && !path_delay->ignoreClkLatency()) - return tgt_clk->name(); + group_name = tgt_clk->name(); else - return path_delay_group_name_; + group_name = path_delay_group_name_; } - else { - sta->report()->critical(1391, "unknown path end type"); - return nullptr; - } -} - -GroupPath * -PathGroups::groupPathTo(const PathEnd *path_end, - const StaState *sta) -{ - const Path *path = path_end->path(); - const Pin *pin = path->pin(sta); - ExceptionPath *exception = - sta->search()->exceptionTo(ExceptionPathType::group_path, path, - pin, path->transition(sta), - path_end->targetClkEdge(sta), - path->minMax(sta), false, false); - return dynamic_cast(exception); + if (group_name) + group_names.push_back(group_name); + return group_names; } void @@ -632,8 +631,7 @@ MakePathEnds1::copy() const void MakePathEnds1::visit(PathEnd *path_end) { - PathGroup *group = path_groups_->pathGroup(path_end); - if (group) + for (PathGroup *group : path_groups_->pathGroups(path_end)) visitPathEnd(path_end, group); } @@ -644,14 +642,15 @@ MakePathEnds1::visitPathEnd(PathEnd *path_end, if (group->saveable(path_end)) { // Only keep the path end with the smallest slack/latest arrival. PathEnd *worst_end = ends_.findKey(group); + PathEnd *copy = path_end->copy(); if (worst_end) { if (cmp_(path_end, worst_end)) { - ends_[group] = path_end->copy(); + ends_[group] = copy; delete worst_end; } } else - ends_[group] = path_end->copy(); + ends_[group] = copy; } } @@ -732,8 +731,7 @@ MakePathEndsAll::~MakePathEndsAll() void MakePathEndsAll::visit(PathEnd *path_end) { - PathGroup *group = path_groups_->pathGroup(path_end); - if (group) + for (PathGroup *group : path_groups_->pathGroups(path_end)) visitPathEnd(path_end, group); } diff --git a/search/ReportPath.cc b/search/ReportPath.cc index d9a633dc..6b991557 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -401,8 +401,8 @@ ReportPath::reportEndpointHeader(const PathEnd *end, { PathGroup *prev_group = nullptr; if (prev_end) - prev_group = search_->pathGroup(prev_end); - PathGroup *group = search_->pathGroup(end); + prev_group = prev_end->pathGroup(); + PathGroup *group = end->pathGroup(); if (group && group != prev_group) { if (prev_group) reportBlankLine(); @@ -1086,7 +1086,7 @@ ReportPath::reportJson(const PathEnd *end, result += "{\n"; stringAppend(result, " \"type\": \"%s\",\n", end->typeName()); stringAppend(result, " \"path_group\": \"%s\",\n", - search_->pathGroup(end)->name()); + end->pathGroup()->name()); stringAppend(result, " \"path_type\": \"%s\",\n", end->minMax(this)->to_string().c_str()); @@ -1273,7 +1273,7 @@ ReportPath::reportSlackOnly(const PathEnd *end) const { string line; const EarlyLate *early_late = end->pathEarlyLate(this); - reportDescription(search_->pathGroup(end)->name(), line); + reportDescription(end->pathGroup()->name(), line); if (end->isUnconstrained()) reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line); else @@ -1939,7 +1939,7 @@ ReportPath::reportGroup(const PathEnd *end) const { string line; line = "Path Group: "; - PathGroup *group = search_->pathGroup(end); + PathGroup *group = end->pathGroup(); line += group ? group->name() : "(none)"; report_->reportLineString(line); diff --git a/search/Search.cc b/search/Search.cc index 9b38b66a..6fd4c14c 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -3767,6 +3767,34 @@ Search::exceptionTo(ExceptionPathType type, //////////////////////////////////////////////////////////////// +// Find group paths that end at the path. +ExceptionPathSeq +Search::groupPathsTo(const PathEnd *path_end) const +{ + ExceptionPathSeq group_paths; + const Path *path = path_end->path(); + const Pin *pin = path->pin(this); + const Tag *tag = path->tag(this); + const RiseFall *rf = tag->transition(); + const ClockEdge *clk_edge = path_end->targetClkEdge(this); + const MinMax *min_max = tag->minMax(this); + const ExceptionStateSet *states = path->tag(this)->states(); + if (states) { + for (auto state : *states) { + ExceptionPath *exception = state->exception(); + if (exception->isGroupPath() + && sdc_->exceptionMatchesTo(exception, pin, rf, clk_edge, min_max, + false, false)) + group_paths.push_back(exception); + } + } + // Check for group_path -to exceptions originating at the end pin or target clock. + sdc_->groupPathsTo(pin, rf, clk_edge, min_max, group_paths); + return group_paths; +} + +//////////////////////////////////////////////////////////////// + Slack Search::totalNegativeSlack(const MinMax *min_max) { @@ -4095,13 +4123,13 @@ Search::deletePathGroups() path_groups_ = nullptr; } -PathGroup * -Search::pathGroup(const PathEnd *path_end) const +PathGroupSeq +Search::pathGroups(const PathEnd *path_end) const { if (path_groups_) - return path_groups_->pathGroup(path_end); + return path_groups_->pathGroups(path_end); else - return nullptr; + return PathGroupSeq(); } bool diff --git a/search/Sta.cc b/search/Sta.cc index b963b6a1..7c0b67f7 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -3068,11 +3068,15 @@ EndpointPathEndVisitor::copy() const void EndpointPathEndVisitor::visit(PathEnd *path_end) { - if (path_end->minMax(sta_) == min_max_ - && PathGroups::pathGroupName(path_end, sta_) == path_group_name_) { - Slack end_slack = path_end->slack(sta_); - if (delayLess(end_slack, slack_, sta_)) - slack_ = end_slack; + if (path_end->minMax(sta_) == min_max_) { + StdStringSeq group_names = PathGroups::pathGroupNames(path_end, sta_); + for (std::string &group_name : group_names) { + if (group_name == path_group_name_) { + Slack end_slack = path_end->slack(sta_); + if (delayLess(end_slack, slack_, sta_)) + slack_ = end_slack; + } + } } } diff --git a/search/Tag.cc b/search/Tag.cc index 32a29420..27badadc 100644 --- a/search/Tag.cc +++ b/search/Tag.cc @@ -181,6 +181,12 @@ Tag::transition() const return RiseFall::find(rf_index_); } +const MinMax * +Tag::minMax(const StaState *sta) const +{ + return pathAnalysisPt(sta)->pathMinMax(); +} + PathAnalysisPt * Tag::pathAnalysisPt(const StaState *sta) const { diff --git a/search/Tag.hh b/search/Tag.hh index c158a2b4..e084bd29 100644 --- a/search/Tag.hh +++ b/search/Tag.hh @@ -73,6 +73,7 @@ public: const Pin *clkSrc() const; int rfIndex() const { return rf_index_; } const RiseFall *transition() const; + const MinMax *minMax(const StaState *sta) const; PathAnalysisPt *pathAnalysisPt(const StaState *sta) const; PathAPIndex pathAPIndex() const { return path_ap_index_; } TagIndex index() const { return index_; } diff --git a/search/VisitPathGroupVertices.cc b/search/VisitPathGroupVertices.cc index 4e77577a..c733f9b8 100644 --- a/search/VisitPathGroupVertices.cc +++ b/search/VisitPathGroupVertices.cc @@ -177,12 +177,14 @@ VisitPathGroupEnds::vertexBegin(Vertex *) void VisitPathGroupEnds::visit(PathEnd *path_end) { - PathGroup *group = sta_->search()->pathGroup(path_end); - if (group == path_group_) { - Path *path = path_end->path(); - Vertex *vertex = path->vertex(sta_); - vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_); - vertex_matches_ = true; + PathGroupSeq groups = sta_->search()->pathGroups(path_end); + for (PathGroup *group : groups) { + if (group == path_group_) { + Path *path = path_end->path(); + Vertex *vertex = path->vertex(sta_); + vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_); + vertex_matches_ = true; + } } }