OLD | NEW |
(Empty) | |
| 1 Backport of this patch to mesa 7.9: |
| 2 |
| 3 From 1802cb9bafc4125300870be51e8b22ddd795d61e Mon Sep 17 00:00:00 2001 |
| 4 From: Kenneth Graunke <kenneth@whitecape.org> |
| 5 Date: Mon, 29 Nov 2010 18:59:16 +0000 |
| 6 Subject: glsl: Remove "discard" support from lower_jumps. |
| 7 |
| 8 The new lower_discard and opt_discard_simplification passes should |
| 9 handle all the necessary transformations, so lower_jumps doesn't need to |
| 10 support it. |
| 11 |
| 12 Also, lower_jumps incorrectly handled conditional discards - it would |
| 13 unconditionally truncate all code after the discard. Rather than fixing |
| 14 the bug, simply remove the code. |
| 15 |
| 16 NOTE: This is a candidate for the 7.9 branch. |
| 17 --- |
| 18 diff -Naurp Mesa-7.9.orig/src/glsl/ir_lower_jumps.cpp Mesa-7.9.work/src/glsl/ir_
lower_jumps.cpp |
| 19 --- Mesa-7.9.orig/src/glsl/ir_lower_jumps.cpp 2010-12-07 18:22:17.749760000 -0
800 |
| 20 +++ Mesa-7.9.work/src/glsl/ir_lower_jumps.cpp 2010-12-13 11:26:58.014994000 -0
800 |
| 21 @@ -36,7 +36,6 @@ enum jump_strength |
| 22 strength_continue, |
| 23 strength_break, |
| 24 strength_return, |
| 25 - strength_discard |
| 26 }; |
| 27 |
| 28 struct block_record |
| 29 @@ -202,8 +201,6 @@ struct ir_lower_jumps_visitor : public i |
| 30 |
| 31 virtual void visit(class ir_discard * ir) |
| 32 { |
| 33 - truncate_after_instruction(ir); |
| 34 - this->block.min_strength = strength_discard; |
| 35 } |
| 36 |
| 37 enum jump_strength get_jump_strength(ir_instruction* ir) |
| 38 @@ -217,8 +214,6 @@ struct ir_lower_jumps_visitor : public i |
| 39 return strength_continue; |
| 40 } else if(ir->ir_type == ir_type_return) |
| 41 return strength_return; |
| 42 - else if(ir->ir_type == ir_type_discard) |
| 43 - return strength_discard; |
| 44 else |
| 45 return strength_none; |
| 46 } |
| 47 @@ -253,9 +248,6 @@ struct ir_lower_jumps_visitor : public i |
| 48 else |
| 49 lower = lower_sub_return; |
| 50 break; |
| 51 - case strength_discard: |
| 52 - lower = false; /* probably nothing needs this lowered */ |
| 53 - break; |
| 54 } |
| 55 return lower; |
| 56 } |
| 57 @@ -313,7 +305,6 @@ retry: /* we get here if we put code aft |
| 58 /* FINISHME: unify returns with identical expressions */ |
| 59 else if(jump_strengths[0] == strength_return && this->function.sign
ature->return_type->is_void()) |
| 60 ir->insert_after(new(ir) ir_return(NULL)); |
| 61 - /* FINISHME: unify discards */ |
| 62 else |
| 63 unify = false; |
| 64 |
| 65 diff -Naurp Mesa-7.9.orig/src/glsl/ir_lower_jumps.cpp~ Mesa-7.9.work/src/glsl/ir
_lower_jumps.cpp~ |
| 66 --- Mesa-7.9.orig/src/glsl/ir_lower_jumps.cpp~ 1969-12-31 16:00:00.000000000 -0
800 |
| 67 +++ Mesa-7.9.work/src/glsl/ir_lower_jumps.cpp~ 2010-12-13 11:26:29.542278000 -0
800 |
| 68 @@ -0,0 +1,539 @@ |
| 69 +/* |
| 70 + * Copyright © 2010 Luca Barbieri |
| 71 + * |
| 72 + * Permission is hereby granted, free of charge, to any person obtaining a |
| 73 + * copy of this software and associated documentation files (the "Software"), |
| 74 + * to deal in the Software without restriction, including without limitation |
| 75 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 76 + * and/or sell copies of the Software, and to permit persons to whom the |
| 77 + * Software is furnished to do so, subject to the following conditions: |
| 78 + * |
| 79 + * The above copyright notice and this permission notice (including the next |
| 80 + * paragraph) shall be included in all copies or substantial portions of the |
| 81 + * Software. |
| 82 + * |
| 83 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 84 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 85 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 86 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 87 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 88 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 89 + * DEALINGS IN THE SOFTWARE. |
| 90 + */ |
| 91 + |
| 92 +/** |
| 93 + * \file ir_lower_jumps.cpp |
| 94 + */ |
| 95 + |
| 96 +#include "glsl_types.h" |
| 97 +#include <string.h> |
| 98 +#include "ir.h" |
| 99 + |
| 100 +enum jump_strength |
| 101 +{ |
| 102 + strength_none, |
| 103 + strength_always_clears_execute_flag, |
| 104 + strength_continue, |
| 105 + strength_break, |
| 106 + strength_return, |
| 107 +}; |
| 108 + |
| 109 +struct block_record |
| 110 +{ |
| 111 + /* minimum jump strength (of lowered IR, not pre-lowering IR) |
| 112 + * |
| 113 + * If the block ends with a jump, must be the strength of the jump. |
| 114 + * Otherwise, the jump would be dead and have been deleted before) |
| 115 + * |
| 116 + * If the block doesn't end with a jump, it can be different than strength_n
one if all paths before it lead to some jump |
| 117 + * (e.g. an if with a return in one branch, and a break in the other, while
not lowering them) |
| 118 + * Note that identical jumps are usually unified though. |
| 119 + */ |
| 120 + jump_strength min_strength; |
| 121 + |
| 122 + /* can anything clear the execute flag? */ |
| 123 + bool may_clear_execute_flag; |
| 124 + |
| 125 + block_record() |
| 126 + { |
| 127 + this->min_strength = strength_none; |
| 128 + this->may_clear_execute_flag = false; |
| 129 + } |
| 130 +}; |
| 131 + |
| 132 +struct loop_record |
| 133 +{ |
| 134 + ir_function_signature* signature; |
| 135 + ir_loop* loop; |
| 136 + |
| 137 + /* used to avoid lowering the break used to represent lowered breaks */ |
| 138 + unsigned nesting_depth; |
| 139 + bool in_if_at_the_end_of_the_loop; |
| 140 + |
| 141 + bool may_set_return_flag; |
| 142 + |
| 143 + ir_variable* break_flag; |
| 144 + ir_variable* execute_flag; /* cleared to emulate continue */ |
| 145 + |
| 146 + loop_record(ir_function_signature* p_signature = 0, ir_loop* p_loop = 0) |
| 147 + { |
| 148 + this->signature = p_signature; |
| 149 + this->loop = p_loop; |
| 150 + this->nesting_depth = 0; |
| 151 + this->in_if_at_the_end_of_the_loop = false; |
| 152 + this->may_set_return_flag = false; |
| 153 + this->break_flag = 0; |
| 154 + this->execute_flag = 0; |
| 155 + } |
| 156 + |
| 157 + ir_variable* get_execute_flag() |
| 158 + { |
| 159 + /* also supported for the "function loop" */ |
| 160 + if(!this->execute_flag) { |
| 161 + exec_list& list = this->loop ? this->loop->body_instructions : signatu
re->body; |
| 162 + this->execute_flag = new(this->signature) ir_variable(glsl_type::bool_
type, "execute_flag", ir_var_temporary); |
| 163 + list.push_head(new(this->signature) ir_assignment(new(this->signature)
ir_dereference_variable(execute_flag), new(this->signature) ir_constant(true),
0)); |
| 164 + list.push_head(this->execute_flag); |
| 165 + } |
| 166 + return this->execute_flag; |
| 167 + } |
| 168 + |
| 169 + ir_variable* get_break_flag() |
| 170 + { |
| 171 + assert(this->loop); |
| 172 + if(!this->break_flag) { |
| 173 + this->break_flag = new(this->signature) ir_variable(glsl_type::bool_ty
pe, "break_flag", ir_var_temporary); |
| 174 + this->loop->insert_before(this->break_flag); |
| 175 + this->loop->insert_before(new(this->signature) ir_assignment(new(this-
>signature) ir_dereference_variable(break_flag), new(this->signature) ir_constan
t(false), 0)); |
| 176 + } |
| 177 + return this->break_flag; |
| 178 + } |
| 179 +}; |
| 180 + |
| 181 +struct function_record |
| 182 +{ |
| 183 + ir_function_signature* signature; |
| 184 + ir_variable* return_flag; /* used to break out of all loops and then jump to
the return instruction */ |
| 185 + ir_variable* return_value; |
| 186 + bool is_main; |
| 187 + unsigned nesting_depth; |
| 188 + |
| 189 + function_record(ir_function_signature* p_signature = 0) |
| 190 + { |
| 191 + this->signature = p_signature; |
| 192 + this->return_flag = 0; |
| 193 + this->return_value = 0; |
| 194 + this->nesting_depth = 0; |
| 195 + this->is_main = this->signature && (strcmp(this->signature->function_name
(), "main") == 0); |
| 196 + } |
| 197 + |
| 198 + ir_variable* get_return_flag() |
| 199 + { |
| 200 + if(!this->return_flag) { |
| 201 + this->return_flag = new(this->signature) ir_variable(glsl_type::bool_t
ype, "return_flag", ir_var_temporary); |
| 202 + this->signature->body.push_head(new(this->signature) ir_assignment(new
(this->signature) ir_dereference_variable(return_flag), new(this->signature) ir_
constant(false), 0)); |
| 203 + this->signature->body.push_head(this->return_flag); |
| 204 + } |
| 205 + return this->return_flag; |
| 206 + } |
| 207 + |
| 208 + ir_variable* get_return_value() |
| 209 + { |
| 210 + if(!this->return_value) { |
| 211 + assert(!this->signature->return_type->is_void()); |
| 212 + return_value = new(this->signature) ir_variable(this->signature->retur
n_type, "return_value", ir_var_temporary); |
| 213 + this->signature->body.push_head(this->return_value); |
| 214 + } |
| 215 + return this->return_value; |
| 216 + } |
| 217 +}; |
| 218 + |
| 219 +struct ir_lower_jumps_visitor : public ir_control_flow_visitor { |
| 220 + bool progress; |
| 221 + |
| 222 + struct function_record function; |
| 223 + struct loop_record loop; |
| 224 + struct block_record block; |
| 225 + |
| 226 + bool pull_out_jumps; |
| 227 + bool lower_continue; |
| 228 + bool lower_break; |
| 229 + bool lower_sub_return; |
| 230 + bool lower_main_return; |
| 231 + |
| 232 + ir_lower_jumps_visitor() |
| 233 + { |
| 234 + this->progress = false; |
| 235 + } |
| 236 + |
| 237 + void truncate_after_instruction(exec_node *ir) |
| 238 + { |
| 239 + if (!ir) |
| 240 + return; |
| 241 + |
| 242 + while (!ir->get_next()->is_tail_sentinel()) { |
| 243 + ((ir_instruction *)ir->get_next())->remove(); |
| 244 + this->progress = true; |
| 245 + } |
| 246 + } |
| 247 + |
| 248 + void move_outer_block_inside(ir_instruction *ir, exec_list *inner_block) |
| 249 + { |
| 250 + while (!ir->get_next()->is_tail_sentinel()) { |
| 251 + ir_instruction *move_ir = (ir_instruction *)ir->get_next(); |
| 252 + |
| 253 + move_ir->remove(); |
| 254 + inner_block->push_tail(move_ir); |
| 255 + } |
| 256 + } |
| 257 + |
| 258 + virtual void visit(class ir_loop_jump * ir) |
| 259 + { |
| 260 + truncate_after_instruction(ir); |
| 261 + this->block.min_strength = ir->is_break() ? strength_break : strength_con
tinue; |
| 262 + } |
| 263 + |
| 264 + virtual void visit(class ir_return * ir) |
| 265 + { |
| 266 + truncate_after_instruction(ir); |
| 267 + this->block.min_strength = strength_return; |
| 268 + } |
| 269 + |
| 270 + virtual void visit(class ir_discard * ir) |
| 271 + { |
| 272 + } |
| 273 + |
| 274 + enum jump_strength get_jump_strength(ir_instruction* ir) |
| 275 + { |
| 276 + if(!ir) |
| 277 + return strength_none; |
| 278 + else if(ir->ir_type == ir_type_loop_jump) { |
| 279 + if(((ir_loop_jump*)ir)->is_break()) |
| 280 + return strength_break; |
| 281 + else |
| 282 + return strength_continue; |
| 283 + } else if(ir->ir_type == ir_type_return) |
| 284 + return strength_return; |
| 285 + else |
| 286 + return strength_none; |
| 287 + } |
| 288 + |
| 289 + bool should_lower_jump(ir_jump* ir) |
| 290 + { |
| 291 + unsigned strength = get_jump_strength(ir); |
| 292 + bool lower; |
| 293 + switch(strength) |
| 294 + { |
| 295 + case strength_none: |
| 296 + lower = false; /* don't change this, code relies on it */ |
| 297 + break; |
| 298 + case strength_continue: |
| 299 + lower = lower_continue; |
| 300 + break; |
| 301 + case strength_break: |
| 302 + assert(this->loop.loop); |
| 303 + /* never lower "canonical break" */ |
| 304 + if(ir->get_next()->is_tail_sentinel() && (this->loop.nesting_depth ==
0 |
| 305 + || (this->loop.nesting_depth == 1 && this->loop.in_if_at_the_end
_of_the_loop))) |
| 306 + lower = false; |
| 307 + else |
| 308 + lower = lower_break; |
| 309 + break; |
| 310 + case strength_return: |
| 311 + /* never lower return at the end of a this->function */ |
| 312 + if(this->function.nesting_depth == 0 && ir->get_next()->is_tail_sentin
el()) |
| 313 + lower = false; |
| 314 + else if (this->function.is_main) |
| 315 + lower = lower_main_return; |
| 316 + else |
| 317 + lower = lower_sub_return; |
| 318 + break; |
| 319 + case strength_discard: |
| 320 + lower = false; /* probably nothing needs this lowered */ |
| 321 + break; |
| 322 + } |
| 323 + return lower; |
| 324 + } |
| 325 + |
| 326 + block_record visit_block(exec_list* list) |
| 327 + { |
| 328 + block_record saved_block = this->block; |
| 329 + this->block = block_record(); |
| 330 + visit_exec_list(list, this); |
| 331 + block_record ret = this->block; |
| 332 + this->block = saved_block; |
| 333 + return ret; |
| 334 + } |
| 335 + |
| 336 + virtual void visit(ir_if *ir) |
| 337 + { |
| 338 + if(this->loop.nesting_depth == 0 && ir->get_next()->is_tail_sentinel()) |
| 339 + this->loop.in_if_at_the_end_of_the_loop = true; |
| 340 + |
| 341 + ++this->function.nesting_depth; |
| 342 + ++this->loop.nesting_depth; |
| 343 + |
| 344 + block_record block_records[2]; |
| 345 + ir_jump* jumps[2]; |
| 346 + |
| 347 + block_records[0] = visit_block(&ir->then_instructions); |
| 348 + block_records[1] = visit_block(&ir->else_instructions); |
| 349 + |
| 350 +retry: /* we get here if we put code after the if inside a branch */ |
| 351 + for(unsigned i = 0; i < 2; ++i) { |
| 352 + exec_list& list = i ? ir->else_instructions : ir->then_instructions; |
| 353 + jumps[i] = 0; |
| 354 + if(!list.is_empty() && get_jump_strength((ir_instruction*)list.get_tail()
)) |
| 355 + jumps[i] = (ir_jump*)list.get_tail(); |
| 356 + } |
| 357 + |
| 358 + for(;;) { |
| 359 + jump_strength jump_strengths[2]; |
| 360 + |
| 361 + for(unsigned i = 0; i < 2; ++i) { |
| 362 + if(jumps[i]) { |
| 363 + jump_strengths[i] = block_records[i].min_strength; |
| 364 + assert(jump_strengths[i] == get_jump_strength(jumps[i])); |
| 365 + } else |
| 366 + jump_strengths[i] = strength_none; |
| 367 + } |
| 368 + |
| 369 + /* move both jumps out if possible */ |
| 370 + if(pull_out_jumps && jump_strengths[0] == jump_strengths[1]) { |
| 371 + bool unify = true; |
| 372 + if(jump_strengths[0] == strength_continue) |
| 373 + ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_continu
e)); |
| 374 + else if(jump_strengths[0] == strength_break) |
| 375 + ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_break))
; |
| 376 + /* FINISHME: unify returns with identical expressions */ |
| 377 + else if(jump_strengths[0] == strength_return && this->function.sign
ature->return_type->is_void()) |
| 378 + ir->insert_after(new(ir) ir_return(NULL)); |
| 379 + /* FINISHME: unify discards */ |
| 380 + else |
| 381 + unify = false; |
| 382 + |
| 383 + if(unify) { |
| 384 + jumps[0]->remove(); |
| 385 + jumps[1]->remove(); |
| 386 + this->progress = true; |
| 387 + |
| 388 + jumps[0] = 0; |
| 389 + jumps[1] = 0; |
| 390 + block_records[0].min_strength = strength_none; |
| 391 + block_records[1].min_strength = strength_none; |
| 392 + break; |
| 393 + } |
| 394 + } |
| 395 + |
| 396 + /* lower a jump: if both need to lowered, start with the strongest one
, so that |
| 397 + * we might later unify the lowered version with the other one |
| 398 + */ |
| 399 + bool should_lower[2]; |
| 400 + for(unsigned i = 0; i < 2; ++i) |
| 401 + should_lower[i] = should_lower_jump(jumps[i]); |
| 402 + |
| 403 + int lower; |
| 404 + if(should_lower[1] && should_lower[0]) |
| 405 + lower = jump_strengths[1] > jump_strengths[0]; |
| 406 + else if(should_lower[0]) |
| 407 + lower = 0; |
| 408 + else if(should_lower[1]) |
| 409 + lower = 1; |
| 410 + else |
| 411 + break; |
| 412 + |
| 413 + if(jump_strengths[lower] == strength_return) { |
| 414 + ir_variable* return_flag = this->function.get_return_flag(); |
| 415 + if(!this->function.signature->return_type->is_void()) { |
| 416 + ir_variable* return_value = this->function.get_return_value(); |
| 417 + jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_de
reference_variable(return_value), ((ir_return*)jumps[lower])->value, NULL)); |
| 418 + } |
| 419 + jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_deref
erence_variable(return_flag), new (ir) ir_constant(true), NULL)); |
| 420 + this->loop.may_set_return_flag = true; |
| 421 + if(this->loop.loop) { |
| 422 + ir_loop_jump* lowered = 0; |
| 423 + lowered = new(ir) ir_loop_jump(ir_loop_jump::jump_break); |
| 424 + block_records[lower].min_strength = strength_break; |
| 425 + jumps[lower]->replace_with(lowered); |
| 426 + jumps[lower] = lowered; |
| 427 + } else |
| 428 + goto lower_continue; |
| 429 + this->progress = true; |
| 430 + } else if(jump_strengths[lower] == strength_break) { |
| 431 + /* We can't lower to an actual continue because that would execute
the increment. |
| 432 + * |
| 433 + * In the lowered code, we instead put the break check between the
this->loop body and the increment, |
| 434 + * which is impossible with a real continue as defined by the GLSL
IR currently. |
| 435 + * |
| 436 + * Smarter options (such as undoing the increment) are possible but
it's not worth implementing them, |
| 437 + * because if break is lowered, continue is almost surely lowered t
oo. |
| 438 + */ |
| 439 + jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_deref
erence_variable(this->loop.get_break_flag()), new (ir) ir_constant(true), 0)); |
| 440 + goto lower_continue; |
| 441 + } else if(jump_strengths[lower] == strength_continue) { |
| 442 +lower_continue: |
| 443 + ir_variable* execute_flag = this->loop.get_execute_flag(); |
| 444 + jumps[lower]->replace_with(new(ir) ir_assignment(new (ir) ir_derefe
rence_variable(execute_flag), new (ir) ir_constant(false), 0)); |
| 445 + jumps[lower] = 0; |
| 446 + block_records[lower].min_strength = strength_always_clears_execute_
flag; |
| 447 + block_records[lower].may_clear_execute_flag = true; |
| 448 + this->progress = true; |
| 449 + break; |
| 450 + } |
| 451 + } |
| 452 + |
| 453 + /* move out a jump out if possible */ |
| 454 + if(pull_out_jumps) { |
| 455 + int move_out = -1; |
| 456 + if(jumps[0] && block_records[1].min_strength >= strength_continue) |
| 457 + move_out = 0; |
| 458 + else if(jumps[1] && block_records[0].min_strength >= strength_continue
) |
| 459 + move_out = 1; |
| 460 + |
| 461 + if(move_out >= 0) |
| 462 + { |
| 463 + jumps[move_out]->remove(); |
| 464 + ir->insert_after(jumps[move_out]); |
| 465 + jumps[move_out] = 0; |
| 466 + block_records[move_out].min_strength = strength_none; |
| 467 + this->progress = true; |
| 468 + } |
| 469 + } |
| 470 + |
| 471 + if(block_records[0].min_strength < block_records[1].min_strength) |
| 472 + this->block.min_strength = block_records[0].min_strength; |
| 473 + else |
| 474 + this->block.min_strength = block_records[1].min_strength; |
| 475 + 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; |
| 476 + |
| 477 + if(this->block.min_strength) |
| 478 + truncate_after_instruction(ir); |
| 479 + else if(this->block.may_clear_execute_flag) |
| 480 + { |
| 481 + int move_into = -1; |
| 482 + if(block_records[0].min_strength && !block_records[1].may_clear_execut
e_flag) |
| 483 + move_into = 1; |
| 484 + else if(block_records[1].min_strength && !block_records[0].may_clear_e
xecute_flag) |
| 485 + move_into = 0; |
| 486 + |
| 487 + if(move_into >= 0) { |
| 488 + assert(!block_records[move_into].min_strength && !block_records[mov
e_into].may_clear_execute_flag); /* otherwise, we just truncated */ |
| 489 + |
| 490 + exec_list* list = move_into ? &ir->else_instructions : &ir->then_in
structions; |
| 491 + exec_node* next = ir->get_next(); |
| 492 + if(!next->is_tail_sentinel()) { |
| 493 + move_outer_block_inside(ir, list); |
| 494 + |
| 495 + exec_list list; |
| 496 + list.head = next; |
| 497 + block_records[move_into] = visit_block(&list); |
| 498 + |
| 499 + this->progress = true; |
| 500 + goto retry; |
| 501 + } |
| 502 + } else { |
| 503 + ir_instruction* ir_after; |
| 504 + for(ir_after = (ir_instruction*)ir->get_next(); !ir_after->is_tail_
sentinel();) |
| 505 + { |
| 506 + ir_if* ir_if = ir_after->as_if(); |
| 507 + if(ir_if && ir_if->else_instructions.is_empty()) { |
| 508 + ir_dereference_variable* ir_if_cond_deref = ir_if->condition-
>as_dereference_variable(); |
| 509 + if(ir_if_cond_deref && ir_if_cond_deref->var == this->loop.ex
ecute_flag) { |
| 510 + ir_instruction* ir_next = (ir_instruction*)ir_after->get_n
ext(); |
| 511 + ir_after->insert_before(&ir_if->then_instructions); |
| 512 + ir_after->remove(); |
| 513 + ir_after = ir_next; |
| 514 + continue; |
| 515 + } |
| 516 + } |
| 517 + ir_after = (ir_instruction*)ir_after->get_next(); |
| 518 + |
| 519 + /* only set this if we find any unprotected instruction */ |
| 520 + this->progress = true; |
| 521 + } |
| 522 + |
| 523 + if(!ir->get_next()->is_tail_sentinel()) { |
| 524 + assert(this->loop.execute_flag); |
| 525 + ir_if* if_execute = new(ir) ir_if(new(ir) ir_dereference_variabl
e(this->loop.execute_flag)); |
| 526 + move_outer_block_inside(ir, &if_execute->then_instructions); |
| 527 + ir->insert_after(if_execute); |
| 528 + } |
| 529 + } |
| 530 + } |
| 531 + --this->loop.nesting_depth; |
| 532 + --this->function.nesting_depth; |
| 533 + } |
| 534 + |
| 535 + virtual void visit(ir_loop *ir) |
| 536 + { |
| 537 + ++this->function.nesting_depth; |
| 538 + loop_record saved_loop = this->loop; |
| 539 + this->loop = loop_record(this->function.signature, ir); |
| 540 + |
| 541 + block_record body = visit_block(&ir->body_instructions); |
| 542 + |
| 543 + if(body.min_strength >= strength_break) { |
| 544 + /* FINISHME: turn the this->loop into an if, or replace it with its bo
dy */ |
| 545 + } |
| 546 + |
| 547 + if(this->loop.break_flag) { |
| 548 + ir_if* break_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->
loop.break_flag)); |
| 549 + break_if->then_instructions.push_tail(new(ir) ir_loop_jump(ir_loop_jum
p::jump_break)); |
| 550 + ir->body_instructions.push_tail(break_if); |
| 551 + } |
| 552 + |
| 553 + if(this->loop.may_set_return_flag) { |
| 554 + assert(this->function.return_flag); |
| 555 + ir_if* return_if = new(ir) ir_if(new(ir) ir_dereference_variable(this-
>function.return_flag)); |
| 556 + return_if->then_instructions.push_tail(new(ir) ir_loop_jump(saved_loop
.loop ? ir_loop_jump::jump_break : ir_loop_jump::jump_continue)); |
| 557 + ir->insert_after(return_if); |
| 558 + } |
| 559 + |
| 560 + this->loop = saved_loop; |
| 561 + --this->function.nesting_depth; |
| 562 + } |
| 563 + |
| 564 + virtual void visit(ir_function_signature *ir) |
| 565 + { |
| 566 + /* these are not strictly necessary */ |
| 567 + assert(!this->function.signature); |
| 568 + assert(!this->loop.loop); |
| 569 + |
| 570 + function_record saved_function = this->function; |
| 571 + loop_record saved_loop = this->loop; |
| 572 + this->function = function_record(ir); |
| 573 + this->loop = loop_record(ir); |
| 574 + |
| 575 + assert(!this->loop.loop); |
| 576 + visit_block(&ir->body); |
| 577 + |
| 578 + if(this->function.return_value) |
| 579 + ir->body.push_tail(new(ir) ir_return(new (ir) ir_dereference_variable(
this->function.return_value))); |
| 580 + |
| 581 + this->loop = saved_loop; |
| 582 + this->function = saved_function; |
| 583 + } |
| 584 + |
| 585 + virtual void visit(class ir_function * ir) |
| 586 + { |
| 587 + visit_block(&ir->signatures); |
| 588 + } |
| 589 +}; |
| 590 + |
| 591 +bool |
| 592 +do_lower_jumps(exec_list *instructions, bool pull_out_jumps, bool lower_sub_ret
urn, bool lower_main_return, bool lower_continue, bool lower_break) |
| 593 +{ |
| 594 + ir_lower_jumps_visitor v; |
| 595 + v.pull_out_jumps = pull_out_jumps; |
| 596 + v.lower_continue = lower_continue; |
| 597 + v.lower_break = lower_break; |
| 598 + v.lower_sub_return = lower_sub_return; |
| 599 + v.lower_main_return = lower_main_return; |
| 600 + |
| 601 + do { |
| 602 + v.progress = false; |
| 603 + visit_exec_list(instructions, &v); |
| 604 + } while (v.progress); |
| 605 + |
| 606 + return v.progress; |
| 607 +} |
OLD | NEW |