@@ -42,6 +42,7 @@ struct TraverseState {
42
42
43
43
enum ActionType {
44
44
TRAVERSE,
45
+ TRAVERSE_ALL_SOURCE_SETS,
45
46
INSERT_GOALS_TO_REMOVE,
46
47
ERASE_GOALS_TO_REMOVE,
47
48
ERASE_SEEN_GOALS,
@@ -57,20 +58,32 @@ enum ActionType {
57
58
// through "actions".
58
59
struct Action {
59
60
ActionType action_type;
60
- // Goal either to delete are added to the corresponding set.
61
- const Binding* goal;
62
- // The iterator is for std::set and this is stable upon deletion and insertion
63
- // if it's not directly the element being deleted or inserted. We will only
64
- // try to erase the element on the exact node traversal, so we can safely
65
- // reuse the iterator that was returned from the insertion.
66
- // Not using this for action ERASE_GOALS_TO_REMOVE, as we are requesting
67
- // for removal before the insertion has happened.
68
- GoalSet::iterator erase_it;
61
+ union {
62
+ // Goal either to delete are added to the corresponding set.
63
+ const Binding* goal;
64
+ // The iterator is for std::set and this is stable upon deletion and
65
+ // insertion if it's not directly the element being deleted or inserted.
66
+ // We will only try to erase the element on the exact node traversal, so
67
+ // we can safely reuse the iterator that was returned from the insertion.
68
+ // Not using this for action ERASE_GOALS_TO_REMOVE, as we are requesting
69
+ // for removal before the insertion has happened.
70
+ GoalSet::iterator erase_it;
71
+ // Source set to handle by a TRAVERSE_ALL_SOURCE_SETS action and end of the
72
+ // source sets. The two entries are never the same for actions on the
73
+ // actions stack. (Ideally, this would be an anonymous struct with proper
74
+ // field names but gcc does not allow this, as opposed to clang.)
75
+ std::set<SourceSet>::const_iterator source_sets_it[2 ];
76
+ };
77
+
69
78
Action (ActionType action_type, const Binding* goal)
70
79
: action_type(action_type), goal(goal) {}
71
- Action (ActionType action_type, const Binding* goal,
72
- GoalSet::iterator erase_it)
73
- : action_type(action_type), goal(goal), erase_it(erase_it) {}
80
+ Action (ActionType action_type, GoalSet::iterator erase_it)
81
+ : action_type(action_type), erase_it(erase_it) {}
82
+ Action (ActionType action_type,
83
+ std::set<SourceSet>::const_iterator source_sets_it,
84
+ std::set<SourceSet>::const_iterator source_sets_end)
85
+ : action_type(action_type),
86
+ source_sets_it{source_sets_it, source_sets_end} {}
74
87
};
75
88
76
89
static void traverse (const CFGNode* position,
@@ -93,7 +106,7 @@ static void traverse(const CFGNode* position,
93
106
return ;
94
107
}
95
108
auto [it, _] = state.seen_goals .insert (goal);
96
- actions.emplace (ERASE_SEEN_GOALS, nullptr , it);
109
+ actions.emplace (ERASE_SEEN_GOALS, it);
97
110
98
111
const auto * origin = goal->FindOrigin (position);
99
112
if (!origin) {
@@ -105,18 +118,9 @@ static void traverse(const CFGNode* position,
105
118
106
119
state.removed_goals .push_back (goal);
107
120
actions.emplace (ERASE_REMOVED_GOALS, nullptr );
108
- for (const auto & source_set : origin->source_sets ) {
109
- for (const Binding* next_goal : source_set) {
110
- if (!state.goals_to_remove .count (next_goal)) {
111
- actions.emplace (ERASE_GOALS_TO_REMOVE, next_goal);
112
- }
113
- }
114
- actions.emplace (TRAVERSE, nullptr );
115
- for (const Binding* next_goal : source_set) {
116
- if (!state.goals_to_remove .count (next_goal)) {
117
- actions.emplace (INSERT_GOALS_TO_REMOVE, next_goal);
118
- }
119
- }
121
+ if (!origin->source_sets .empty ()) {
122
+ actions.emplace (TRAVERSE_ALL_SOURCE_SETS, origin->source_sets .cbegin (),
123
+ origin->source_sets .cend ());
120
124
}
121
125
}
122
126
@@ -149,6 +153,21 @@ static std::vector<RemoveResult> remove_finished_goals(const CFGNode* pos,
149
153
case TRAVERSE:
150
154
traverse (pos, results, actions, state);
151
155
break ;
156
+ case TRAVERSE_ALL_SOURCE_SETS: {
157
+ const auto & source_set = *action.source_sets_it [0 ];
158
+ action.source_sets_it [0 ]++;
159
+ if (action.source_sets_it [0 ] != action.source_sets_it [1 ]) {
160
+ actions.push (action);
161
+ }
162
+ for (const Binding* next_goal : source_set) {
163
+ auto [it, added] = state.goals_to_remove .insert (next_goal);
164
+ if (added) {
165
+ actions.emplace (ERASE_GOALS_TO_REMOVE, next_goal);
166
+ }
167
+ }
168
+ actions.emplace (TRAVERSE, nullptr );
169
+ break ;
170
+ }
152
171
case INSERT_GOALS_TO_REMOVE:
153
172
state.goals_to_remove .insert (action.goal );
154
173
break ;
0 commit comments