File: | root/firefox-clang/third_party/rust/glslopt/glsl-optimizer/src/compiler/glsl/list.h |
Warning: | line 190, column 18 Access to field 'next' results in a dereference of a null pointer (loaded from field 'prev') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright © 2010 Luca Barbieri | ||||
3 | * | ||||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||||
5 | * copy of this software and associated documentation files (the "Software"), | ||||
6 | * to deal in the Software without restriction, including without limitation | ||||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||||
9 | * Software is furnished to do so, subject to the following conditions: | ||||
10 | * | ||||
11 | * The above copyright notice and this permission notice (including the next | ||||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||||
13 | * Software. | ||||
14 | * | ||||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
21 | * DEALINGS IN THE SOFTWARE. | ||||
22 | */ | ||||
23 | |||||
24 | /** | ||||
25 | * \file lower_jumps.cpp | ||||
26 | * | ||||
27 | * This pass lowers jumps (break, continue, and return) to if/else structures. | ||||
28 | * | ||||
29 | * It can be asked to: | ||||
30 | * 1. Pull jumps out of ifs where possible | ||||
31 | * 2. Remove all "continue"s, replacing them with an "execute flag" | ||||
32 | * 3. Replace all "break" with a single conditional one at the end of the loop | ||||
33 | * 4. Replace all "return"s with a single return at the end of the function, | ||||
34 | * for the main function and/or other functions | ||||
35 | * | ||||
36 | * Applying this pass gives several benefits: | ||||
37 | * 1. All functions can be inlined. | ||||
38 | * 2. nv40 and other pre-DX10 chips without "continue" can be supported | ||||
39 | * 3. nv30 and other pre-DX10 chips with no control flow at all are better | ||||
40 | * supported | ||||
41 | * | ||||
42 | * Continues are lowered by adding a per-loop "execute flag", initialized to | ||||
43 | * true, that when cleared inhibits all execution until the end of the loop. | ||||
44 | * | ||||
45 | * Breaks are lowered to continues, plus setting a "break flag" that is checked | ||||
46 | * at the end of the loop, and trigger the unique "break". | ||||
47 | * | ||||
48 | * Returns are lowered to breaks/continues, plus adding a "return flag" that | ||||
49 | * causes loops to break again out of their enclosing loops until all the | ||||
50 | * loops are exited: then the "execute flag" logic will ignore everything | ||||
51 | * until the end of the function. | ||||
52 | * | ||||
53 | * Note that "continue" and "return" can also be implemented by adding | ||||
54 | * a dummy loop and using break. | ||||
55 | * However, this is bad for hardware with limited nesting depth, and | ||||
56 | * prevents further optimization, and thus is not currently performed. | ||||
57 | */ | ||||
58 | |||||
59 | #include "compiler/glsl_types.h" | ||||
60 | #include <string.h> | ||||
61 | #include "ir.h" | ||||
62 | |||||
63 | /** | ||||
64 | * Enum recording the result of analyzing how control flow might exit | ||||
65 | * an IR node. | ||||
66 | * | ||||
67 | * Each possible value of jump_strength indicates a strictly stronger | ||||
68 | * guarantee on control flow than the previous value. | ||||
69 | * | ||||
70 | * The ordering of strengths roughly reflects the way jumps are | ||||
71 | * lowered: jumps with higher strength tend to be lowered to jumps of | ||||
72 | * lower strength. Accordingly, strength is used as a heuristic to | ||||
73 | * determine which lowering to perform first. | ||||
74 | * | ||||
75 | * This enum is also used by get_jump_strength() to categorize | ||||
76 | * instructions as either break, continue, return, or other. When | ||||
77 | * used in this fashion, strength_always_clears_execute_flag is not | ||||
78 | * used. | ||||
79 | * | ||||
80 | * The control flow analysis made by this optimization pass makes two | ||||
81 | * simplifying assumptions: | ||||
82 | * | ||||
83 | * - It ignores discard instructions, since they are lowered by a | ||||
84 | * separate pass (lower_discard.cpp). | ||||
85 | * | ||||
86 | * - It assumes it is always possible for control to flow from a loop | ||||
87 | * to the instruction immediately following it. Technically, this | ||||
88 | * is not true (since all execution paths through the loop might | ||||
89 | * jump back to the top, or return from the function). | ||||
90 | * | ||||
91 | * Both of these simplifying assumtions are safe, since they can never | ||||
92 | * cause reachable code to be incorrectly classified as unreachable; | ||||
93 | * they can only do the opposite. | ||||
94 | */ | ||||
95 | enum jump_strength | ||||
96 | { | ||||
97 | /** | ||||
98 | * Analysis has produced no guarantee on how control flow might | ||||
99 | * exit this IR node. It might fall out the bottom (with or | ||||
100 | * without clearing the execute flag, if present), or it might | ||||
101 | * continue to the top of the innermost enclosing loop, break out | ||||
102 | * of it, or return from the function. | ||||
103 | */ | ||||
104 | strength_none, | ||||
105 | |||||
106 | /** | ||||
107 | * The only way control can fall out the bottom of this node is | ||||
108 | * through a code path that clears the execute flag. It might also | ||||
109 | * continue to the top of the innermost enclosing loop, break out | ||||
110 | * of it, or return from the function. | ||||
111 | */ | ||||
112 | strength_always_clears_execute_flag, | ||||
113 | |||||
114 | /** | ||||
115 | * Control cannot fall out the bottom of this node. It might | ||||
116 | * continue to the top of the innermost enclosing loop, break out | ||||
117 | * of it, or return from the function. | ||||
118 | */ | ||||
119 | strength_continue, | ||||
120 | |||||
121 | /** | ||||
122 | * Control cannot fall out the bottom of this node, or continue the | ||||
123 | * top of the innermost enclosing loop. It can only break out of | ||||
124 | * it or return from the function. | ||||
125 | */ | ||||
126 | strength_break, | ||||
127 | |||||
128 | /** | ||||
129 | * Control cannot fall out the bottom of this node, continue to the | ||||
130 | * top of the innermost enclosing loop, or break out of it. It can | ||||
131 | * only return from the function. | ||||
132 | */ | ||||
133 | strength_return | ||||
134 | }; | ||||
135 | |||||
136 | namespace { | ||||
137 | |||||
138 | struct block_record | ||||
139 | { | ||||
140 | /* minimum jump strength (of lowered IR, not pre-lowering IR) | ||||
141 | * | ||||
142 | * If the block ends with a jump, must be the strength of the jump. | ||||
143 | * Otherwise, the jump would be dead and have been deleted before) | ||||
144 | * | ||||
145 | * If the block doesn't end with a jump, it can be different than strength_none if all paths before it lead to some jump | ||||
146 | * (e.g. an if with a return in one branch, and a break in the other, while not lowering them) | ||||
147 | * Note that identical jumps are usually unified though. | ||||
148 | */ | ||||
149 | jump_strength min_strength; | ||||
150 | |||||
151 | /* can anything clear the execute flag? */ | ||||
152 | bool may_clear_execute_flag; | ||||
153 | |||||
154 | block_record() | ||||
155 | { | ||||
156 | this->min_strength = strength_none; | ||||
157 | this->may_clear_execute_flag = false; | ||||
158 | } | ||||
159 | }; | ||||
160 | |||||
161 | struct loop_record | ||||
162 | { | ||||
163 | ir_function_signature* signature; | ||||
164 | ir_loop* loop; | ||||
165 | |||||
166 | /* used to avoid lowering the break used to represent lowered breaks */ | ||||
167 | unsigned nesting_depth; | ||||
168 | bool in_if_at_the_end_of_the_loop; | ||||
169 | |||||
170 | bool may_set_return_flag; | ||||
171 | |||||
172 | ir_variable* break_flag; | ||||
173 | ir_variable* execute_flag; /* cleared to emulate continue */ | ||||
174 | |||||
175 | loop_record(ir_function_signature* p_signature = 0, ir_loop* p_loop = 0) | ||||
176 | { | ||||
177 | this->signature = p_signature; | ||||
178 | this->loop = p_loop; | ||||
179 | this->nesting_depth = 0; | ||||
180 | this->in_if_at_the_end_of_the_loop = false; | ||||
181 | this->may_set_return_flag = false; | ||||
182 | this->break_flag = 0; | ||||
183 | this->execute_flag = 0; | ||||
184 | } | ||||
185 | |||||
186 | ir_variable* get_execute_flag() | ||||
187 | { | ||||
188 | /* also supported for the "function loop" */ | ||||
189 | if(!this->execute_flag) { | ||||
190 | exec_list& list = this->loop ? this->loop->body_instructions : signature->body; | ||||
191 | this->execute_flag = new(this->signature) ir_variable(glsl_type::bool_type, "execute_flag", ir_var_temporary); | ||||
192 | list.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(execute_flag), new(this->signature) ir_constant(true))); | ||||
193 | list.push_head(this->execute_flag); | ||||
194 | } | ||||
195 | return this->execute_flag; | ||||
196 | } | ||||
197 | |||||
198 | ir_variable* get_break_flag() | ||||
199 | { | ||||
200 | assert(this->loop)(static_cast <bool> (this->loop) ? void (0) : __assert_fail ("this->loop", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
201 | if(!this->break_flag) { | ||||
202 | this->break_flag = new(this->signature) ir_variable(glsl_type::bool_type, "break_flag", ir_var_temporary); | ||||
203 | this->loop->insert_before(this->break_flag); | ||||
204 | this->loop->insert_before(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(break_flag), new(this->signature) ir_constant(false))); | ||||
205 | } | ||||
206 | return this->break_flag; | ||||
207 | } | ||||
208 | }; | ||||
209 | |||||
210 | struct function_record | ||||
211 | { | ||||
212 | ir_function_signature* signature; | ||||
213 | ir_variable* return_flag; /* used to break out of all loops and then jump to the return instruction */ | ||||
214 | ir_variable* return_value; | ||||
215 | bool lower_return; | ||||
216 | unsigned nesting_depth; | ||||
217 | |||||
218 | function_record(ir_function_signature* p_signature = 0, | ||||
219 | bool lower_return = false) | ||||
220 | { | ||||
221 | this->signature = p_signature; | ||||
222 | this->return_flag = 0; | ||||
223 | this->return_value = 0; | ||||
224 | this->nesting_depth = 0; | ||||
225 | this->lower_return = lower_return; | ||||
226 | } | ||||
227 | |||||
228 | ir_variable* get_return_flag() | ||||
229 | { | ||||
230 | if(!this->return_flag) { | ||||
231 | this->return_flag = new(this->signature) ir_variable(glsl_type::bool_type, "return_flag", ir_var_temporary); | ||||
232 | this->signature->body.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(return_flag), new(this->signature) ir_constant(false))); | ||||
233 | this->signature->body.push_head(this->return_flag); | ||||
234 | } | ||||
235 | return this->return_flag; | ||||
236 | } | ||||
237 | |||||
238 | ir_variable* get_return_value() | ||||
239 | { | ||||
240 | if(!this->return_value) { | ||||
241 | assert(!this->signature->return_type->is_void())(static_cast <bool> (!this->signature->return_type ->is_void()) ? void (0) : __assert_fail ("!this->signature->return_type->is_void()" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | ||||
242 | return_value = new(this->signature) ir_variable(this->signature->return_type, "return_value", ir_var_temporary); | ||||
243 | this->signature->body.push_head(this->return_value); | ||||
244 | } | ||||
245 | return this->return_value; | ||||
246 | } | ||||
247 | }; | ||||
248 | |||||
249 | struct ir_lower_jumps_visitor : public ir_control_flow_visitor { | ||||
250 | /* Postconditions: on exit of any visit() function: | ||||
251 | * | ||||
252 | * ANALYSIS: this->block.min_strength, | ||||
253 | * this->block.may_clear_execute_flag, and | ||||
254 | * this->loop.may_set_return_flag are updated to reflect the | ||||
255 | * characteristics of the visited statement. | ||||
256 | * | ||||
257 | * DEAD_CODE_ELIMINATION: If this->block.min_strength is not | ||||
258 | * strength_none, the visited node is at the end of its exec_list. | ||||
259 | * In other words, any unreachable statements that follow the | ||||
260 | * visited statement in its exec_list have been removed. | ||||
261 | * | ||||
262 | * CONTAINED_JUMPS_LOWERED: If the visited statement contains other | ||||
263 | * statements, then should_lower_jump() is false for all of the | ||||
264 | * return, break, or continue statements it contains. | ||||
265 | * | ||||
266 | * Note that visiting a jump does not lower it. That is the | ||||
267 | * responsibility of the statement (or function signature) that | ||||
268 | * contains the jump. | ||||
269 | */ | ||||
270 | |||||
271 | using ir_control_flow_visitor::visit; | ||||
272 | |||||
273 | bool progress; | ||||
274 | |||||
275 | struct function_record function; | ||||
276 | struct loop_record loop; | ||||
277 | struct block_record block; | ||||
278 | |||||
279 | bool pull_out_jumps; | ||||
280 | bool lower_continue; | ||||
281 | bool lower_break; | ||||
282 | bool lower_sub_return; | ||||
283 | bool lower_main_return; | ||||
284 | |||||
285 | ir_lower_jumps_visitor() | ||||
286 | : progress(false), | ||||
287 | pull_out_jumps(false), | ||||
288 | lower_continue(false), | ||||
289 | lower_break(false), | ||||
290 | lower_sub_return(false), | ||||
291 | lower_main_return(false) | ||||
292 | { | ||||
293 | } | ||||
294 | |||||
295 | void truncate_after_instruction(exec_node *ir) | ||||
296 | { | ||||
297 | if (!ir) | ||||
298 | return; | ||||
299 | |||||
300 | while (!ir->get_next()->is_tail_sentinel()) { | ||||
301 | ((ir_instruction *)ir->get_next())->remove(); | ||||
302 | this->progress = true; | ||||
303 | } | ||||
304 | } | ||||
305 | |||||
306 | void move_outer_block_inside(ir_instruction *ir, exec_list *inner_block) | ||||
307 | { | ||||
308 | while (!ir->get_next()->is_tail_sentinel()) { | ||||
309 | ir_instruction *move_ir = (ir_instruction *)ir->get_next(); | ||||
310 | |||||
311 | move_ir->remove(); | ||||
312 | inner_block->push_tail(move_ir); | ||||
313 | } | ||||
314 | } | ||||
315 | |||||
316 | /** | ||||
317 | * Insert the instructions necessary to lower a return statement, | ||||
318 | * before the given return instruction. | ||||
319 | */ | ||||
320 | void insert_lowered_return(ir_return *ir) | ||||
321 | { | ||||
322 | ir_variable* return_flag = this->function.get_return_flag(); | ||||
323 | if(!this->function.signature->return_type->is_void()) { | ||||
324 | ir_variable* return_value = this->function.get_return_value(); | ||||
325 | ir->insert_before( | ||||
326 | new(ir) ir_assignment( | ||||
327 | new (ir) ir_dereference_variable(return_value), | ||||
328 | ir->value)); | ||||
329 | } | ||||
330 | ir->insert_before( | ||||
331 | new(ir) ir_assignment( | ||||
332 | new (ir) ir_dereference_variable(return_flag), | ||||
333 | new (ir) ir_constant(true))); | ||||
334 | this->loop.may_set_return_flag = true; | ||||
335 | } | ||||
336 | |||||
337 | /** | ||||
338 | * If the given instruction is a return, lower it to instructions | ||||
339 | * that store the return value (if there is one), set the return | ||||
340 | * flag, and then break. | ||||
341 | * | ||||
342 | * It is safe to pass NULL to this function. | ||||
343 | */ | ||||
344 | void lower_return_unconditionally(ir_instruction *ir) | ||||
345 | { | ||||
346 | if (get_jump_strength(ir) != strength_return) { | ||||
347 | return; | ||||
348 | } | ||||
349 | insert_lowered_return((ir_return*)ir); | ||||
350 | ir->replace_with(new(ir) ir_loop_jump(ir_loop_jump::jump_break)); | ||||
351 | } | ||||
352 | |||||
353 | /** | ||||
354 | * Create the necessary instruction to replace a break instruction. | ||||
355 | */ | ||||
356 | ir_instruction *create_lowered_break() | ||||
357 | { | ||||
358 | void *ctx = this->function.signature; | ||||
359 | return new(ctx) ir_assignment( | ||||
360 | new(ctx) ir_dereference_variable(this->loop.get_break_flag()), | ||||
361 | new(ctx) ir_constant(true)); | ||||
362 | } | ||||
363 | |||||
364 | /** | ||||
365 | * If the given instruction is a break, lower it to an instruction | ||||
366 | * that sets the break flag, without consulting | ||||
367 | * should_lower_jump(). | ||||
368 | * | ||||
369 | * It is safe to pass NULL to this function. | ||||
370 | */ | ||||
371 | void lower_break_unconditionally(ir_instruction *ir) | ||||
372 | { | ||||
373 | if (get_jump_strength(ir) != strength_break) { | ||||
374 | return; | ||||
375 | } | ||||
376 | ir->replace_with(create_lowered_break()); | ||||
377 | } | ||||
378 | |||||
379 | /** | ||||
380 | * If the block ends in a conditional or unconditional break, lower | ||||
381 | * it, even though should_lower_jump() says it needn't be lowered. | ||||
382 | */ | ||||
383 | void lower_final_breaks(exec_list *block) | ||||
384 | { | ||||
385 | ir_instruction *ir = (ir_instruction *) block->get_tail(); | ||||
386 | lower_break_unconditionally(ir); | ||||
387 | ir_if *ir_if = ir->as_if(); | ||||
388 | if (ir_if) { | ||||
389 | lower_break_unconditionally( | ||||
390 | (ir_instruction *) ir_if->then_instructions.get_tail()); | ||||
391 | lower_break_unconditionally( | ||||
392 | (ir_instruction *) ir_if->else_instructions.get_tail()); | ||||
393 | } | ||||
394 | } | ||||
395 | |||||
396 | virtual void visit(class ir_loop_jump * ir) | ||||
397 | { | ||||
398 | /* Eliminate all instructions after each one, since they are | ||||
399 | * unreachable. This satisfies the DEAD_CODE_ELIMINATION | ||||
400 | * postcondition. | ||||
401 | */ | ||||
402 | truncate_after_instruction(ir); | ||||
403 | |||||
404 | /* Set this->block.min_strength based on this instruction. This | ||||
405 | * satisfies the ANALYSIS postcondition. It is not necessary to | ||||
406 | * update this->block.may_clear_execute_flag or | ||||
407 | * this->loop.may_set_return_flag, because an unlowered jump | ||||
408 | * instruction can't change any flags. | ||||
409 | */ | ||||
410 | this->block.min_strength = ir->is_break() ? strength_break : strength_continue; | ||||
411 | |||||
412 | /* The CONTAINED_JUMPS_LOWERED postcondition is already | ||||
413 | * satisfied, because jump statements can't contain other | ||||
414 | * statements. | ||||
415 | */ | ||||
416 | } | ||||
417 | |||||
418 | virtual void visit(class ir_return * ir) | ||||
419 | { | ||||
420 | /* Eliminate all instructions after each one, since they are | ||||
421 | * unreachable. This satisfies the DEAD_CODE_ELIMINATION | ||||
422 | * postcondition. | ||||
423 | */ | ||||
424 | truncate_after_instruction(ir); | ||||
425 | |||||
426 | /* Set this->block.min_strength based on this instruction. This | ||||
427 | * satisfies the ANALYSIS postcondition. It is not necessary to | ||||
428 | * update this->block.may_clear_execute_flag or | ||||
429 | * this->loop.may_set_return_flag, because an unlowered return | ||||
430 | * instruction can't change any flags. | ||||
431 | */ | ||||
432 | this->block.min_strength = strength_return; | ||||
433 | |||||
434 | /* The CONTAINED_JUMPS_LOWERED postcondition is already | ||||
435 | * satisfied, because jump statements can't contain other | ||||
436 | * statements. | ||||
437 | */ | ||||
438 | } | ||||
439 | |||||
440 | virtual void visit(class ir_discard * ir) | ||||
441 | { | ||||
442 | /* Nothing needs to be done. The ANALYSIS and | ||||
443 | * DEAD_CODE_ELIMINATION postconditions are already satisfied, | ||||
444 | * because discard statements are ignored by this optimization | ||||
445 | * pass. The CONTAINED_JUMPS_LOWERED postcondition is already | ||||
446 | * satisfied, because discard statements can't contain other | ||||
447 | * statements. | ||||
448 | */ | ||||
449 | (void) ir; | ||||
450 | } | ||||
451 | |||||
452 | virtual void visit(class ir_precision_statement * ir) | ||||
453 | { | ||||
454 | /* Nothing needs to be done. */ | ||||
455 | } | ||||
456 | |||||
457 | virtual void visit(class ir_typedecl_statement * ir) | ||||
458 | { | ||||
459 | /* Nothing needs to be done. */ | ||||
460 | } | ||||
461 | |||||
462 | enum jump_strength get_jump_strength(ir_instruction* ir) | ||||
463 | { | ||||
464 | if(!ir
| ||||
465 | return strength_none; | ||||
466 | else if(ir->ir_type
| ||||
467 | if(((ir_loop_jump*)ir)->is_break()) | ||||
468 | return strength_break; | ||||
469 | else | ||||
470 | return strength_continue; | ||||
471 | } else if(ir->ir_type == ir_type_return) | ||||
472 | return strength_return; | ||||
473 | else | ||||
474 | return strength_none; | ||||
475 | } | ||||
476 | |||||
477 | bool should_lower_jump(ir_jump* ir) | ||||
478 | { | ||||
479 | unsigned strength = get_jump_strength(ir); | ||||
480 | bool lower; | ||||
481 | switch(strength) | ||||
482 | { | ||||
483 | case strength_none: | ||||
484 | lower = false; /* don't change this, code relies on it */ | ||||
485 | break; | ||||
486 | case strength_continue: | ||||
487 | lower = lower_continue; | ||||
488 | break; | ||||
489 | case strength_break: | ||||
490 | assert(this->loop.loop)(static_cast <bool> (this->loop.loop) ? void (0) : __assert_fail ("this->loop.loop", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
491 | /* never lower "canonical break" */ | ||||
492 | if(ir->get_next()->is_tail_sentinel() && (this->loop.nesting_depth == 0 | ||||
493 | || (this->loop.nesting_depth == 1 && this->loop.in_if_at_the_end_of_the_loop))) | ||||
494 | lower = false; | ||||
495 | else | ||||
496 | lower = lower_break; | ||||
497 | break; | ||||
498 | case strength_return: | ||||
499 | /* never lower return at the end of a this->function */ | ||||
500 | if(this->function.nesting_depth == 0 && ir->get_next()->is_tail_sentinel()) | ||||
501 | lower = false; | ||||
502 | else | ||||
503 | lower = this->function.lower_return; | ||||
504 | break; | ||||
505 | } | ||||
506 | return lower; | ||||
507 | } | ||||
508 | |||||
509 | block_record visit_block(exec_list* list) | ||||
510 | { | ||||
511 | /* Note: since visiting a node may change that node's next | ||||
512 | * pointer, we can't use visit_exec_list(), because | ||||
513 | * visit_exec_list() caches the node's next pointer before | ||||
514 | * visiting it. So we use foreach_in_list() instead. | ||||
515 | * | ||||
516 | * foreach_in_list() isn't safe if the node being visited gets | ||||
517 | * removed, but fortunately this visitor doesn't do that. | ||||
518 | */ | ||||
519 | |||||
520 | block_record saved_block = this->block; | ||||
521 | this->block = block_record(); | ||||
522 | foreach_in_list(ir_instruction, node, list)for (ir_instruction *node = (!exec_node_is_tail_sentinel((list )->head_sentinel.next) ? (ir_instruction *) ((list)->head_sentinel .next) : __null); (node) != __null; (node) = (!exec_node_is_tail_sentinel ((node)->next) ? (ir_instruction *) ((node)->next) : __null )) { | ||||
523 | node->accept(this); | ||||
524 | } | ||||
525 | block_record ret = this->block; | ||||
526 | this->block = saved_block; | ||||
527 | return ret; | ||||
528 | } | ||||
529 | |||||
530 | virtual void visit(ir_if *ir) | ||||
531 | { | ||||
532 | if(this->loop.nesting_depth == 0 && ir->get_next()->is_tail_sentinel()) | ||||
533 | this->loop.in_if_at_the_end_of_the_loop = true; | ||||
534 | |||||
535 | ++this->function.nesting_depth; | ||||
536 | ++this->loop.nesting_depth; | ||||
537 | |||||
538 | block_record block_records[2]; | ||||
539 | ir_jump* jumps[2]; | ||||
540 | |||||
541 | /* Recursively lower nested jumps. This satisfies the | ||||
542 | * CONTAINED_JUMPS_LOWERED postcondition, except in the case of | ||||
543 | * unconditional jumps at the end of ir->then_instructions and | ||||
544 | * ir->else_instructions, which are handled below. | ||||
545 | */ | ||||
546 | block_records[0] = visit_block(&ir->then_instructions); | ||||
547 | block_records[1] = visit_block(&ir->else_instructions); | ||||
548 | |||||
549 | retry: /* we get here if we put code after the if inside a branch */ | ||||
550 | |||||
551 | /* Determine which of ir->then_instructions and | ||||
552 | * ir->else_instructions end with an unconditional jump. | ||||
553 | */ | ||||
554 | for(unsigned i = 0; i < 2; ++i) { | ||||
555 | exec_list& list = i ? ir->else_instructions : ir->then_instructions; | ||||
556 | jumps[i] = 0; | ||||
557 | if(!list.is_empty() && get_jump_strength((ir_instruction*)list.get_tail())) | ||||
558 | jumps[i] = (ir_jump*)list.get_tail(); | ||||
559 | } | ||||
560 | |||||
561 | /* Loop until we have satisfied the CONTAINED_JUMPS_LOWERED | ||||
562 | * postcondition by lowering jumps in both then_instructions and | ||||
563 | * else_instructions. | ||||
564 | */ | ||||
565 | for(;;) { | ||||
566 | /* Determine the types of the jumps that terminate | ||||
567 | * ir->then_instructions and ir->else_instructions. | ||||
568 | */ | ||||
569 | jump_strength jump_strengths[2]; | ||||
570 | |||||
571 | for(unsigned i = 0; i < 2; ++i) { | ||||
572 | if(jumps[i]) { | ||||
573 | jump_strengths[i] = block_records[i].min_strength; | ||||
574 | assert(jump_strengths[i] == get_jump_strength(jumps[i]))(static_cast <bool> (jump_strengths[i] == get_jump_strength (jumps[i])) ? void (0) : __assert_fail ("jump_strengths[i] == get_jump_strength(jumps[i])" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | ||||
575 | } else | ||||
576 | jump_strengths[i] = strength_none; | ||||
577 | } | ||||
578 | |||||
579 | /* If both code paths end in a jump, and the jumps are the | ||||
580 | * same, and we are pulling out jumps, replace them with a | ||||
581 | * single jump that comes after the if instruction. The new | ||||
582 | * jump will be visited next, and it will be lowered if | ||||
583 | * necessary by the loop or conditional that encloses it. | ||||
584 | */ | ||||
585 | if(pull_out_jumps && jump_strengths[0] == jump_strengths[1]) { | ||||
586 | bool unify = true; | ||||
587 | if(jump_strengths[0] == strength_continue) | ||||
588 | ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_continue)); | ||||
589 | else if(jump_strengths[0] == strength_break) | ||||
590 | ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_break)); | ||||
591 | /* FINISHME: unify returns with identical expressions */ | ||||
592 | else if(jump_strengths[0] == strength_return && this->function.signature->return_type->is_void()) | ||||
593 | ir->insert_after(new(ir) ir_return(NULL__null)); | ||||
594 | else | ||||
595 | unify = false; | ||||
596 | |||||
597 | if(unify) { | ||||
598 | jumps[0]->remove(); | ||||
599 | jumps[1]->remove(); | ||||
600 | this->progress = true; | ||||
601 | |||||
602 | /* Update jumps[] to reflect the fact that the jumps | ||||
603 | * are gone, and update block_records[] to reflect the | ||||
604 | * fact that control can now flow to the next | ||||
605 | * instruction. | ||||
606 | */ | ||||
607 | jumps[0] = 0; | ||||
608 | jumps[1] = 0; | ||||
609 | block_records[0].min_strength = strength_none; | ||||
610 | block_records[1].min_strength = strength_none; | ||||
611 | |||||
612 | /* The CONTAINED_JUMPS_LOWERED postcondition is now | ||||
613 | * satisfied, so we can break out of the loop. | ||||
614 | */ | ||||
615 | break; | ||||
616 | } | ||||
617 | } | ||||
618 | |||||
619 | /* lower a jump: if both need to lowered, start with the strongest one, so that | ||||
620 | * we might later unify the lowered version with the other one | ||||
621 | */ | ||||
622 | bool should_lower[2]; | ||||
623 | for(unsigned i = 0; i < 2; ++i) | ||||
624 | should_lower[i] = should_lower_jump(jumps[i]); | ||||
625 | |||||
626 | int lower; | ||||
627 | if(should_lower[1] && should_lower[0]) | ||||
628 | lower = jump_strengths[1] > jump_strengths[0]; | ||||
629 | else if(should_lower[0]) | ||||
630 | lower = 0; | ||||
631 | else if(should_lower[1]) | ||||
632 | lower = 1; | ||||
633 | else | ||||
634 | /* Neither code path ends in a jump that needs to be | ||||
635 | * lowered, so the CONTAINED_JUMPS_LOWERED postcondition | ||||
636 | * is satisfied and we can break out of the loop. | ||||
637 | */ | ||||
638 | break; | ||||
639 | |||||
640 | if(jump_strengths[lower] == strength_return) { | ||||
641 | /* To lower a return, we create a return flag (if the | ||||
642 | * function doesn't have one already) and add instructions | ||||
643 | * that: 1. store the return value (if this function has a | ||||
644 | * non-void return) and 2. set the return flag | ||||
645 | */ | ||||
646 | insert_lowered_return((ir_return*)jumps[lower]); | ||||
647 | if(this->loop.loop) { | ||||
648 | /* If we are in a loop, replace the return instruction | ||||
649 | * with a break instruction, and then loop so that the | ||||
650 | * break instruction can be lowered if necessary. | ||||
651 | */ | ||||
652 | ir_loop_jump* lowered = 0; | ||||
653 | lowered = new(ir) ir_loop_jump(ir_loop_jump::jump_break); | ||||
654 | /* Note: we must update block_records and jumps to | ||||
655 | * reflect the fact that the control path has been | ||||
656 | * altered from a return to a break. | ||||
657 | */ | ||||
658 | block_records[lower].min_strength = strength_break; | ||||
659 | jumps[lower]->replace_with(lowered); | ||||
660 | jumps[lower] = lowered; | ||||
661 | } else { | ||||
662 | /* If we are not in a loop, we then proceed as we would | ||||
663 | * for a continue statement (set the execute flag to | ||||
664 | * false to prevent the rest of the function from | ||||
665 | * executing). | ||||
666 | */ | ||||
667 | goto lower_continue; | ||||
668 | } | ||||
669 | this->progress = true; | ||||
670 | } else if(jump_strengths[lower] == strength_break) { | ||||
671 | /* To lower a break, we create a break flag (if the loop | ||||
672 | * doesn't have one already) and add an instruction that | ||||
673 | * sets it. | ||||
674 | * | ||||
675 | * Then we proceed as we would for a continue statement | ||||
676 | * (set the execute flag to false to prevent the rest of | ||||
677 | * the loop body from executing). | ||||
678 | * | ||||
679 | * The visit() function for the loop will ensure that the | ||||
680 | * break flag is checked after executing the loop body. | ||||
681 | */ | ||||
682 | jumps[lower]->insert_before(create_lowered_break()); | ||||
683 | goto lower_continue; | ||||
684 | } else if(jump_strengths[lower] == strength_continue) { | ||||
685 | lower_continue: | ||||
686 | /* To lower a continue, we create an execute flag (if the | ||||
687 | * loop doesn't have one already) and replace the continue | ||||
688 | * with an instruction that clears it. | ||||
689 | * | ||||
690 | * Note that this code path gets exercised when lowering | ||||
691 | * return statements that are not inside a loop, so | ||||
692 | * this->loop must be initialized even outside of loops. | ||||
693 | */ | ||||
694 | ir_variable* execute_flag = this->loop.get_execute_flag(); | ||||
695 | jumps[lower]->replace_with(new(ir) ir_assignment(new (ir) ir_dereference_variable(execute_flag), new (ir) ir_constant(false))); | ||||
696 | /* Note: we must update block_records and jumps to reflect | ||||
697 | * the fact that the control path has been altered to an | ||||
698 | * instruction that clears the execute flag. | ||||
699 | */ | ||||
700 | jumps[lower] = 0; | ||||
701 | block_records[lower].min_strength = strength_always_clears_execute_flag; | ||||
702 | block_records[lower].may_clear_execute_flag = true; | ||||
703 | this->progress = true; | ||||
704 | |||||
705 | /* Let the loop run again, in case the other branch of the | ||||
706 | * if needs to be lowered too. | ||||
707 | */ | ||||
708 | } | ||||
709 | } | ||||
710 | |||||
711 | /* move out a jump out if possible */ | ||||
712 | if(pull_out_jumps) { | ||||
713 | /* If one of the branches ends in a jump, and control cannot | ||||
714 | * fall out the bottom of the other branch, then we can move | ||||
715 | * the jump after the if. | ||||
716 | * | ||||
717 | * Set move_out to the branch we are moving a jump out of. | ||||
718 | */ | ||||
719 | int move_out = -1; | ||||
720 | if(jumps[0] && block_records[1].min_strength >= strength_continue) | ||||
721 | move_out = 0; | ||||
722 | else if(jumps[1] && block_records[0].min_strength >= strength_continue) | ||||
723 | move_out = 1; | ||||
724 | |||||
725 | if(move_out >= 0) | ||||
726 | { | ||||
727 | jumps[move_out]->remove(); | ||||
728 | ir->insert_after(jumps[move_out]); | ||||
729 | /* Note: we must update block_records and jumps to reflect | ||||
730 | * the fact that the jump has been moved out of the if. | ||||
731 | */ | ||||
732 | jumps[move_out] = 0; | ||||
733 | block_records[move_out].min_strength = strength_none; | ||||
734 | this->progress = true; | ||||
735 | } | ||||
736 | } | ||||
737 | |||||
738 | /* Now satisfy the ANALYSIS postcondition by setting | ||||
739 | * this->block.min_strength and | ||||
740 | * this->block.may_clear_execute_flag based on the | ||||
741 | * characteristics of the two branches. | ||||
742 | */ | ||||
743 | if(block_records[0].min_strength < block_records[1].min_strength) | ||||
744 | this->block.min_strength = block_records[0].min_strength; | ||||
745 | else | ||||
746 | this->block.min_strength = block_records[1].min_strength; | ||||
747 | this->block.may_clear_execute_flag = this->block.may_clear_execute_flag || block_records[0].may_clear_execute_flag || block_records[1].may_clear_execute_flag; | ||||
748 | |||||
749 | /* Now we need to clean up the instructions that follow the | ||||
750 | * if. | ||||
751 | * | ||||
752 | * If those instructions are unreachable, then satisfy the | ||||
753 | * DEAD_CODE_ELIMINATION postcondition by eliminating them. | ||||
754 | * Otherwise that postcondition is already satisfied. | ||||
755 | */ | ||||
756 | if(this->block.min_strength) | ||||
757 | truncate_after_instruction(ir); | ||||
758 | else if(this->block.may_clear_execute_flag) | ||||
759 | { | ||||
760 | /* If the "if" instruction might clear the execute flag, then | ||||
761 | * we need to guard any instructions that follow so that they | ||||
762 | * are only executed if the execute flag is set. | ||||
763 | * | ||||
764 | * If one of the branches of the "if" always clears the | ||||
765 | * execute flag, and the other branch never clears it, then | ||||
766 | * this is easy: just move all the instructions following the | ||||
767 | * "if" into the branch that never clears it. | ||||
768 | */ | ||||
769 | int move_into = -1; | ||||
770 | if(block_records[0].min_strength && !block_records[1].may_clear_execute_flag) | ||||
771 | move_into = 1; | ||||
772 | else if(block_records[1].min_strength && !block_records[0].may_clear_execute_flag) | ||||
773 | move_into = 0; | ||||
774 | |||||
775 | if(move_into >= 0) { | ||||
776 | assert(!block_records[move_into].min_strength && !block_records[move_into].may_clear_execute_flag)(static_cast <bool> (!block_records[move_into].min_strength && !block_records[move_into].may_clear_execute_flag) ? void (0) : __assert_fail ("!block_records[move_into].min_strength && !block_records[move_into].may_clear_execute_flag" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); /* otherwise, we just truncated */ | ||||
777 | |||||
778 | exec_list* list = move_into ? &ir->else_instructions : &ir->then_instructions; | ||||
779 | exec_node* next = ir->get_next(); | ||||
780 | if(!next->is_tail_sentinel()) { | ||||
781 | move_outer_block_inside(ir, list); | ||||
782 | |||||
783 | /* If any instructions moved, then we need to visit | ||||
784 | * them (since they are now inside the "if"). Since | ||||
785 | * block_records[move_into] is in its default state | ||||
786 | * (see assertion above), we can safely replace | ||||
787 | * block_records[move_into] with the result of this | ||||
788 | * analysis. | ||||
789 | */ | ||||
790 | exec_list list; | ||||
791 | list.head_sentinel.next = next; | ||||
792 | block_records[move_into] = visit_block(&list); | ||||
793 | |||||
794 | /* | ||||
795 | * Then we need to re-start our jump lowering, since one | ||||
796 | * of the instructions we moved might be a jump that | ||||
797 | * needs to be lowered. | ||||
798 | */ | ||||
799 | this->progress = true; | ||||
800 | goto retry; | ||||
801 | } | ||||
802 | } else { | ||||
803 | /* If we get here, then the simple case didn't apply; we | ||||
804 | * need to actually guard the instructions that follow. | ||||
805 | * | ||||
806 | * To avoid creating unnecessarily-deep nesting, first | ||||
807 | * look through the instructions that follow and unwrap | ||||
808 | * any instructions that that are already wrapped in the | ||||
809 | * appropriate guard. | ||||
810 | */ | ||||
811 | ir_instruction* ir_after; | ||||
812 | for(ir_after = (ir_instruction*)ir->get_next(); !ir_after->is_tail_sentinel();) | ||||
813 | { | ||||
814 | ir_if* ir_if = ir_after->as_if(); | ||||
815 | if(ir_if && ir_if->else_instructions.is_empty()) { | ||||
816 | ir_dereference_variable* ir_if_cond_deref = ir_if->condition->as_dereference_variable(); | ||||
817 | if(ir_if_cond_deref && ir_if_cond_deref->var == this->loop.execute_flag) { | ||||
818 | ir_instruction* ir_next = (ir_instruction*)ir_after->get_next(); | ||||
819 | ir_after->insert_before(&ir_if->then_instructions); | ||||
820 | ir_after->remove(); | ||||
821 | ir_after = ir_next; | ||||
822 | continue; | ||||
823 | } | ||||
824 | } | ||||
825 | ir_after = (ir_instruction*)ir_after->get_next(); | ||||
826 | |||||
827 | /* only set this if we find any unprotected instruction */ | ||||
828 | this->progress = true; | ||||
829 | } | ||||
830 | |||||
831 | /* Then, wrap all the instructions that follow in a single | ||||
832 | * guard. | ||||
833 | */ | ||||
834 | if(!ir->get_next()->is_tail_sentinel()) { | ||||
835 | assert(this->loop.execute_flag)(static_cast <bool> (this->loop.execute_flag) ? void (0) : __assert_fail ("this->loop.execute_flag", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
836 | ir_if* if_execute = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.execute_flag)); | ||||
837 | move_outer_block_inside(ir, &if_execute->then_instructions); | ||||
838 | ir->insert_after(if_execute); | ||||
839 | } | ||||
840 | } | ||||
841 | } | ||||
842 | --this->loop.nesting_depth; | ||||
843 | --this->function.nesting_depth; | ||||
844 | } | ||||
845 | |||||
846 | virtual void visit(ir_loop *ir) | ||||
847 | { | ||||
848 | /* Visit the body of the loop, with a fresh data structure in | ||||
849 | * this->loop so that the analysis we do here won't bleed into | ||||
850 | * enclosing loops. | ||||
851 | * | ||||
852 | * We assume that all code after a loop is reachable from the | ||||
853 | * loop (see comments on enum jump_strength), so the | ||||
854 | * DEAD_CODE_ELIMINATION postcondition is automatically | ||||
855 | * satisfied, as is the block.min_strength portion of the | ||||
856 | * ANALYSIS postcondition. | ||||
857 | * | ||||
858 | * The block.may_clear_execute_flag portion of the ANALYSIS | ||||
859 | * postcondition is automatically satisfied because execute | ||||
860 | * flags do not propagate outside of loops. | ||||
861 | * | ||||
862 | * The loop.may_set_return_flag portion of the ANALYSIS | ||||
863 | * postcondition is handled below. | ||||
864 | */ | ||||
865 | ++this->function.nesting_depth; | ||||
866 | loop_record saved_loop = this->loop; | ||||
867 | this->loop = loop_record(this->function.signature, ir); | ||||
868 | |||||
869 | /* Recursively lower nested jumps. This satisfies the | ||||
870 | * CONTAINED_JUMPS_LOWERED postcondition, except in the case of | ||||
871 | * an unconditional continue or return at the bottom of the | ||||
872 | * loop, which are handled below. | ||||
873 | */ | ||||
874 | block_record body = visit_block(&ir->body_instructions); | ||||
875 | |||||
876 | /* If the loop ends in an unconditional continue, eliminate it | ||||
877 | * because it is redundant. | ||||
878 | */ | ||||
879 | ir_instruction *ir_last | ||||
880 | = (ir_instruction *) ir->body_instructions.get_tail(); | ||||
881 | if (get_jump_strength(ir_last) == strength_continue) { | ||||
| |||||
882 | ir_last->remove(); | ||||
883 | } | ||||
884 | |||||
885 | /* If the loop ends in an unconditional return, and we are | ||||
886 | * lowering returns, lower it. | ||||
887 | */ | ||||
888 | if (this->function.lower_return) | ||||
889 | lower_return_unconditionally(ir_last); | ||||
890 | |||||
891 | if(body.min_strength >= strength_break) { | ||||
892 | /* FINISHME: If the min_strength of the loop body is | ||||
893 | * strength_break or strength_return, that means that it | ||||
894 | * isn't a loop at all, since control flow always leaves the | ||||
895 | * body of the loop via break or return. In principle the | ||||
896 | * loop could be eliminated in this case. This optimization | ||||
897 | * is not implemented yet. | ||||
898 | */ | ||||
899 | } | ||||
900 | |||||
901 | if(this->loop.break_flag) { | ||||
902 | /* We only get here if we are lowering breaks */ | ||||
903 | assert (lower_break)(static_cast <bool> (lower_break) ? void (0) : __assert_fail ("lower_break", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
904 | |||||
905 | /* If a break flag was generated while visiting the body of | ||||
906 | * the loop, then at least one break was lowered, so we need | ||||
907 | * to generate an if statement at the end of the loop that | ||||
908 | * does a "break" if the break flag is set. The break we | ||||
909 | * generate won't violate the CONTAINED_JUMPS_LOWERED | ||||
910 | * postcondition, because should_lower_jump() always returns | ||||
911 | * false for a break that happens at the end of a loop. | ||||
912 | * | ||||
913 | * However, if the loop already ends in a conditional or | ||||
914 | * unconditional break, then we need to lower that break, | ||||
915 | * because it won't be at the end of the loop anymore. | ||||
916 | */ | ||||
917 | lower_final_breaks(&ir->body_instructions); | ||||
918 | |||||
919 | ir_if* break_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.break_flag)); | ||||
920 | break_if->then_instructions.push_tail(new(ir) ir_loop_jump(ir_loop_jump::jump_break)); | ||||
921 | ir->body_instructions.push_tail(break_if); | ||||
922 | } | ||||
923 | |||||
924 | /* If the body of the loop may set the return flag, then at | ||||
925 | * least one return was lowered to a break, so we need to ensure | ||||
926 | * that the return flag is checked after the body of the loop is | ||||
927 | * executed. | ||||
928 | */ | ||||
929 | if(this->loop.may_set_return_flag) { | ||||
930 | assert(this->function.return_flag)(static_cast <bool> (this->function.return_flag) ? void (0) : __assert_fail ("this->function.return_flag", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
931 | /* Generate the if statement to check the return flag */ | ||||
932 | ir_if* return_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->function.return_flag)); | ||||
933 | /* Note: we also need to propagate the knowledge that the | ||||
934 | * return flag may get set to the outer context. This | ||||
935 | * satisfies the loop.may_set_return_flag part of the | ||||
936 | * ANALYSIS postcondition. | ||||
937 | */ | ||||
938 | saved_loop.may_set_return_flag = true; | ||||
939 | if(saved_loop.loop) | ||||
940 | /* If this loop is nested inside another one, then the if | ||||
941 | * statement that we generated should break out of that | ||||
942 | * loop if the return flag is set. Caller will lower that | ||||
943 | * break statement if necessary. | ||||
944 | */ | ||||
945 | return_if->then_instructions.push_tail(new(ir) ir_loop_jump(ir_loop_jump::jump_break)); | ||||
946 | else { | ||||
947 | /* Otherwise, ensure that the instructions that follow are only | ||||
948 | * executed if the return flag is clear. We can do that by moving | ||||
949 | * those instructions into the else clause of the generated if | ||||
950 | * statement. | ||||
951 | */ | ||||
952 | move_outer_block_inside(ir, &return_if->else_instructions); | ||||
953 | |||||
954 | /* In case the loop is embedded inside an if add a new return to | ||||
955 | * the return flag then branch and let a future pass tidy it up. | ||||
956 | */ | ||||
957 | if (this->function.signature->return_type->is_void()) | ||||
958 | return_if->then_instructions.push_tail(new(ir) ir_return(NULL__null)); | ||||
959 | else { | ||||
960 | assert(this->function.return_value)(static_cast <bool> (this->function.return_value) ? void (0) : __assert_fail ("this->function.return_value", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
961 | ir_variable* return_value = this->function.return_value; | ||||
962 | return_if->then_instructions.push_tail( | ||||
963 | new(ir) ir_return(new(ir) ir_dereference_variable(return_value))); | ||||
964 | } | ||||
965 | } | ||||
966 | |||||
967 | ir->insert_after(return_if); | ||||
968 | } | ||||
969 | |||||
970 | this->loop = saved_loop; | ||||
971 | --this->function.nesting_depth; | ||||
972 | } | ||||
973 | |||||
974 | virtual void visit(ir_function_signature *ir) | ||||
975 | { | ||||
976 | /* these are not strictly necessary */ | ||||
977 | assert(!this->function.signature)(static_cast <bool> (!this->function.signature) ? void (0) : __assert_fail ("!this->function.signature", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | ||||
978 | assert(!this->loop.loop)(static_cast <bool> (!this->loop.loop) ? void (0) : __assert_fail ("!this->loop.loop", __builtin_FILE (), __builtin_LINE () , __extension__ __PRETTY_FUNCTION__)); | ||||
979 | |||||
980 | bool lower_return; | ||||
981 | if (strcmp(ir->function_name(), "main") == 0) | ||||
982 | lower_return = lower_main_return; | ||||
983 | else | ||||
984 | lower_return = lower_sub_return; | ||||
985 | |||||
986 | function_record saved_function = this->function; | ||||
987 | loop_record saved_loop = this->loop; | ||||
988 | this->function = function_record(ir, lower_return); | ||||
989 | this->loop = loop_record(ir); | ||||
990 | |||||
991 | assert(!this->loop.loop)(static_cast <bool> (!this->loop.loop) ? void (0) : __assert_fail ("!this->loop.loop", __builtin_FILE (), __builtin_LINE () , __extension__ __PRETTY_FUNCTION__)); | ||||
992 | |||||
993 | /* Visit the body of the function to lower any jumps that occur | ||||
994 | * in it, except possibly an unconditional return statement at | ||||
995 | * the end of it. | ||||
996 | */ | ||||
997 | visit_block(&ir->body); | ||||
998 | |||||
999 | /* If the body ended in an unconditional return of non-void, | ||||
1000 | * then we don't need to lower it because it's the one canonical | ||||
1001 | * return. | ||||
1002 | * | ||||
1003 | * If the body ended in a return of void, eliminate it because | ||||
1004 | * it is redundant. | ||||
1005 | */ | ||||
1006 | if (ir->return_type->is_void() && | ||||
1007 | get_jump_strength((ir_instruction *) ir->body.get_tail())) { | ||||
1008 | ir_jump *jump = (ir_jump *) ir->body.get_tail(); | ||||
1009 | assert (jump->ir_type == ir_type_return)(static_cast <bool> (jump->ir_type == ir_type_return ) ? void (0) : __assert_fail ("jump->ir_type == ir_type_return" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | ||||
1010 | jump->remove(); | ||||
1011 | } | ||||
1012 | |||||
1013 | if(this->function.return_value) | ||||
1014 | ir->body.push_tail(new(ir) ir_return(new (ir) ir_dereference_variable(this->function.return_value))); | ||||
1015 | |||||
1016 | this->loop = saved_loop; | ||||
1017 | this->function = saved_function; | ||||
1018 | } | ||||
1019 | |||||
1020 | virtual void visit(class ir_function * ir) | ||||
1021 | { | ||||
1022 | visit_block(&ir->signatures); | ||||
1023 | } | ||||
1024 | }; | ||||
1025 | |||||
1026 | } /* anonymous namespace */ | ||||
1027 | |||||
1028 | bool | ||||
1029 | do_lower_jumps(exec_list *instructions, bool pull_out_jumps, bool lower_sub_return, bool lower_main_return, bool lower_continue, bool lower_break) | ||||
1030 | { | ||||
1031 | ir_lower_jumps_visitor v; | ||||
1032 | v.pull_out_jumps = pull_out_jumps; | ||||
1033 | v.lower_continue = lower_continue; | ||||
1034 | v.lower_break = lower_break; | ||||
1035 | v.lower_sub_return = lower_sub_return; | ||||
1036 | v.lower_main_return = lower_main_return; | ||||
1037 | |||||
1038 | bool progress_ever = false; | ||||
1039 | do { | ||||
1040 | v.progress = false; | ||||
1041 | visit_exec_list(instructions, &v); | ||||
1042 | progress_ever = v.progress || progress_ever; | ||||
1043 | } while (v.progress); | ||||
1044 | |||||
1045 | return progress_ever; | ||||
1046 | } |
1 | /* | |||
2 | * Copyright © 2008, 2010 Intel Corporation | |||
3 | * | |||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
5 | * copy of this software and associated documentation files (the "Software"), | |||
6 | * to deal in the Software without restriction, including without limitation | |||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
8 | * and/or sell copies of the Software, and to permit persons to whom the | |||
9 | * Software is furnished to do so, subject to the following conditions: | |||
10 | * | |||
11 | * The above copyright notice and this permission notice (including the next | |||
12 | * paragraph) shall be included in all copies or substantial portions of the | |||
13 | * Software. | |||
14 | * | |||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
21 | * DEALINGS IN THE SOFTWARE. | |||
22 | */ | |||
23 | ||||
24 | /** | |||
25 | * \file list.h | |||
26 | * \brief Doubly-linked list abstract container type. | |||
27 | * | |||
28 | * Each doubly-linked list has a sentinel head and tail node. These nodes | |||
29 | * contain no data. The head sentinel can be identified by its \c prev | |||
30 | * pointer being \c NULL. The tail sentinel can be identified by its | |||
31 | * \c next pointer being \c NULL. | |||
32 | * | |||
33 | * A list is empty if either the head sentinel's \c next pointer points to the | |||
34 | * tail sentinel or the tail sentinel's \c prev poiner points to the head | |||
35 | * sentinel. The head sentinel and tail sentinel nodes are allocated within the | |||
36 | * list structure. | |||
37 | * | |||
38 | * Do note that this means that the list nodes will contain pointers into the | |||
39 | * list structure itself and as a result you may not \c realloc() an \c | |||
40 | * exec_list or any structure in which an \c exec_list is embedded. | |||
41 | */ | |||
42 | ||||
43 | #ifndef LIST_CONTAINER_H | |||
44 | #define LIST_CONTAINER_H | |||
45 | ||||
46 | #ifndef __cplusplus201703L | |||
47 | #include <stddef.h> | |||
48 | #endif | |||
49 | #include <assert.h> | |||
50 | ||||
51 | #include "util/ralloc.h" | |||
52 | ||||
53 | struct exec_node { | |||
54 | struct exec_node *next; | |||
55 | struct exec_node *prev; | |||
56 | ||||
57 | #ifdef __cplusplus201703L | |||
58 | DECLARE_RZALLOC_CXX_OPERATORS(exec_node)private: static void _ralloc_destructor(void *p) { reinterpret_cast <exec_node *>(p)->exec_node::~exec_node(); } public: static void* operator new(size_t size, void *mem_ctx) { void *p = rzalloc_size(mem_ctx, size); (static_cast <bool> ( p != __null) ? void (0) : __assert_fail ("p != NULL", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); if (!__has_trivial_destructor(exec_node)) ralloc_set_destructor (p, _ralloc_destructor); return p; } static void operator delete (void *p) { if (!__has_trivial_destructor(exec_node)) ralloc_set_destructor (p, __null); ralloc_free(p); } | |||
59 | ||||
60 | exec_node() : next(NULL__null), prev(NULL__null) | |||
61 | { | |||
62 | /* empty */ | |||
63 | } | |||
64 | ||||
65 | const exec_node *get_next() const; | |||
66 | exec_node *get_next(); | |||
67 | ||||
68 | const exec_node *get_prev() const; | |||
69 | exec_node *get_prev(); | |||
70 | ||||
71 | void remove(); | |||
72 | ||||
73 | /** | |||
74 | * Link a node with itself | |||
75 | * | |||
76 | * This creates a sort of degenerate list that is occasionally useful. | |||
77 | */ | |||
78 | void self_link(); | |||
79 | ||||
80 | /** | |||
81 | * Insert a node in the list after the current node | |||
82 | */ | |||
83 | void insert_after(exec_node *after); | |||
84 | ||||
85 | /** | |||
86 | * Insert another list in the list after the current node | |||
87 | */ | |||
88 | void insert_after(struct exec_list *after); | |||
89 | ||||
90 | /** | |||
91 | * Insert a node in the list before the current node | |||
92 | */ | |||
93 | void insert_before(exec_node *before); | |||
94 | ||||
95 | /** | |||
96 | * Insert another list in the list before the current node | |||
97 | */ | |||
98 | void insert_before(struct exec_list *before); | |||
99 | ||||
100 | /** | |||
101 | * Replace the current node with the given node. | |||
102 | */ | |||
103 | void replace_with(exec_node *replacement); | |||
104 | ||||
105 | /** | |||
106 | * Is this the sentinel at the tail of the list? | |||
107 | */ | |||
108 | bool is_tail_sentinel() const; | |||
109 | ||||
110 | /** | |||
111 | * Is this the sentinel at the head of the list? | |||
112 | */ | |||
113 | bool is_head_sentinel() const; | |||
114 | #endif | |||
115 | }; | |||
116 | ||||
117 | static inline void | |||
118 | exec_node_init(struct exec_node *n) | |||
119 | { | |||
120 | n->next = NULL__null; | |||
121 | n->prev = NULL__null; | |||
122 | } | |||
123 | ||||
124 | static inline const struct exec_node * | |||
125 | exec_node_get_next_const(const struct exec_node *n) | |||
126 | { | |||
127 | return n->next; | |||
128 | } | |||
129 | ||||
130 | static inline struct exec_node * | |||
131 | exec_node_get_next(struct exec_node *n) | |||
132 | { | |||
133 | return n->next; | |||
134 | } | |||
135 | ||||
136 | static inline const struct exec_node * | |||
137 | exec_node_get_prev_const(const struct exec_node *n) | |||
138 | { | |||
139 | return n->prev; | |||
140 | } | |||
141 | ||||
142 | static inline struct exec_node * | |||
143 | exec_node_get_prev(struct exec_node *n) | |||
144 | { | |||
145 | return n->prev; | |||
146 | } | |||
147 | ||||
148 | static inline void | |||
149 | exec_node_remove(struct exec_node *n) | |||
150 | { | |||
151 | n->next->prev = n->prev; | |||
152 | n->prev->next = n->next; | |||
153 | n->next = NULL__null; | |||
154 | n->prev = NULL__null; | |||
155 | } | |||
156 | ||||
157 | static inline void | |||
158 | exec_node_self_link(struct exec_node *n) | |||
159 | { | |||
160 | n->next = n; | |||
161 | n->prev = n; | |||
162 | } | |||
163 | ||||
164 | static inline void | |||
165 | exec_node_insert_after(struct exec_node *n, struct exec_node *after) | |||
166 | { | |||
167 | after->next = n->next; | |||
168 | after->prev = n; | |||
169 | ||||
170 | n->next->prev = after; | |||
171 | n->next = after; | |||
172 | } | |||
173 | ||||
174 | static inline void | |||
175 | exec_node_insert_node_before(struct exec_node *n, struct exec_node *before) | |||
176 | { | |||
177 | before->next = n; | |||
178 | before->prev = n->prev; | |||
179 | ||||
180 | n->prev->next = before; | |||
181 | n->prev = before; | |||
182 | } | |||
183 | ||||
184 | static inline void | |||
185 | exec_node_replace_with(struct exec_node *n, struct exec_node *replacement) | |||
186 | { | |||
187 | replacement->prev = n->prev; | |||
188 | replacement->next = n->next; | |||
189 | ||||
190 | n->prev->next = replacement; | |||
| ||||
191 | n->next->prev = replacement; | |||
192 | } | |||
193 | ||||
194 | static inline bool | |||
195 | exec_node_is_tail_sentinel(const struct exec_node *n) | |||
196 | { | |||
197 | return n->next == NULL__null; | |||
198 | } | |||
199 | ||||
200 | static inline bool | |||
201 | exec_node_is_head_sentinel(const struct exec_node *n) | |||
202 | { | |||
203 | return n->prev == NULL__null; | |||
204 | } | |||
205 | ||||
206 | #ifdef __cplusplus201703L | |||
207 | inline const exec_node *exec_node::get_next() const | |||
208 | { | |||
209 | return exec_node_get_next_const(this); | |||
210 | } | |||
211 | ||||
212 | inline exec_node *exec_node::get_next() | |||
213 | { | |||
214 | return exec_node_get_next(this); | |||
215 | } | |||
216 | ||||
217 | inline const exec_node *exec_node::get_prev() const | |||
218 | { | |||
219 | return exec_node_get_prev_const(this); | |||
220 | } | |||
221 | ||||
222 | inline exec_node *exec_node::get_prev() | |||
223 | { | |||
224 | return exec_node_get_prev(this); | |||
225 | } | |||
226 | ||||
227 | inline void exec_node::remove() | |||
228 | { | |||
229 | exec_node_remove(this); | |||
230 | } | |||
231 | ||||
232 | inline void exec_node::self_link() | |||
233 | { | |||
234 | exec_node_self_link(this); | |||
235 | } | |||
236 | ||||
237 | inline void exec_node::insert_after(exec_node *after) | |||
238 | { | |||
239 | exec_node_insert_after(this, after); | |||
240 | } | |||
241 | ||||
242 | inline void exec_node::insert_before(exec_node *before) | |||
243 | { | |||
244 | exec_node_insert_node_before(this, before); | |||
245 | } | |||
246 | ||||
247 | inline void exec_node::replace_with(exec_node *replacement) | |||
248 | { | |||
249 | exec_node_replace_with(this, replacement); | |||
250 | } | |||
251 | ||||
252 | inline bool exec_node::is_tail_sentinel() const | |||
253 | { | |||
254 | return exec_node_is_tail_sentinel(this); | |||
255 | } | |||
256 | ||||
257 | inline bool exec_node::is_head_sentinel() const | |||
258 | { | |||
259 | return exec_node_is_head_sentinel(this); | |||
260 | } | |||
261 | #endif | |||
262 | ||||
263 | #ifdef __cplusplus201703L | |||
264 | /* This macro will not work correctly if `t' uses virtual inheritance. If you | |||
265 | * are using virtual inheritance, you deserve a slow and painful death. Enjoy! | |||
266 | */ | |||
267 | #define exec_list_offsetof(t, f, p)(((char *) &((t *) p)->f) - ((char *) p)) \ | |||
268 | (((char *) &((t *) p)->f) - ((char *) p)) | |||
269 | #else | |||
270 | #define exec_list_offsetof(t, f, p)(((char *) &((t *) p)->f) - ((char *) p)) offsetof(t, f)__builtin_offsetof(t, f) | |||
271 | #endif | |||
272 | ||||
273 | /** | |||
274 | * Get a pointer to the structure containing an exec_node | |||
275 | * | |||
276 | * Given a pointer to an \c exec_node embedded in a structure, get a pointer to | |||
277 | * the containing structure. | |||
278 | * | |||
279 | * \param type Base type of the structure containing the node | |||
280 | * \param node Pointer to the \c exec_node | |||
281 | * \param field Name of the field in \c type that is the embedded \c exec_node | |||
282 | */ | |||
283 | #define exec_node_data(type, node, field)((type *) (((uintptr_t) node) - (((char *) &((type *) node )->field) - ((char *) node)))) \ | |||
284 | ((type *) (((uintptr_t) node) - exec_list_offsetof(type, field, node)(((char *) &((type *) node)->field) - ((char *) node)))) | |||
285 | ||||
286 | #ifdef __cplusplus201703L | |||
287 | struct exec_node; | |||
288 | #endif | |||
289 | ||||
290 | struct exec_list { | |||
291 | struct exec_node head_sentinel; | |||
292 | struct exec_node tail_sentinel; | |||
293 | ||||
294 | #ifdef __cplusplus201703L | |||
295 | DECLARE_RALLOC_CXX_OPERATORS(exec_list)private: static void _ralloc_destructor(void *p) { reinterpret_cast <exec_list *>(p)->exec_list::~exec_list(); } public: static void* operator new(size_t size, void *mem_ctx) { void *p = ralloc_size(mem_ctx, size); (static_cast <bool> ( p != __null) ? void (0) : __assert_fail ("p != NULL", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); if (!__has_trivial_destructor(exec_list)) ralloc_set_destructor (p, _ralloc_destructor); return p; } static void operator delete (void *p) { if (!__has_trivial_destructor(exec_list)) ralloc_set_destructor (p, __null); ralloc_free(p); } | |||
296 | ||||
297 | exec_list() | |||
298 | { | |||
299 | make_empty(); | |||
300 | } | |||
301 | ||||
302 | void make_empty(); | |||
303 | ||||
304 | bool is_empty() const; | |||
305 | ||||
306 | const exec_node *get_head() const; | |||
307 | exec_node *get_head(); | |||
308 | const exec_node *get_head_raw() const; | |||
309 | exec_node *get_head_raw(); | |||
310 | ||||
311 | const exec_node *get_tail() const; | |||
312 | exec_node *get_tail(); | |||
313 | const exec_node *get_tail_raw() const; | |||
314 | exec_node *get_tail_raw(); | |||
315 | ||||
316 | unsigned length() const; | |||
317 | ||||
318 | void push_head(exec_node *n); | |||
319 | void push_tail(exec_node *n); | |||
320 | void push_degenerate_list_at_head(exec_node *n); | |||
321 | ||||
322 | /** | |||
323 | * Remove the first node from a list and return it | |||
324 | * | |||
325 | * \return | |||
326 | * The first node in the list or \c NULL if the list is empty. | |||
327 | * | |||
328 | * \sa exec_list::get_head | |||
329 | */ | |||
330 | exec_node *pop_head(); | |||
331 | ||||
332 | /** | |||
333 | * Move all of the nodes from this list to the target list | |||
334 | */ | |||
335 | void move_nodes_to(exec_list *target); | |||
336 | ||||
337 | /** | |||
338 | * Append all nodes from the source list to the end of the target list | |||
339 | */ | |||
340 | void append_list(exec_list *source); | |||
341 | ||||
342 | /** | |||
343 | * Prepend all nodes from the source list to the beginning of the target | |||
344 | * list | |||
345 | */ | |||
346 | void prepend_list(exec_list *source); | |||
347 | #endif | |||
348 | }; | |||
349 | ||||
350 | static inline void | |||
351 | exec_list_make_empty(struct exec_list *list) | |||
352 | { | |||
353 | list->head_sentinel.next = &list->tail_sentinel; | |||
354 | list->head_sentinel.prev = NULL__null; | |||
355 | list->tail_sentinel.next = NULL__null; | |||
356 | list->tail_sentinel.prev = &list->head_sentinel; | |||
357 | } | |||
358 | ||||
359 | static inline bool | |||
360 | exec_list_is_empty(const struct exec_list *list) | |||
361 | { | |||
362 | /* There are three ways to test whether a list is empty or not. | |||
363 | * | |||
364 | * - Check to see if the head sentinel's \c next is the tail sentinel. | |||
365 | * - Check to see if the tail sentinel's \c prev is the head sentinel. | |||
366 | * - Check to see if the head is the sentinel node by test whether its | |||
367 | * \c next pointer is \c NULL. | |||
368 | * | |||
369 | * The first two methods tend to generate better code on modern systems | |||
370 | * because they save a pointer dereference. | |||
371 | */ | |||
372 | return list->head_sentinel.next == &list->tail_sentinel; | |||
373 | } | |||
374 | ||||
375 | static inline bool | |||
376 | exec_list_is_singular(const struct exec_list *list) | |||
377 | { | |||
378 | return !exec_list_is_empty(list) && | |||
379 | list->head_sentinel.next->next == &list->tail_sentinel; | |||
380 | } | |||
381 | ||||
382 | static inline const struct exec_node * | |||
383 | exec_list_get_head_const(const struct exec_list *list) | |||
384 | { | |||
385 | return !exec_list_is_empty(list) ? list->head_sentinel.next : NULL__null; | |||
386 | } | |||
387 | ||||
388 | static inline struct exec_node * | |||
389 | exec_list_get_head(struct exec_list *list) | |||
390 | { | |||
391 | return !exec_list_is_empty(list) ? list->head_sentinel.next : NULL__null; | |||
392 | } | |||
393 | ||||
394 | static inline const struct exec_node * | |||
395 | exec_list_get_head_raw_const(const struct exec_list *list) | |||
396 | { | |||
397 | return list->head_sentinel.next; | |||
398 | } | |||
399 | ||||
400 | static inline struct exec_node * | |||
401 | exec_list_get_head_raw(struct exec_list *list) | |||
402 | { | |||
403 | return list->head_sentinel.next; | |||
404 | } | |||
405 | ||||
406 | static inline const struct exec_node * | |||
407 | exec_list_get_tail_const(const struct exec_list *list) | |||
408 | { | |||
409 | return !exec_list_is_empty(list) ? list->tail_sentinel.prev : NULL__null; | |||
410 | } | |||
411 | ||||
412 | static inline struct exec_node * | |||
413 | exec_list_get_tail(struct exec_list *list) | |||
414 | { | |||
415 | return !exec_list_is_empty(list) ? list->tail_sentinel.prev : NULL__null; | |||
416 | } | |||
417 | ||||
418 | static inline const struct exec_node * | |||
419 | exec_list_get_tail_raw_const(const struct exec_list *list) | |||
420 | { | |||
421 | return list->tail_sentinel.prev; | |||
422 | } | |||
423 | ||||
424 | static inline struct exec_node * | |||
425 | exec_list_get_tail_raw(struct exec_list *list) | |||
426 | { | |||
427 | return list->tail_sentinel.prev; | |||
428 | } | |||
429 | ||||
430 | static inline unsigned | |||
431 | exec_list_length(const struct exec_list *list) | |||
432 | { | |||
433 | unsigned size = 0; | |||
434 | struct exec_node *node; | |||
435 | ||||
436 | for (node = list->head_sentinel.next; node->next != NULL__null; node = node->next) { | |||
437 | size++; | |||
438 | } | |||
439 | ||||
440 | return size; | |||
441 | } | |||
442 | ||||
443 | static inline void | |||
444 | exec_list_push_head(struct exec_list *list, struct exec_node *n) | |||
445 | { | |||
446 | n->next = list->head_sentinel.next; | |||
447 | n->prev = &list->head_sentinel; | |||
448 | ||||
449 | n->next->prev = n; | |||
450 | list->head_sentinel.next = n; | |||
451 | } | |||
452 | ||||
453 | static inline void | |||
454 | exec_list_push_tail(struct exec_list *list, struct exec_node *n) | |||
455 | { | |||
456 | n->next = &list->tail_sentinel; | |||
457 | n->prev = list->tail_sentinel.prev; | |||
458 | ||||
459 | n->prev->next = n; | |||
460 | list->tail_sentinel.prev = n; | |||
461 | } | |||
462 | ||||
463 | static inline void | |||
464 | exec_list_push_degenerate_list_at_head(struct exec_list *list, struct exec_node *n) | |||
465 | { | |||
466 | assert(n->prev->next == n)(static_cast <bool> (n->prev->next == n) ? void ( 0) : __assert_fail ("n->prev->next == n", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
467 | ||||
468 | n->prev->next = list->head_sentinel.next; | |||
469 | list->head_sentinel.next->prev = n->prev; | |||
470 | n->prev = &list->head_sentinel; | |||
471 | list->head_sentinel.next = n; | |||
472 | } | |||
473 | ||||
474 | static inline struct exec_node * | |||
475 | exec_list_pop_head(struct exec_list *list) | |||
476 | { | |||
477 | struct exec_node *const n = exec_list_get_head(list); | |||
478 | if (n != NULL__null) | |||
479 | exec_node_remove(n); | |||
480 | ||||
481 | return n; | |||
482 | } | |||
483 | ||||
484 | static inline void | |||
485 | exec_list_move_nodes_to(struct exec_list *list, struct exec_list *target) | |||
486 | { | |||
487 | if (exec_list_is_empty(list)) { | |||
488 | exec_list_make_empty(target); | |||
489 | } else { | |||
490 | target->head_sentinel.next = list->head_sentinel.next; | |||
491 | target->head_sentinel.prev = NULL__null; | |||
492 | target->tail_sentinel.next = NULL__null; | |||
493 | target->tail_sentinel.prev = list->tail_sentinel.prev; | |||
494 | ||||
495 | target->head_sentinel.next->prev = &target->head_sentinel; | |||
496 | target->tail_sentinel.prev->next = &target->tail_sentinel; | |||
497 | ||||
498 | exec_list_make_empty(list); | |||
499 | } | |||
500 | } | |||
501 | ||||
502 | static inline void | |||
503 | exec_list_append(struct exec_list *list, struct exec_list *source) | |||
504 | { | |||
505 | if (exec_list_is_empty(source)) | |||
506 | return; | |||
507 | ||||
508 | /* Link the first node of the source with the last node of the target list. | |||
509 | */ | |||
510 | list->tail_sentinel.prev->next = source->head_sentinel.next; | |||
511 | source->head_sentinel.next->prev = list->tail_sentinel.prev; | |||
512 | ||||
513 | /* Make the tail of the source list be the tail of the target list. | |||
514 | */ | |||
515 | list->tail_sentinel.prev = source->tail_sentinel.prev; | |||
516 | list->tail_sentinel.prev->next = &list->tail_sentinel; | |||
517 | ||||
518 | /* Make the source list empty for good measure. | |||
519 | */ | |||
520 | exec_list_make_empty(source); | |||
521 | } | |||
522 | ||||
523 | static inline void | |||
524 | exec_node_insert_list_after(struct exec_node *n, struct exec_list *after) | |||
525 | { | |||
526 | if (exec_list_is_empty(after)) | |||
527 | return; | |||
528 | ||||
529 | after->tail_sentinel.prev->next = n->next; | |||
530 | after->head_sentinel.next->prev = n; | |||
531 | ||||
532 | n->next->prev = after->tail_sentinel.prev; | |||
533 | n->next = after->head_sentinel.next; | |||
534 | ||||
535 | exec_list_make_empty(after); | |||
536 | } | |||
537 | ||||
538 | static inline void | |||
539 | exec_list_prepend(struct exec_list *list, struct exec_list *source) | |||
540 | { | |||
541 | exec_list_append(source, list); | |||
542 | exec_list_move_nodes_to(source, list); | |||
543 | } | |||
544 | ||||
545 | static inline void | |||
546 | exec_node_insert_list_before(struct exec_node *n, struct exec_list *before) | |||
547 | { | |||
548 | if (exec_list_is_empty(before)) | |||
549 | return; | |||
550 | ||||
551 | before->tail_sentinel.prev->next = n; | |||
552 | before->head_sentinel.next->prev = n->prev; | |||
553 | ||||
554 | n->prev->next = before->head_sentinel.next; | |||
555 | n->prev = before->tail_sentinel.prev; | |||
556 | ||||
557 | exec_list_make_empty(before); | |||
558 | } | |||
559 | ||||
560 | static inline void | |||
561 | exec_list_validate(const struct exec_list *list) | |||
562 | { | |||
563 | const struct exec_node *node; | |||
564 | ||||
565 | assert(list->head_sentinel.next->prev == &list->head_sentinel)(static_cast <bool> (list->head_sentinel.next->prev == &list->head_sentinel) ? void (0) : __assert_fail ( "list->head_sentinel.next->prev == &list->head_sentinel" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
566 | assert(list->head_sentinel.prev == NULL)(static_cast <bool> (list->head_sentinel.prev == __null ) ? void (0) : __assert_fail ("list->head_sentinel.prev == NULL" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
567 | assert(list->tail_sentinel.next == NULL)(static_cast <bool> (list->tail_sentinel.next == __null ) ? void (0) : __assert_fail ("list->tail_sentinel.next == NULL" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
568 | assert(list->tail_sentinel.prev->next == &list->tail_sentinel)(static_cast <bool> (list->tail_sentinel.prev->next == &list->tail_sentinel) ? void (0) : __assert_fail ( "list->tail_sentinel.prev->next == &list->tail_sentinel" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
569 | ||||
570 | /* We could try to use one of the interators below for this but they all | |||
571 | * either require C++ or assume the exec_node is embedded in a structure | |||
572 | * which is not the case for this function. | |||
573 | */ | |||
574 | for (node = list->head_sentinel.next; node->next != NULL__null; node = node->next) { | |||
575 | assert(node->next->prev == node)(static_cast <bool> (node->next->prev == node) ? void (0) : __assert_fail ("node->next->prev == node", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
576 | assert(node->prev->next == node)(static_cast <bool> (node->prev->next == node) ? void (0) : __assert_fail ("node->prev->next == node", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
577 | } | |||
578 | } | |||
579 | ||||
580 | #ifdef __cplusplus201703L | |||
581 | inline void exec_list::make_empty() | |||
582 | { | |||
583 | exec_list_make_empty(this); | |||
584 | } | |||
585 | ||||
586 | inline bool exec_list::is_empty() const | |||
587 | { | |||
588 | return exec_list_is_empty(this); | |||
589 | } | |||
590 | ||||
591 | inline const exec_node *exec_list::get_head() const | |||
592 | { | |||
593 | return exec_list_get_head_const(this); | |||
594 | } | |||
595 | ||||
596 | inline exec_node *exec_list::get_head() | |||
597 | { | |||
598 | return exec_list_get_head(this); | |||
599 | } | |||
600 | ||||
601 | inline const exec_node *exec_list::get_head_raw() const | |||
602 | { | |||
603 | return exec_list_get_head_raw_const(this); | |||
604 | } | |||
605 | ||||
606 | inline exec_node *exec_list::get_head_raw() | |||
607 | { | |||
608 | return exec_list_get_head_raw(this); | |||
609 | } | |||
610 | ||||
611 | inline const exec_node *exec_list::get_tail() const | |||
612 | { | |||
613 | return exec_list_get_tail_const(this); | |||
614 | } | |||
615 | ||||
616 | inline exec_node *exec_list::get_tail() | |||
617 | { | |||
618 | return exec_list_get_tail(this); | |||
619 | } | |||
620 | ||||
621 | inline const exec_node *exec_list::get_tail_raw() const | |||
622 | { | |||
623 | return exec_list_get_tail_raw_const(this); | |||
624 | } | |||
625 | ||||
626 | inline exec_node *exec_list::get_tail_raw() | |||
627 | { | |||
628 | return exec_list_get_tail_raw(this); | |||
629 | } | |||
630 | ||||
631 | inline unsigned exec_list::length() const | |||
632 | { | |||
633 | return exec_list_length(this); | |||
634 | } | |||
635 | ||||
636 | inline void exec_list::push_head(exec_node *n) | |||
637 | { | |||
638 | exec_list_push_head(this, n); | |||
639 | } | |||
640 | ||||
641 | inline void exec_list::push_tail(exec_node *n) | |||
642 | { | |||
643 | exec_list_push_tail(this, n); | |||
644 | } | |||
645 | ||||
646 | inline void exec_list::push_degenerate_list_at_head(exec_node *n) | |||
647 | { | |||
648 | exec_list_push_degenerate_list_at_head(this, n); | |||
649 | } | |||
650 | ||||
651 | inline exec_node *exec_list::pop_head() | |||
652 | { | |||
653 | return exec_list_pop_head(this); | |||
654 | } | |||
655 | ||||
656 | inline void exec_list::move_nodes_to(exec_list *target) | |||
657 | { | |||
658 | exec_list_move_nodes_to(this, target); | |||
659 | } | |||
660 | ||||
661 | inline void exec_list::append_list(exec_list *source) | |||
662 | { | |||
663 | exec_list_append(this, source); | |||
664 | } | |||
665 | ||||
666 | inline void exec_node::insert_after(exec_list *after) | |||
667 | { | |||
668 | exec_node_insert_list_after(this, after); | |||
669 | } | |||
670 | ||||
671 | inline void exec_list::prepend_list(exec_list *source) | |||
672 | { | |||
673 | exec_list_prepend(this, source); | |||
674 | } | |||
675 | ||||
676 | inline void exec_node::insert_before(exec_list *before) | |||
677 | { | |||
678 | exec_node_insert_list_before(this, before); | |||
679 | } | |||
680 | #endif | |||
681 | ||||
682 | #define exec_node_typed_forward(__node, __type)(!exec_node_is_tail_sentinel(__node) ? (__type) (__node) : __null ) \ | |||
683 | (!exec_node_is_tail_sentinel(__node) ? (__type) (__node) : NULL__null) | |||
684 | ||||
685 | #define exec_node_typed_backward(__node, __type)(!exec_node_is_head_sentinel(__node) ? (__type) (__node) : __null ) \ | |||
686 | (!exec_node_is_head_sentinel(__node) ? (__type) (__node) : NULL__null) | |||
687 | ||||
688 | #define foreach_in_list(__type, __inst, __list)for (__type *__inst = (!exec_node_is_tail_sentinel((__list)-> head_sentinel.next) ? (__type *) ((__list)->head_sentinel. next) : __null); (__inst) != __null; (__inst) = (!exec_node_is_tail_sentinel ((__inst)->next) ? (__type *) ((__inst)->next) : __null )) \ | |||
689 | for (__type *__inst = exec_node_typed_forward((__list)->head_sentinel.next, __type *)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next) ? (__type *) ((__list)->head_sentinel.next) : __null); \ | |||
690 | (__inst) != NULL__null; \ | |||
691 | (__inst) = exec_node_typed_forward((__inst)->next, __type *)(!exec_node_is_tail_sentinel((__inst)->next) ? (__type *) ( (__inst)->next) : __null)) | |||
692 | ||||
693 | #define foreach_in_list_reverse(__type, __inst, __list)for (__type *__inst = (!exec_node_is_head_sentinel((__list)-> tail_sentinel.prev) ? (__type *) ((__list)->tail_sentinel. prev) : __null); (__inst) != __null; (__inst) = (!exec_node_is_head_sentinel ((__inst)->prev) ? (__type *) ((__inst)->prev) : __null )) \ | |||
694 | for (__type *__inst = exec_node_typed_backward((__list)->tail_sentinel.prev, __type *)(!exec_node_is_head_sentinel((__list)->tail_sentinel.prev) ? (__type *) ((__list)->tail_sentinel.prev) : __null); \ | |||
695 | (__inst) != NULL__null; \ | |||
696 | (__inst) = exec_node_typed_backward((__inst)->prev, __type *)(!exec_node_is_head_sentinel((__inst)->prev) ? (__type *) ( (__inst)->prev) : __null)) | |||
697 | ||||
698 | /** | |||
699 | * This version is safe even if the current node is removed. | |||
700 | */ | |||
701 | ||||
702 | #define foreach_in_list_safe(__type, __node, __list)for (__type *__node = (!exec_node_is_tail_sentinel((__list)-> head_sentinel.next) ? (__type *) ((__list)->head_sentinel. next) : __null), *__next = (__node) ? (!exec_node_is_tail_sentinel ((__list)->head_sentinel.next->next) ? (__type *) ((__list )->head_sentinel.next->next) : __null) : __null; (__node ) != __null; (__node) = __next, __next = __next ? (!exec_node_is_tail_sentinel (__next->next) ? (__type *) (__next->next) : __null) : __null ) \ | |||
703 | for (__type *__node = exec_node_typed_forward((__list)->head_sentinel.next, __type *)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next) ? (__type *) ((__list)->head_sentinel.next) : __null), \ | |||
704 | *__next = (__node) ? exec_node_typed_forward((__list)->head_sentinel.next->next, __type *)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next-> next) ? (__type *) ((__list)->head_sentinel.next->next) : __null) : NULL__null; \ | |||
705 | (__node) != NULL__null; \ | |||
706 | (__node) = __next, __next = __next ? exec_node_typed_forward(__next->next, __type *)(!exec_node_is_tail_sentinel(__next->next) ? (__type *) (__next ->next) : __null) : NULL__null) | |||
707 | ||||
708 | #define foreach_in_list_reverse_safe(__type, __node, __list)for (__type *__node = (!exec_node_is_head_sentinel((__list)-> tail_sentinel.prev) ? (__type *) ((__list)->tail_sentinel. prev) : __null), *__prev = (__node) ? (!exec_node_is_head_sentinel ((__list)->tail_sentinel.prev->prev) ? (__type *) ((__list )->tail_sentinel.prev->prev) : __null) : __null; (__node ) != __null; (__node) = __prev, __prev = __prev ? (!exec_node_is_head_sentinel (__prev->prev) ? (__type *) (__prev->prev) : __null) : __null ) \ | |||
709 | for (__type *__node = exec_node_typed_backward((__list)->tail_sentinel.prev, __type *)(!exec_node_is_head_sentinel((__list)->tail_sentinel.prev) ? (__type *) ((__list)->tail_sentinel.prev) : __null), \ | |||
710 | *__prev = (__node) ? exec_node_typed_backward((__list)->tail_sentinel.prev->prev, __type *)(!exec_node_is_head_sentinel((__list)->tail_sentinel.prev-> prev) ? (__type *) ((__list)->tail_sentinel.prev->prev) : __null) : NULL__null; \ | |||
711 | (__node) != NULL__null; \ | |||
712 | (__node) = __prev, __prev = __prev ? exec_node_typed_backward(__prev->prev, __type *)(!exec_node_is_head_sentinel(__prev->prev) ? (__type *) (__prev ->prev) : __null) : NULL__null) | |||
713 | ||||
714 | #define foreach_in_list_use_after(__type, __inst, __list)__type *__inst; for ((__inst) = (!exec_node_is_tail_sentinel( (__list)->head_sentinel.next) ? (__type *) ((__list)->head_sentinel .next) : __null); (__inst) != __null; (__inst) = (!exec_node_is_tail_sentinel ((__inst)->next) ? (__type *) ((__inst)->next) : __null )) \ | |||
715 | __type *__inst; \ | |||
716 | for ((__inst) = exec_node_typed_forward((__list)->head_sentinel.next, __type *)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next) ? (__type *) ((__list)->head_sentinel.next) : __null); \ | |||
717 | (__inst) != NULL__null; \ | |||
718 | (__inst) = exec_node_typed_forward((__inst)->next, __type *)(!exec_node_is_tail_sentinel((__inst)->next) ? (__type *) ( (__inst)->next) : __null)) | |||
719 | ||||
720 | /** | |||
721 | * Iterate through two lists at once. Stops at the end of the shorter list. | |||
722 | * | |||
723 | * This is safe against either current node being removed or replaced. | |||
724 | */ | |||
725 | #define foreach_two_lists(__node1, __list1, __node2, __list2)for (struct exec_node * __node1 = (__list1)->head_sentinel .next, * __node2 = (__list2)->head_sentinel.next, * __next1 = __node1->next, * __next2 = __node2->next ; __next1 != __null && __next2 != __null ; __node1 = __next1, __node2 = __next2, __next1 = __next1->next, __next2 = __next2-> next) \ | |||
726 | for (struct exec_node * __node1 = (__list1)->head_sentinel.next, \ | |||
727 | * __node2 = (__list2)->head_sentinel.next, \ | |||
728 | * __next1 = __node1->next, \ | |||
729 | * __next2 = __node2->next \ | |||
730 | ; __next1 != NULL__null && __next2 != NULL__null \ | |||
731 | ; __node1 = __next1, \ | |||
732 | __node2 = __next2, \ | |||
733 | __next1 = __next1->next, \ | |||
734 | __next2 = __next2->next) | |||
735 | ||||
736 | #define exec_node_data_forward(type, node, field)(!exec_node_is_tail_sentinel(node) ? ((type *) (((uintptr_t) node ) - (((char *) &((type *) node)->field) - ((char *) node )))) : __null) \ | |||
737 | (!exec_node_is_tail_sentinel(node) ? exec_node_data(type, node, field)((type *) (((uintptr_t) node) - (((char *) &((type *) node )->field) - ((char *) node)))) : NULL__null) | |||
738 | ||||
739 | #define exec_node_data_backward(type, node, field)(!exec_node_is_head_sentinel(node) ? ((type *) (((uintptr_t) node ) - (((char *) &((type *) node)->field) - ((char *) node )))) : __null) \ | |||
740 | (!exec_node_is_head_sentinel(node) ? exec_node_data(type, node, field)((type *) (((uintptr_t) node) - (((char *) &((type *) node )->field) - ((char *) node)))) : NULL__null) | |||
741 | ||||
742 | #define foreach_list_typed(__type, __node, __field, __list)for (__type * __node = (!exec_node_is_tail_sentinel((__list)-> head_sentinel.next) ? ((__type *) (((uintptr_t) (__list)-> head_sentinel.next) - (((char *) &((__type *) (__list)-> head_sentinel.next)->__field) - ((char *) (__list)->head_sentinel .next)))) : __null); (__node) != __null; (__node) = (!exec_node_is_tail_sentinel ((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node )->__field.next) - (((char *) &((__type *) (__node)-> __field.next)->__field) - ((char *) (__node)->__field.next )))) : __null)) \ | |||
743 | for (__type * __node = \ | |||
744 | exec_node_data_forward(__type, (__list)->head_sentinel.next, __field)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next) ? ((__type *) (((uintptr_t) (__list)->head_sentinel.next) - (((char *) &((__type *) (__list)->head_sentinel.next )->__field) - ((char *) (__list)->head_sentinel.next))) ) : __null); \ | |||
745 | (__node) != NULL__null; \ | |||
746 | (__node) = exec_node_data_forward(__type, (__node)->__field.next, __field)(!exec_node_is_tail_sentinel((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node)->__field.next) - (((char *) & ((__type *) (__node)->__field.next)->__field) - ((char * ) (__node)->__field.next)))) : __null)) | |||
747 | ||||
748 | #define foreach_list_typed_from(__type, __node, __field, __list, __start)for (__type * __node = (!exec_node_is_tail_sentinel((__start) ) ? ((__type *) (((uintptr_t) (__start)) - (((char *) &(( __type *) (__start))->__field) - ((char *) (__start))))) : __null); (__node) != __null; (__node) = (!exec_node_is_tail_sentinel ((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node )->__field.next) - (((char *) &((__type *) (__node)-> __field.next)->__field) - ((char *) (__node)->__field.next )))) : __null)) \ | |||
749 | for (__type * __node = exec_node_data_forward(__type, (__start), __field)(!exec_node_is_tail_sentinel((__start)) ? ((__type *) (((uintptr_t ) (__start)) - (((char *) &((__type *) (__start))->__field ) - ((char *) (__start))))) : __null); \ | |||
750 | (__node) != NULL__null; \ | |||
751 | (__node) = exec_node_data_forward(__type, (__node)->__field.next, __field)(!exec_node_is_tail_sentinel((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node)->__field.next) - (((char *) & ((__type *) (__node)->__field.next)->__field) - ((char * ) (__node)->__field.next)))) : __null)) | |||
752 | ||||
753 | #define foreach_list_typed_reverse(__type, __node, __field, __list)for (__type * __node = (!exec_node_is_head_sentinel((__list)-> tail_sentinel.prev) ? ((__type *) (((uintptr_t) (__list)-> tail_sentinel.prev) - (((char *) &((__type *) (__list)-> tail_sentinel.prev)->__field) - ((char *) (__list)->tail_sentinel .prev)))) : __null); (__node) != __null; (__node) = (!exec_node_is_head_sentinel ((__node)->__field.prev) ? ((__type *) (((uintptr_t) (__node )->__field.prev) - (((char *) &((__type *) (__node)-> __field.prev)->__field) - ((char *) (__node)->__field.prev )))) : __null)) \ | |||
754 | for (__type * __node = \ | |||
755 | exec_node_data_backward(__type, (__list)->tail_sentinel.prev, __field)(!exec_node_is_head_sentinel((__list)->tail_sentinel.prev) ? ((__type *) (((uintptr_t) (__list)->tail_sentinel.prev) - (((char *) &((__type *) (__list)->tail_sentinel.prev )->__field) - ((char *) (__list)->tail_sentinel.prev))) ) : __null); \ | |||
756 | (__node) != NULL__null; \ | |||
757 | (__node) = exec_node_data_backward(__type, (__node)->__field.prev, __field)(!exec_node_is_head_sentinel((__node)->__field.prev) ? ((__type *) (((uintptr_t) (__node)->__field.prev) - (((char *) & ((__type *) (__node)->__field.prev)->__field) - ((char * ) (__node)->__field.prev)))) : __null)) | |||
758 | ||||
759 | #define foreach_list_typed_safe(__type, __node, __field, __list)for (__type * __node = (!exec_node_is_tail_sentinel((__list)-> head_sentinel.next) ? ((__type *) (((uintptr_t) (__list)-> head_sentinel.next) - (((char *) &((__type *) (__list)-> head_sentinel.next)->__field) - ((char *) (__list)->head_sentinel .next)))) : __null), * __next = (__node) ? (!exec_node_is_tail_sentinel ((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node )->__field.next) - (((char *) &((__type *) (__node)-> __field.next)->__field) - ((char *) (__node)->__field.next )))) : __null) : __null; (__node) != __null; (__node) = __next , __next = (__next && (__next)->__field.next) ? (! exec_node_is_tail_sentinel((__next)->__field.next) ? ((__type *) (((uintptr_t) (__next)->__field.next) - (((char *) & ((__type *) (__next)->__field.next)->__field) - ((char * ) (__next)->__field.next)))) : __null) : __null) \ | |||
760 | for (__type * __node = \ | |||
761 | exec_node_data_forward(__type, (__list)->head_sentinel.next, __field)(!exec_node_is_tail_sentinel((__list)->head_sentinel.next) ? ((__type *) (((uintptr_t) (__list)->head_sentinel.next) - (((char *) &((__type *) (__list)->head_sentinel.next )->__field) - ((char *) (__list)->head_sentinel.next))) ) : __null), \ | |||
762 | * __next = (__node) ? \ | |||
763 | exec_node_data_forward(__type, (__node)->__field.next, __field)(!exec_node_is_tail_sentinel((__node)->__field.next) ? ((__type *) (((uintptr_t) (__node)->__field.next) - (((char *) & ((__type *) (__node)->__field.next)->__field) - ((char * ) (__node)->__field.next)))) : __null) : NULL__null; \ | |||
764 | (__node) != NULL__null; \ | |||
765 | (__node) = __next, __next = (__next && (__next)->__field.next) ? \ | |||
766 | exec_node_data_forward(__type, (__next)->__field.next, __field)(!exec_node_is_tail_sentinel((__next)->__field.next) ? ((__type *) (((uintptr_t) (__next)->__field.next) - (((char *) & ((__type *) (__next)->__field.next)->__field) - ((char * ) (__next)->__field.next)))) : __null) : NULL__null) | |||
767 | ||||
768 | #define foreach_list_typed_reverse_safe(__type, __node, __field, __list)for (__type * __node = (!exec_node_is_head_sentinel((__list)-> tail_sentinel.prev) ? ((__type *) (((uintptr_t) (__list)-> tail_sentinel.prev) - (((char *) &((__type *) (__list)-> tail_sentinel.prev)->__field) - ((char *) (__list)->tail_sentinel .prev)))) : __null), * __prev = (__node) ? (!exec_node_is_head_sentinel ((__node)->__field.prev) ? ((__type *) (((uintptr_t) (__node )->__field.prev) - (((char *) &((__type *) (__node)-> __field.prev)->__field) - ((char *) (__node)->__field.prev )))) : __null) : __null; (__node) != __null; (__node) = __prev , __prev = (__prev && (__prev)->__field.prev) ? (! exec_node_is_head_sentinel((__prev)->__field.prev) ? ((__type *) (((uintptr_t) (__prev)->__field.prev) - (((char *) & ((__type *) (__prev)->__field.prev)->__field) - ((char * ) (__prev)->__field.prev)))) : __null) : __null) \ | |||
769 | for (__type * __node = \ | |||
770 | exec_node_data_backward(__type, (__list)->tail_sentinel.prev, __field)(!exec_node_is_head_sentinel((__list)->tail_sentinel.prev) ? ((__type *) (((uintptr_t) (__list)->tail_sentinel.prev) - (((char *) &((__type *) (__list)->tail_sentinel.prev )->__field) - ((char *) (__list)->tail_sentinel.prev))) ) : __null), \ | |||
771 | * __prev = (__node) ? \ | |||
772 | exec_node_data_backward(__type, (__node)->__field.prev, __field)(!exec_node_is_head_sentinel((__node)->__field.prev) ? ((__type *) (((uintptr_t) (__node)->__field.prev) - (((char *) & ((__type *) (__node)->__field.prev)->__field) - ((char * ) (__node)->__field.prev)))) : __null) : NULL__null; \ | |||
773 | (__node) != NULL__null; \ | |||
774 | (__node) = __prev, __prev = (__prev && (__prev)->__field.prev) ? \ | |||
775 | exec_node_data_backward(__type, (__prev)->__field.prev, __field)(!exec_node_is_head_sentinel((__prev)->__field.prev) ? ((__type *) (((uintptr_t) (__prev)->__field.prev) - (((char *) & ((__type *) (__prev)->__field.prev)->__field) - ((char * ) (__prev)->__field.prev)))) : __null) : NULL__null) | |||
776 | ||||
777 | #endif /* LIST_CONTAINER_H */ |