2013-10-30 10:32:12 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2013 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file brw_dead_control_flow.cpp
|
|
|
|
|
*
|
|
|
|
|
* This file implements the dead control flow elimination optimization pass.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "brw_shader.h"
|
|
|
|
|
#include "brw_cfg.h"
|
|
|
|
|
|
2016-03-12 18:50:24 -08:00
|
|
|
using namespace brw;
|
|
|
|
|
|
2013-10-30 10:32:12 -07:00
|
|
|
/* Look for and eliminate dead control flow:
|
|
|
|
|
*
|
|
|
|
|
* - if/endif
|
2016-02-26 11:16:33 -08:00
|
|
|
* - else in else/endif
|
2016-02-24 19:29:57 -08:00
|
|
|
* - then in if/else/endif
|
2013-10-30 10:32:12 -07:00
|
|
|
*/
|
|
|
|
|
bool
|
2015-05-20 09:44:01 -07:00
|
|
|
dead_control_flow_eliminate(backend_shader *s)
|
2013-10-30 10:32:12 -07:00
|
|
|
{
|
|
|
|
|
bool progress = false;
|
|
|
|
|
|
2015-05-20 09:44:01 -07:00
|
|
|
foreach_block_safe (block, s->cfg) {
|
2016-02-24 19:26:13 -08:00
|
|
|
bblock_t *prev_block = block->prev();
|
2016-03-30 12:00:02 -07:00
|
|
|
|
|
|
|
|
if (!prev_block)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-02-24 18:52:05 -08:00
|
|
|
backend_instruction *const inst = block->start();
|
2016-02-24 19:29:57 -08:00
|
|
|
backend_instruction *const prev_inst = prev_block->end();
|
2013-10-30 10:32:12 -07:00
|
|
|
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
/* ENDIF instructions, by definition, can only be found at the start of
|
2013-10-30 10:32:12 -07:00
|
|
|
* basic blocks.
|
|
|
|
|
*/
|
2016-02-24 19:39:49 -08:00
|
|
|
if (inst->opcode == BRW_OPCODE_ENDIF &&
|
|
|
|
|
prev_inst->opcode == BRW_OPCODE_ELSE) {
|
|
|
|
|
bblock_t *const else_block = prev_block;
|
|
|
|
|
backend_instruction *const else_inst = prev_inst;
|
2014-07-16 15:29:41 -07:00
|
|
|
|
2016-02-24 19:39:49 -08:00
|
|
|
else_inst->remove(else_block);
|
|
|
|
|
progress = true;
|
|
|
|
|
} else if (inst->opcode == BRW_OPCODE_ENDIF &&
|
|
|
|
|
prev_inst->opcode == BRW_OPCODE_IF) {
|
|
|
|
|
bblock_t *const endif_block = block;
|
|
|
|
|
bblock_t *const if_block = prev_block;
|
|
|
|
|
backend_instruction *const endif_inst = inst;
|
|
|
|
|
backend_instruction *const if_inst = prev_inst;
|
2014-07-16 15:29:41 -07:00
|
|
|
|
2016-02-24 19:39:49 -08:00
|
|
|
bblock_t *earlier_block = NULL, *later_block = NULL;
|
2014-07-16 15:29:41 -07:00
|
|
|
|
2016-02-24 19:39:49 -08:00
|
|
|
if (if_block->start_ip == if_block->end_ip) {
|
|
|
|
|
earlier_block = if_block->prev();
|
|
|
|
|
} else {
|
|
|
|
|
earlier_block = if_block;
|
|
|
|
|
}
|
|
|
|
|
if_inst->remove(if_block);
|
2014-07-16 15:29:41 -07:00
|
|
|
|
2016-02-24 19:39:49 -08:00
|
|
|
if (endif_block->start_ip == endif_block->end_ip) {
|
|
|
|
|
later_block = endif_block->next();
|
|
|
|
|
} else {
|
|
|
|
|
later_block = endif_block;
|
|
|
|
|
}
|
|
|
|
|
endif_inst->remove(endif_block);
|
|
|
|
|
|
|
|
|
|
assert((earlier_block == NULL) == (later_block == NULL));
|
|
|
|
|
if (earlier_block && earlier_block->can_combine_with(later_block)) {
|
|
|
|
|
earlier_block->combine_with(later_block);
|
|
|
|
|
|
|
|
|
|
/* If ENDIF was in its own block, then we've now deleted it and
|
|
|
|
|
* merged the two surrounding blocks, the latter of which the
|
|
|
|
|
* __next block pointer was pointing to.
|
|
|
|
|
*/
|
|
|
|
|
if (endif_block != later_block) {
|
|
|
|
|
__next = earlier_block->next();
|
2014-07-16 15:29:41 -07:00
|
|
|
}
|
2016-02-24 18:52:05 -08:00
|
|
|
}
|
2016-02-24 19:39:49 -08:00
|
|
|
|
|
|
|
|
progress = true;
|
2016-02-24 19:11:39 -08:00
|
|
|
} else if (inst->opcode == BRW_OPCODE_ELSE &&
|
|
|
|
|
prev_inst->opcode == BRW_OPCODE_IF) {
|
|
|
|
|
bblock_t *const else_block = block;
|
|
|
|
|
backend_instruction *const if_inst = prev_inst;
|
|
|
|
|
backend_instruction *const else_inst = inst;
|
|
|
|
|
|
|
|
|
|
/* Since the else-branch is becoming the new then-branch, the
|
|
|
|
|
* condition has to be inverted.
|
|
|
|
|
*/
|
|
|
|
|
if_inst->predicate_inverse = !if_inst->predicate_inverse;
|
|
|
|
|
else_inst->remove(else_block);
|
|
|
|
|
|
|
|
|
|
progress = true;
|
2013-10-30 10:32:12 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (progress)
|
2016-03-13 19:26:37 -07:00
|
|
|
s->invalidate_analysis(DEPENDENCY_BLOCKS | DEPENDENCY_INSTRUCTIONS);
|
2013-10-30 10:32:12 -07:00
|
|
|
|
|
|
|
|
return progress;
|
|
|
|
|
}
|