@@ -54,11 +54,47 @@ void reachability_slicert::fixedpoint_to_assertions(
54
54
const is_threadedt &is_threaded,
55
55
slicing_criteriont &criterion)
56
56
{
57
- std::vector<cfgt::node_indext> src = get_sources (is_threaded, criterion);
57
+ std::vector<search_stack_entryt> stack;
58
+ std::vector<cfgt::node_indext> sources = get_sources (is_threaded, criterion);
59
+ for (const auto source : sources)
60
+ stack.emplace_back (source, false );
58
61
59
- std::vector<cfgt::node_indext> reachable = cfg.get_reachable (src, false );
60
- for (const auto index : reachable)
61
- cfg[index ].reaches_assertion = true ;
62
+ while (!stack.empty ())
63
+ {
64
+ auto &node = cfg[stack.back ().node_index ];
65
+ auto caller_is_known = stack.back ().caller_is_known ;
66
+ stack.pop_back ();
67
+
68
+ if (node.reaches_assertion )
69
+ continue ;
70
+ node.reaches_assertion = true ;
71
+
72
+ for (const auto &edge : node.in )
73
+ {
74
+ const auto &pred_node = cfg[edge.first ];
75
+
76
+ if (pred_node.PC ->is_end_function ())
77
+ {
78
+ // This is an end-of-function -> successor-of-callsite edge.
79
+ // Thus node.PC must have a predecessor instruction which is the calling
80
+ // instruction. Queue both the caller and the end of the callee.
81
+ stack.emplace_back (edge.first , true );
82
+ stack.emplace_back (
83
+ cfg.entry_map [std::prev (node.PC )], caller_is_known);
84
+ }
85
+ else if (pred_node.PC ->is_function_call ())
86
+ {
87
+ // Skip this predecessor, unless this is a bodyless function, or we
88
+ // don't know who our callee was:
89
+ if (!caller_is_known || std::next (pred_node.PC ) == node.PC )
90
+ stack.emplace_back (edge.first , caller_is_known);
91
+ }
92
+ else
93
+ {
94
+ stack.emplace_back (edge.first , caller_is_known);
95
+ }
96
+ }
97
+ }
62
98
}
63
99
64
100
// / Perform forwards depth-first search of the control-flow graph of the
@@ -71,11 +107,67 @@ void reachability_slicert::fixedpoint_from_assertions(
71
107
const is_threadedt &is_threaded,
72
108
slicing_criteriont &criterion)
73
109
{
74
- std::vector<cfgt::node_indext> src = get_sources (is_threaded, criterion);
110
+ std::vector<search_stack_entryt> stack;
111
+ std::vector<cfgt::node_indext> sources = get_sources (is_threaded, criterion);
112
+ for (const auto source : sources)
113
+ stack.emplace_back (source, false );
114
+
115
+ while (!stack.empty ())
116
+ {
117
+ auto &node = cfg[stack.back ().node_index ];
118
+ auto caller_is_known = stack.back ().caller_is_known ;
119
+ stack.pop_back ();
120
+
75
121
76
- const std::vector<cfgt::node_indext> reachable = cfg.get_reachable (src, true );
77
- for (const auto index : reachable)
78
- cfg[index ].reachable_from_assertion = true ;
122
+ if (node.reachable_from_assertion )
123
+ continue ;
124
+ node.reachable_from_assertion = true ;
125
+
126
+ if (node.PC ->is_function_call ())
127
+ {
128
+ // Queue the instruction's natural successor (function head, or next
129
+ // instruction if the function is bodyless)
130
+ INVARIANT (node.out .size () == 1 , " Call sites should have one successor" );
131
+ auto successor_index = node.out .begin ()->first ;
132
+
133
+ // If the function has a body, mark the function head, but note that we
134
+ // have already taken care of the return site.
135
+ const auto &callee_head_node = cfg[successor_index];
136
+ auto callee_it = callee_head_node.PC ;
137
+ if (callee_it != std::next (node.PC ))
138
+ {
139
+ stack.emplace_back (successor_index, true );
140
+
141
+ // Check if it can return, and if so mark the callsite's successor:
142
+ while (!callee_it->is_end_function ())
143
+ ++callee_it;
144
+
145
+ if (cfg[cfg.entry_map [callee_it]].out .size () != 0 )
146
+ {
147
+ stack.emplace_back (
148
+ cfg.entry_map [std::next (node.PC )], caller_is_known);
149
+ }
150
+ }
151
+ else
152
+ {
153
+ // Bodyless function -- mark the successor instruction only.
154
+ stack.emplace_back (successor_index, caller_is_known);
155
+ }
156
+ }
157
+ else if (node.PC ->is_end_function ())
158
+ {
159
+ if (!caller_is_known)
160
+ {
161
+ for (const auto &edge : node.out )
162
+ stack.emplace_back (edge.first , false );
163
+ }
164
+ }
165
+ else
166
+ {
167
+ for (const auto &edge : node.out )
168
+ stack.emplace_back (edge.first , caller_is_known);
169
+ }
170
+ }
79
171
}
80
172
81
173
// / This function removes all instructions that have the flag
0 commit comments