Improve handling of dead blocks.

All tests pass now.
Still need to handle OpFunction, atomics, OpPhi, etc ...
This commit is contained in:
Hans-Kristian Arntzen 2016-11-17 22:15:07 +01:00
parent dad4a34072
commit edbe867b74
11 changed files with 108 additions and 70 deletions

View File

@ -19,7 +19,6 @@ layout(binding = 1, std430) buffer HeightmapFFT
uvec2 workaround_mix(uvec2 a, uvec2 b, bvec2 sel)
{
uint _137;
uint _148;
if (sel.x)
{
_137 = b.x;
@ -29,6 +28,7 @@ uvec2 workaround_mix(uvec2 a, uvec2 b, bvec2 sel)
_137 = a.x;
}
uint _147 = _137;
uint _148;
if (sel.y)
{
_148 = b.y;

View File

@ -18,9 +18,6 @@ void main()
vec4 idat = _24.in_data[ident];
int k = 0;
uint i = 0u;
uint i_1;
uint j;
int l;
if ((idat.y == 20.0))
{
do
@ -63,10 +60,10 @@ void main()
idat = (idat * 2.0);
k = (k + 1);
}
i_1 = 0u;
uint i_1 = 0u;
for (; (i_1 < 16u); i_1 = (i_1 + uint(1)), k = (k + 1))
{
j = 0u;
uint j = 0u;
for (; (j < 30u); j = (j + uint(1)))
{
idat = (_24.mvp * idat);
@ -93,7 +90,7 @@ void main()
{
k = (k + 1);
} while ((k > 10));
l = 0;
int l = 0;
for (;;)
{
if ((l == 5))

View File

@ -9,7 +9,6 @@ layout(binding = 1, std430) buffer SSBO2
void main()
{
uint ident = gl_GlobalInvocationID.x;
int i;
if ((ident == 2u))
{
_27.out_data[ident] = vec4(20.0);
@ -22,7 +21,7 @@ void main()
return;
}
}
i = 0;
int i = 0;
for (; (i < 20); i = (i + 1))
{
if ((i == 10))

View File

@ -17,8 +17,6 @@ void main()
uint ident = gl_GlobalInvocationID.x;
vec4 idat = _24.in_data[ident];
int k = 0;
uint i;
uint j;
for (;;)
{
int _39 = k;
@ -35,10 +33,10 @@ void main()
break;
}
}
i = 0u;
uint i = 0u;
for (; (i < 16u); i = (i + uint(1)), k = (k + 1))
{
j = 0u;
uint j = 0u;
for (; (j < 30u); j = (j + uint(1)))
{
idat = (_24.mvp * idat);

View File

@ -15,7 +15,6 @@ void main()
bool f = true;
FragColor = vec4(mix(vIn2, vIn3, f));
highp vec4 _35;
highp float _44;
if (f)
{
_35 = vIn0;
@ -25,6 +24,7 @@ void main()
_35 = vIn1;
}
FragColor = _35;
highp float _44;
if (f)
{
_44 = vIn2;

View File

@ -99,7 +99,6 @@ void main()
{
vec2 p0 = vPatchPosBase[0];
vec2 param = p0;
vec2 param_1;
if ((!frustum_cull(param)))
{
gl_TessLevelOuter[0] = -1.0;
@ -111,7 +110,7 @@ void main()
}
else
{
param_1 = p0;
vec2 param_1 = p0;
compute_tess_levels(param_1);
}
}

View File

@ -58,10 +58,7 @@ vec2 warp_position()
uint ufloor_lod = uint(floor_lod);
uvec2 uPosition = uvec2(Position);
uvec2 mask = ((uvec2(1u) << uvec2(ufloor_lod, (ufloor_lod + 1u))) - uvec2(1u));
uvec2 rounding;
uint _332;
uint _343;
vec4 lower_upper_snapped;
if ((uPosition.x < 32u))
{
_332 = mask.x;
@ -71,6 +68,7 @@ vec2 warp_position()
_332 = 0u;
}
uint _342 = _332;
uint _343;
if ((uPosition.y < 32u))
{
_343 = mask.y;
@ -79,8 +77,8 @@ vec2 warp_position()
{
_343 = 0u;
}
rounding = uvec2(_342, _343);
lower_upper_snapped = vec4(((uPosition + rounding).xyxy & (~mask).xxyy));
uvec2 rounding = uvec2(_342, _343);
vec4 lower_upper_snapped = vec4(((uPosition + rounding).xyxy & (~mask).xxyy));
return mix(lower_upper_snapped.xy, lower_upper_snapped.zw, vec2(fract_lod));
}

View File

@ -59,12 +59,7 @@ vec2 warp_position()
uint ufloor_lod = uint(floor_lod);
uvec4 uPosition = uvec4(Position);
uvec2 mask = ((uvec2(1u) << uvec2(ufloor_lod, (ufloor_lod + 1u))) - uvec2(1u));
uvec4 rounding;
uint _333;
uint _345;
uint _356;
uint _368;
vec4 lower_upper_snapped;
if ((uPosition.x < 32u))
{
_333 = mask.x;
@ -73,7 +68,9 @@ vec2 warp_position()
{
_333 = 0u;
}
uvec4 rounding;
rounding.x = _333;
uint _345;
if ((uPosition.y < 32u))
{
_345 = mask.x;
@ -83,6 +80,7 @@ vec2 warp_position()
_345 = 0u;
}
rounding.y = _345;
uint _356;
if ((uPosition.x < 32u))
{
_356 = mask.y;
@ -92,6 +90,7 @@ vec2 warp_position()
_356 = 0u;
}
rounding.z = _356;
uint _368;
if ((uPosition.y < 32u))
{
_368 = mask.y;
@ -101,7 +100,7 @@ vec2 warp_position()
_368 = 0u;
}
rounding.w = _368;
lower_upper_snapped = vec4(((uPosition.xyxy + rounding) & (~mask).xxyy));
vec4 lower_upper_snapped = vec4(((uPosition.xyxy + rounding) & (~mask).xxyy));
return mix(lower_upper_snapped.xy, lower_upper_snapped.zw, vec2(fract_lod));
}

View File

@ -16,47 +16,21 @@
#include "spirv_cfg.hpp"
#include <algorithm>
#include <assert.h>
using namespace std;
namespace spirv_cross
{
CFG::CFG(Compiler &compiler_, const SPIRFunction &func_)
: compiler(compiler_), func(func_)
: compiler(compiler_)
, func(func_)
{
preceding_edges.resize(compiler.get_current_id_bound());
succeeding_edges.resize(compiler.get_current_id_bound());
visit_order.resize(compiler.get_current_id_bound());
immediate_dominators.resize(compiler.get_current_id_bound());
// Set up all edges between blocks.
for (auto block_id : func.blocks)
{
auto &block = compiler.get<SPIRBlock>(block_id);
switch (block.terminator)
{
case SPIRBlock::Direct:
add_branch(block.self, block.next_block);
break;
case SPIRBlock::Select:
add_branch(block.self, block.true_block);
add_branch(block.self, block.false_block);
break;
case SPIRBlock::MultiSelect:
for (auto &target : block.cases)
add_branch(block.self, target.block);
if (block.default_block)
add_branch(block.self, block.default_block);
break;
default:
break;
}
}
build_post_order_visit_order();
build_immediate_dominators();
}
@ -98,28 +72,58 @@ void CFG::build_immediate_dominators()
{
if (!immediate_dominators[block])
immediate_dominators[block] = edge;
else if (immediate_dominators[block] && immediate_dominators[edge])
else
{
assert(immediate_dominators[edge]);
immediate_dominators[block] = update_common_dominator(block, edge);
}
}
}
}
void CFG::post_order_visit(uint32_t block)
bool CFG::post_order_visit(uint32_t block_id)
{
// If we have already branched to this block (back edge), stop recursion.
if (visit_order[block] >= 0)
return;
if (visit_order[block_id] >= 0)
return false;
// Block back-edges from recursively revisiting ourselves.
visit_order[block] = 0;
visit_order[block_id] = 0;
// First visit our branch targets.
auto &succeeding = succeeding_edges[block];
for (auto &id : succeeding)
post_order_visit(id);
auto &block = compiler.get<SPIRBlock>(block_id);
switch (block.terminator)
{
case SPIRBlock::Direct:
if (post_order_visit(block.next_block))
add_branch(block_id, block.next_block);
break;
case SPIRBlock::Select:
if (post_order_visit(block.true_block))
add_branch(block_id, block.true_block);
if (post_order_visit(block.false_block))
add_branch(block_id, block.false_block);
break;
case SPIRBlock::MultiSelect:
for (auto &target : block.cases)
{
if (post_order_visit(target.block))
add_branch(block_id, target.block);
}
if (block.default_block && post_order_visit(block.default_block))
add_branch(block_id, block.default_block);
break;
default:
break;
}
// Then visit ourselves.
visit_order[block] = visit_count++;
post_order.push_back(block);
visit_order[block_id] = visit_count++;
post_order.push_back(block_id);
return true;
}
void CFG::build_post_order_visit_order()
@ -143,12 +147,18 @@ void CFG::add_branch(uint32_t from, uint32_t to)
}
DominatorBuilder::DominatorBuilder(const CFG &cfg_)
: cfg(cfg_)
: cfg(cfg_)
{
}
void DominatorBuilder::add_block(uint32_t block)
{
if (!cfg.get_immediate_dominator(block))
{
// Unreachable block via the CFG, we will never emit this code anyways.
return;
}
if (!dominator)
{
dominator = block;

View File

@ -55,7 +55,7 @@ private:
void add_branch(uint32_t from, uint32_t to);
void build_post_order_visit_order();
void build_immediate_dominators();
void post_order_visit(uint32_t block);
bool post_order_visit(uint32_t block);
uint32_t visit_count = 0;
uint32_t update_common_dominator(uint32_t a, uint32_t b);

View File

@ -2734,6 +2734,39 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
void set_current_block(const SPIRBlock &block)
{
current_block = &block;
// If we're branching to a block which uses OpPhi, in GLSL
// this will be a variable write when we branch,
// so we need to track access to these variables as well to
// have a complete picture.
const auto test_phi = [this, &block](uint32_t to) {
auto &next = compiler.get<SPIRBlock>(to);
for (auto &phi : next.phi_variables)
if (phi.parent == block.self)
accessed_variables_to_block[phi.function_variable].insert(block.self);
};
switch (block.terminator)
{
case SPIRBlock::Direct:
test_phi(block.next_block);
break;
case SPIRBlock::Select:
test_phi(block.true_block);
test_phi(block.false_block);
break;
case SPIRBlock::MultiSelect:
for (auto &target : block.cases)
test_phi(target.block);
if (block.default_block)
test_phi(block.default_block);
break;
default:
break;
}
}
bool handle(spv::Op op, const uint32_t *args, uint32_t length)
@ -2808,7 +2841,12 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
// Add it to a per-block list of variables.
uint32_t dominating_block = builder.get_dominator();
auto &block = get<SPIRBlock>(dominating_block);
block.dominated_variables.push_back(var.first);
// If all blocks here are dead code, this will be 0, so the variable in question
// will be completely eliminated.
if (dominating_block)
{
auto &block = get<SPIRBlock>(dominating_block);
block.dominated_variables.push_back(var.first);
}
}
}