/src/zeek/src/script_opt/ZAM/Driver.cc
Line | Count | Source |
1 | | // See the file "COPYING" in the main distribution directory for copyright. |
2 | | |
3 | | // Driver (and other high-level) methods for ZAM compilation. |
4 | | |
5 | | #include "zeek/Frame.h" |
6 | | #include "zeek/Reporter.h" |
7 | | #include "zeek/Scope.h" |
8 | | #include "zeek/script_opt/ScriptOpt.h" |
9 | | #include "zeek/script_opt/ZAM/Compile.h" |
10 | | |
11 | | namespace zeek::detail { |
12 | | |
13 | | ZAMCompiler::ZAMCompiler(ScriptFuncPtr f, std::shared_ptr<ProfileFuncs> _pfs, std::shared_ptr<ProfileFunc> _pf, |
14 | 0 | ScopePtr _scope, StmtPtr _body, std::shared_ptr<UseDefs> _ud, std::shared_ptr<Reducer> _rd) { |
15 | 0 | func = std::move(f); |
16 | 0 | pfs = std::move(_pfs); |
17 | 0 | pf = std::move(_pf); |
18 | 0 | scope = std::move(_scope); |
19 | 0 | body = std::move(_body); |
20 | 0 | ud = std::move(_ud); |
21 | 0 | reducer = std::move(_rd); |
22 | 0 | frame_sizeI = 0; |
23 | |
|
24 | 0 | auto loc = body->GetLocationInfo(); |
25 | 0 | ASSERT(loc->FirstLine() != 0 || body->Tag() == STMT_NULL); |
26 | 0 | auto loc_copy = std::make_shared<Location>(loc->FileName(), loc->FirstLine(), loc->LastLine()); |
27 | 0 | ZAM::curr_func = func->GetName(); |
28 | 0 | ZAM::curr_loc = std::make_shared<ZAMLocInfo>(ZAM::curr_func, std::move(loc_copy), nullptr); |
29 | |
|
30 | 0 | Init(); |
31 | 0 | } |
32 | | |
33 | 0 | ZAMCompiler::~ZAMCompiler() { |
34 | 0 | for ( auto i : insts1 ) |
35 | 0 | delete i; |
36 | 0 | } |
37 | | |
38 | 0 | void ZAMCompiler::Init() { |
39 | 0 | InitGlobals(); |
40 | 0 | InitArgs(); |
41 | 0 | InitCaptures(); |
42 | 0 | InitLocals(); |
43 | |
|
44 | 0 | TrackMemoryManagement(); |
45 | |
|
46 | 0 | non_recursive = non_recursive_funcs.contains(func.get()); |
47 | 0 | } |
48 | | |
49 | 0 | void ZAMCompiler::InitGlobals() { |
50 | 0 | for ( auto& g : pf->Globals() ) { |
51 | 0 | GlobalInfo info{.id = g, .slot = AddToFrame(g)}; |
52 | 0 | global_id_to_info[g] = globalsI.size(); |
53 | 0 | globalsI.push_back(info); |
54 | 0 | } |
55 | 0 | } |
56 | | |
57 | 0 | void ZAMCompiler::InitArgs() { |
58 | 0 | auto uds = ud->HasUsage(body.get()) ? ud->GetUsage(body.get()) : nullptr; |
59 | |
|
60 | 0 | auto args = scope->OrderedVars(); |
61 | 0 | int nparam = func->GetType()->Params()->NumFields(); |
62 | |
|
63 | 0 | push_existing_scope(scope); |
64 | |
|
65 | 0 | for ( auto& a : args ) { |
66 | 0 | if ( --nparam < 0 ) |
67 | 0 | break; |
68 | | |
69 | 0 | if ( uds && uds->HasID(a) ) |
70 | 0 | LoadParam(a); |
71 | 0 | else { |
72 | | // printf("param %s unused\n", obj_desc(arg_id.get())); |
73 | 0 | } |
74 | 0 | } |
75 | |
|
76 | 0 | pop_scope(); |
77 | 0 | } |
78 | | |
79 | 0 | void ZAMCompiler::InitCaptures() { |
80 | 0 | for ( const auto& c : pf->Captures() ) |
81 | 0 | (void)AddToFrame(c); |
82 | 0 | } |
83 | | |
84 | 0 | void ZAMCompiler::InitLocals() { |
85 | | // Assign slots for locals (which includes temporaries). |
86 | 0 | for ( auto& l : pf->Locals() ) { |
87 | 0 | if ( IsCapture(l) ) |
88 | 0 | continue; |
89 | | |
90 | 0 | if ( pf->WhenLocals().contains(l) ) |
91 | 0 | continue; |
92 | | |
93 | | // Don't add locals that were already added because they're |
94 | | // parameters. |
95 | | // |
96 | | // Don't worry about unused variables, those will get |
97 | | // removed during low-level ZAM optimization. |
98 | 0 | if ( ! HasFrameSlot(l) ) |
99 | 0 | (void)AddToFrame(l); |
100 | 0 | } |
101 | 0 | } |
102 | | |
103 | 0 | void ZAMCompiler::TrackMemoryManagement() { |
104 | 0 | for ( auto& slot : frame_layout1 ) { |
105 | | // Look for locals with values of types for which |
106 | | // we do explicit memory management on (re)assignment. |
107 | 0 | auto t = slot.first->GetType(); |
108 | 0 | if ( ZVal::IsManagedType(t) ) |
109 | 0 | managed_slotsI.push_back(slot.second); |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | 0 | StmtPtr ZAMCompiler::CompileBody() { |
114 | 0 | if ( func->Flavor() == FUNC_FLAVOR_HOOK ) |
115 | 0 | PushBreaks(); |
116 | |
|
117 | 0 | (void)CompileStmt(body); |
118 | |
|
119 | 0 | if ( reporter->Errors() > 0 ) |
120 | 0 | return nullptr; |
121 | | |
122 | 0 | ResolveHookBreaks(); |
123 | |
|
124 | 0 | if ( ! nexts.empty() ) |
125 | 0 | reporter->Error("\"next\" used without an enclosing \"for\""); |
126 | |
|
127 | 0 | if ( ! fallthroughs.empty() ) |
128 | 0 | reporter->Error("\"fallthrough\" used without an enclosing \"switch\""); |
129 | |
|
130 | 0 | if ( ! catches.empty() ) |
131 | 0 | reporter->InternalError("untargeted inline return"); |
132 | | |
133 | | // Make sure we have a (pseudo-)instruction at the end so we |
134 | | // can use it as a branch label. |
135 | 0 | if ( ! pending_inst ) |
136 | 0 | pending_inst = new ZInstI(); |
137 | | |
138 | | // Concretize instruction numbers in inst1 so we can |
139 | | // easily move through the code. |
140 | 0 | for ( auto i = 0U; i < insts1.size(); ++i ) |
141 | 0 | insts1[i]->inst_num = i; |
142 | |
|
143 | 0 | ComputeLoopLevels(); |
144 | |
|
145 | 0 | if ( ! analysis_options.no_ZAM_opt ) |
146 | 0 | OptimizeInsts(); |
147 | |
|
148 | 0 | AdjustBranches(); |
149 | | |
150 | | // Construct the final program with the dead code eliminated |
151 | | // and branches resolved. |
152 | | |
153 | | // Make sure we don't include the empty pending-instruction, if any. |
154 | 0 | if ( pending_inst ) |
155 | 0 | pending_inst->live = false; |
156 | | |
157 | | // Maps inst1 instructions to where they are in inst2. |
158 | | // Dead instructions map to -1. |
159 | 0 | std::vector<int> inst1_to_inst2; |
160 | |
|
161 | 0 | for ( auto& i1 : insts1 ) { |
162 | 0 | if ( i1->live ) { |
163 | 0 | inst1_to_inst2.push_back(insts2.size()); |
164 | 0 | insts2.push_back(i1); |
165 | 0 | } |
166 | 0 | else |
167 | 0 | inst1_to_inst2.push_back(-1); |
168 | 0 | } |
169 | | |
170 | | // Re-concretize instruction numbers, and concretize GoTo's. |
171 | 0 | for ( auto i = 0U; i < insts2.size(); ++i ) |
172 | 0 | insts2[i]->inst_num = i; |
173 | |
|
174 | 0 | RetargetBranches(); |
175 | | |
176 | | // If we have remapped frame denizens, update them. If not, |
177 | | // create them. |
178 | 0 | if ( ! shared_frame_denizens.empty() ) |
179 | 0 | RemapFrameDenizens(inst1_to_inst2); |
180 | | |
181 | 0 | else |
182 | 0 | CreateSharedFrameDenizens(); |
183 | |
|
184 | 0 | delete pending_inst; |
185 | |
|
186 | 0 | ConcretizeSwitches(); |
187 | |
|
188 | 0 | auto fname = func->GetName(); |
189 | |
|
190 | 0 | if ( func->Flavor() == FUNC_FLAVOR_FUNCTION ) |
191 | 0 | fname = func_name_at_loc(fname, body->GetLocationInfo()); |
192 | |
|
193 | 0 | auto zb = make_intrusive<ZBody>(fname, this); |
194 | 0 | zb->SetInsts(insts2); |
195 | 0 | zb->SetLocationInfo(body->GetLocationInfo()); |
196 | | |
197 | | // Could erase insts1 here to recover memory, but it's handy |
198 | | // for debugging. |
199 | |
|
200 | 0 | return zb; |
201 | 0 | } |
202 | | |
203 | 0 | void ZAMCompiler::ResolveHookBreaks() { |
204 | 0 | if ( ! breaks.empty() ) { |
205 | 0 | ASSERT(breaks.size() == 1); |
206 | | |
207 | 0 | if ( func->Flavor() == FUNC_FLAVOR_HOOK ) { |
208 | | // Rewrite the breaks. |
209 | 0 | for ( auto& b : breaks[0] ) { |
210 | 0 | auto& i = insts1[b.stmt_num]; |
211 | 0 | auto aux = i->aux; |
212 | 0 | *i = ZInstI(OP_HOOK_BREAK_X); |
213 | 0 | i->aux = aux; |
214 | 0 | } |
215 | 0 | } |
216 | | |
217 | 0 | else |
218 | 0 | reporter->Error("\"break\" used without an enclosing \"for\" or \"switch\""); |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | 0 | void ZAMCompiler::ComputeLoopLevels() { |
223 | | // Compute which instructions are inside loops. |
224 | 0 | for ( auto i = 0; i < static_cast<int>(insts1.size()); ++i ) { |
225 | 0 | auto inst = insts1[i]; |
226 | |
|
227 | 0 | auto t = inst->target; |
228 | 0 | if ( ! t || t == pending_inst ) |
229 | 0 | continue; |
230 | | |
231 | 0 | if ( t->inst_num < i ) { |
232 | 0 | auto j = t->inst_num; |
233 | |
|
234 | 0 | if ( ! t->loop_start ) { |
235 | | // Loop is newly discovered. |
236 | 0 | t->loop_start = true; |
237 | 0 | } |
238 | 0 | else { |
239 | | // We're extending an existing loop. Find |
240 | | // its current end. |
241 | 0 | auto depth = t->loop_depth; |
242 | 0 | while ( j < i && insts1[j]->loop_depth >= depth ) |
243 | 0 | ++j; |
244 | |
|
245 | 0 | ASSERT(insts1[j]->loop_depth == depth - 1); |
246 | 0 | } |
247 | | |
248 | | // Run from j's current position to i, bumping |
249 | | // the loop depth. |
250 | 0 | while ( j <= i ) { |
251 | 0 | ++insts1[j]->loop_depth; |
252 | 0 | ++j; |
253 | 0 | } |
254 | 0 | } |
255 | 0 | } |
256 | 0 | } |
257 | | |
258 | 0 | void ZAMCompiler::AdjustBranches() { |
259 | | // Move branches to dead code forward to their successor live code. |
260 | 0 | for ( auto& inst : insts1 ) { |
261 | 0 | if ( ! inst->live ) |
262 | 0 | continue; |
263 | | |
264 | 0 | if ( auto t = inst->target ) |
265 | 0 | inst->target = FindLiveTarget(t); |
266 | 0 | } |
267 | | |
268 | | // Fix up the implicit branches in switches, too. |
269 | 0 | AdjustSwitchTables(int_casesI); |
270 | 0 | AdjustSwitchTables(uint_casesI); |
271 | 0 | AdjustSwitchTables(double_casesI); |
272 | 0 | AdjustSwitchTables(str_casesI); |
273 | 0 | } |
274 | | |
275 | | template<typename T> |
276 | 0 | void ZAMCompiler::AdjustSwitchTables(CaseMapsI<T>& abstract_cases) { |
277 | 0 | for ( auto& targs : abstract_cases ) { |
278 | 0 | for ( auto& targ : targs ) |
279 | 0 | targ.second = FindLiveTarget(targ.second); |
280 | 0 | } |
281 | 0 | } Unexecuted instantiation: void zeek::detail::ZAMCompiler::AdjustSwitchTables<long>(std::__1::vector<std::__1::map<long, zeek::detail::ZInstI*, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<long, zeek::detail::ZInstI*, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, zeek::detail::ZInstI*> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::AdjustSwitchTables<unsigned long>(std::__1::vector<std::__1::map<unsigned long, zeek::detail::ZInstI*, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<unsigned long, zeek::detail::ZInstI*, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, zeek::detail::ZInstI*> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::AdjustSwitchTables<double>(std::__1::vector<std::__1::map<double, zeek::detail::ZInstI*, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<double, zeek::detail::ZInstI*, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, zeek::detail::ZInstI*> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::AdjustSwitchTables<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::vector<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, zeek::detail::ZInstI*, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, zeek::detail::ZInstI*, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, zeek::detail::ZInstI*> > > > >&) |
282 | | |
283 | 0 | void ZAMCompiler::RetargetBranches() { |
284 | 0 | for ( auto& inst : insts2 ) |
285 | 0 | if ( inst->target ) |
286 | 0 | ConcretizeBranch(inst, inst->target, inst->target_slot); |
287 | 0 | } |
288 | | |
289 | 0 | void ZAMCompiler::RemapFrameDenizens(const std::vector<int>& inst1_to_inst2) { |
290 | 0 | for ( auto& info : shared_frame_denizens ) { |
291 | 0 | for ( auto& start : info.id_start ) { |
292 | | // It can happen that the identifier's |
293 | | // origination instruction was optimized |
294 | | // away, if due to slot sharing it's of |
295 | | // the form "slotX = slotX". In that |
296 | | // case, look forward for the next viable |
297 | | // instruction. |
298 | 0 | while ( start < insts1.size() && inst1_to_inst2[start] == -1 ) |
299 | 0 | ++start; |
300 | |
|
301 | 0 | ASSERT(start < insts1.size()); |
302 | 0 | start = inst1_to_inst2[start]; |
303 | 0 | } |
304 | | |
305 | 0 | shared_frame_denizens_final.push_back(info); |
306 | 0 | } |
307 | 0 | } |
308 | | |
309 | 0 | void ZAMCompiler::CreateSharedFrameDenizens() { |
310 | 0 | for ( auto& fd : frame_denizens ) { |
311 | 0 | FrameSharingInfo info; |
312 | 0 | info.ids.push_back(fd); |
313 | 0 | info.id_start.push_back(0); |
314 | 0 | info.scope_end = insts2.size(); |
315 | | |
316 | | // The following doesn't matter since the value |
317 | | // is only used during compiling, not during |
318 | | // execution. |
319 | 0 | info.is_managed = false; |
320 | |
|
321 | 0 | shared_frame_denizens_final.push_back(std::move(info)); |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | 0 | void ZAMCompiler::ConcretizeSwitches() { |
326 | | // Create concretized versions of any case tables. |
327 | 0 | ConcretizeSwitchTables(int_casesI, int_cases); |
328 | 0 | ConcretizeSwitchTables(uint_casesI, uint_cases); |
329 | 0 | ConcretizeSwitchTables(double_casesI, double_cases); |
330 | 0 | ConcretizeSwitchTables(str_casesI, str_cases); |
331 | 0 | } |
332 | | |
333 | | template<typename T> |
334 | 0 | void ZAMCompiler::ConcretizeSwitchTables(const CaseMapsI<T>& abstract_cases, CaseMaps<T>& concrete_cases) { |
335 | 0 | for ( auto& targs : abstract_cases ) { |
336 | 0 | CaseMap<T> cm; |
337 | 0 | for ( auto& targ : targs ) |
338 | 0 | cm[targ.first] = targ.second->inst_num; |
339 | 0 | concrete_cases.emplace_back(cm); |
340 | 0 | } |
341 | 0 | } Unexecuted instantiation: void zeek::detail::ZAMCompiler::ConcretizeSwitchTables<long>(std::__1::vector<std::__1::map<long, zeek::detail::ZInstI*, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<long, zeek::detail::ZInstI*, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, zeek::detail::ZInstI*> > > > > const&, std::__1::vector<std::__1::map<long, int, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, int> > >, std::__1::allocator<std::__1::map<long, int, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, int> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::ConcretizeSwitchTables<unsigned long>(std::__1::vector<std::__1::map<unsigned long, zeek::detail::ZInstI*, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<unsigned long, zeek::detail::ZInstI*, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, zeek::detail::ZInstI*> > > > > const&, std::__1::vector<std::__1::map<unsigned long, int, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, int> > >, std::__1::allocator<std::__1::map<unsigned long, int, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, int> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::ConcretizeSwitchTables<double>(std::__1::vector<std::__1::map<double, zeek::detail::ZInstI*, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<double, zeek::detail::ZInstI*, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, zeek::detail::ZInstI*> > > > > const&, std::__1::vector<std::__1::map<double, int, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, int> > >, std::__1::allocator<std::__1::map<double, int, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, int> > > > >&) Unexecuted instantiation: void zeek::detail::ZAMCompiler::ConcretizeSwitchTables<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::vector<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, zeek::detail::ZInstI*, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, zeek::detail::ZInstI*> > >, std::__1::allocator<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, zeek::detail::ZInstI*, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, zeek::detail::ZInstI*> > > > > const&, std::__1::vector<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, int> > >, std::__1::allocator<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, int> > > > >&) |
342 | | |
343 | | #include "ZAM-MethodDefs.h" |
344 | | |
345 | 0 | void ZAMCompiler::Dump() { |
346 | 0 | bool remapped_frame = ! analysis_options.no_ZAM_opt; |
347 | |
|
348 | 0 | if ( analysis_options.dump_ZAM ) { |
349 | 0 | if ( remapped_frame ) |
350 | 0 | printf("\nOriginal frame for %s:\n", func->GetName().c_str()); |
351 | |
|
352 | 0 | for ( const auto& elem : frame_layout1 ) |
353 | 0 | printf("frame[%d] = %s\n", elem.second, elem.first->Name()); |
354 | |
|
355 | 0 | if ( remapped_frame ) { |
356 | 0 | printf("Final frame for %s:\n", func->GetName().c_str()); |
357 | |
|
358 | 0 | for ( auto i = 0U; i < shared_frame_denizens.size(); ++i ) { |
359 | 0 | printf("frame2[%d] =", i); |
360 | 0 | for ( auto& id : shared_frame_denizens[i].ids ) |
361 | 0 | printf(" %s", id->Name()); |
362 | 0 | printf("\n"); |
363 | 0 | } |
364 | 0 | } |
365 | |
|
366 | 0 | if ( ! insts2.empty() ) |
367 | 0 | printf("Pre-removal of dead code for %s:\n", func->GetName().c_str()); |
368 | |
|
369 | 0 | auto remappings = remapped_frame ? &shared_frame_denizens : nullptr; |
370 | |
|
371 | 0 | DumpInsts1(remappings); |
372 | |
|
373 | 0 | if ( ! insts2.empty() ) |
374 | 0 | printf("Final intermediary code for %s:\n", func->GetName().c_str()); |
375 | |
|
376 | 0 | remappings = remapped_frame ? &shared_frame_denizens_final : nullptr; |
377 | |
|
378 | 0 | for ( auto i = 0U; i < insts2.size(); ++i ) { |
379 | 0 | auto& inst = insts2[i]; |
380 | 0 | std::string liveness; |
381 | 0 | std::string depth; |
382 | |
|
383 | 0 | if ( inst->live ) |
384 | 0 | liveness = util::fmt("(labels %d)", inst->num_labels); |
385 | 0 | else |
386 | 0 | liveness = "(dead)"; |
387 | |
|
388 | 0 | if ( inst->loop_depth ) |
389 | 0 | depth = util::fmt(" (loop %d)", inst->loop_depth); |
390 | |
|
391 | 0 | printf("%d %s%s: ", i, liveness.c_str(), depth.c_str()); |
392 | |
|
393 | 0 | inst->Dump(stdout, &frame_denizens, remappings); |
394 | 0 | } |
395 | 0 | } |
396 | 0 | else if ( analysis_options.dump_final_ZAM ) { |
397 | 0 | printf("\nFrame for %s:\n", func->GetName().c_str()); |
398 | |
|
399 | 0 | if ( remapped_frame ) { |
400 | 0 | for ( auto i = 0U; i < shared_frame_denizens.size(); ++i ) { |
401 | 0 | printf("frame[%d] =", i); |
402 | 0 | for ( auto& id : shared_frame_denizens[i].ids ) |
403 | 0 | printf(" %s", id->Name()); |
404 | 0 | printf("\n"); |
405 | 0 | } |
406 | 0 | } |
407 | 0 | else |
408 | 0 | for ( const auto& elem : frame_layout1 ) |
409 | 0 | printf("frame[%d] = %s\n", elem.second, elem.first->Name()); |
410 | 0 | } |
411 | |
|
412 | 0 | if ( ! insts2.empty() ) |
413 | 0 | printf("Final code for %s:\n", func->GetName().c_str()); |
414 | |
|
415 | 0 | auto remappings = remapped_frame ? &shared_frame_denizens_final : nullptr; |
416 | 0 | for ( auto i = 0U; i < insts2.size(); ++i ) { |
417 | 0 | auto& inst = insts2[i]; |
418 | | // printf("%s:%d\n", inst->loc->filename, inst->loc->first_line); |
419 | 0 | printf("%d: ", i); |
420 | 0 | inst->Dump(stdout, &frame_denizens, remappings); |
421 | 0 | } |
422 | |
|
423 | 0 | DumpCases(int_cases, "int"); |
424 | 0 | DumpCases(uint_cases, "uint"); |
425 | 0 | DumpCases(double_cases, "double"); |
426 | 0 | DumpCases(str_cases, "str"); |
427 | 0 | } |
428 | | |
429 | | template<typename T> |
430 | 0 | void ZAMCompiler::DumpCases(const CaseMaps<T>& cases, const char* type_name) const { |
431 | 0 | for ( auto i = 0U; i < cases.size(); ++i ) { |
432 | 0 | printf("%s switch table #%d:", type_name, i); |
433 | 0 | for ( auto& m : cases[i] ) { |
434 | 0 | std::string case_val; |
435 | | if constexpr ( std::is_same_v<T, std::string> ) |
436 | 0 | case_val = m.first; |
437 | | else if constexpr ( std::is_same_v<T, zeek_int_t> || std::is_same_v<T, zeek_uint_t> || |
438 | | std::is_same_v<T, double> ) |
439 | 0 | case_val = std::to_string(m.first); |
440 | |
|
441 | 0 | printf(" %s->%d", case_val.c_str(), m.second); |
442 | 0 | } |
443 | 0 | printf("\n"); |
444 | 0 | } |
445 | 0 | } Unexecuted instantiation: void zeek::detail::ZAMCompiler::DumpCases<long>(std::__1::vector<std::__1::map<long, int, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, int> > >, std::__1::allocator<std::__1::map<long, int, std::__1::less<long>, std::__1::allocator<std::__1::pair<long const, int> > > > > const&, char const*) const Unexecuted instantiation: void zeek::detail::ZAMCompiler::DumpCases<unsigned long>(std::__1::vector<std::__1::map<unsigned long, int, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, int> > >, std::__1::allocator<std::__1::map<unsigned long, int, std::__1::less<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, int> > > > > const&, char const*) const Unexecuted instantiation: void zeek::detail::ZAMCompiler::DumpCases<double>(std::__1::vector<std::__1::map<double, int, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, int> > >, std::__1::allocator<std::__1::map<double, int, std::__1::less<double>, std::__1::allocator<std::__1::pair<double const, int> > > > > const&, char const*) const Unexecuted instantiation: void zeek::detail::ZAMCompiler::DumpCases<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::vector<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, int> > >, std::__1::allocator<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, int> > > > > const&, char const*) const |
446 | | |
447 | 0 | void ZAMCompiler::DumpInsts1(const FrameReMap* remappings) { |
448 | 0 | for ( auto i = 0U; i < insts1.size(); ++i ) { |
449 | 0 | auto& inst = insts1[i]; |
450 | |
|
451 | 0 | if ( inst->target ) |
452 | | // To get meaningful branch information in the dump, |
453 | | // we need to concretize the branch slots |
454 | 0 | ConcretizeBranch(inst, inst->target, inst->target_slot); |
455 | |
|
456 | 0 | std::string liveness; |
457 | 0 | std::string depth; |
458 | |
|
459 | 0 | if ( inst->live ) |
460 | 0 | liveness = util::fmt("(labels %d)", inst->num_labels); |
461 | 0 | else |
462 | 0 | liveness = "(dead)"; |
463 | |
|
464 | 0 | if ( inst->loop_depth ) |
465 | 0 | depth = util::fmt(" (loop %d)", inst->loop_depth); |
466 | |
|
467 | 0 | printf("%d %s%s: ", i, liveness.c_str(), depth.c_str()); |
468 | |
|
469 | | inst->Dump(stdout, &frame_denizens, remappings); |
470 | 0 | } |
471 | 0 | } |
472 | | |
473 | | } // namespace zeek::detail |