@@ -54,11 +54,47 @@ void reachability_slicert::fixedpoint_to_assertions(
5454 const is_threadedt &is_threaded,
5555 slicing_criteriont &criterion)
5656{
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 );
5861
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+ }
6298}
6399
64100// / Perform forwards depth-first search of the control-flow graph of the
@@ -71,11 +107,67 @@ void reachability_slicert::fixedpoint_from_assertions(
71107 const is_threadedt &is_threaded,
72108 slicing_criteriont &criterion)
73109{
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+
75121
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+ }
79171}
80172
81173// / This function removes all instructions that have the flag
0 commit comments