Fix predicating instructions before return in loops.
Only the instructions following a return statement were being marked as
affected by it so predication would be applied. But in a loop the instructions
above the return statement are also affected by it.
Bug b/25220690
Change-Id: If2490a6e0b4e9cf8b6e28b33cbbbcec8b4ebfdaa
Reviewed-on: https://swiftshader-review.googlesource.com/5183
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index d61dcde..a6c5fda 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -1090,14 +1090,14 @@
return opcode == OPCODE_BREAK || opcode == OPCODE_BREAKC || opcode == OPCODE_BREAKP;
}
- bool Shader::Instruction::isLoopOrSwitch() const
+ bool Shader::Instruction::isLoop() const
{
- return opcode == OPCODE_LOOP || opcode == OPCODE_REP || opcode == OPCODE_WHILE || opcode == OPCODE_SWITCH;
+ return opcode == OPCODE_LOOP || opcode == OPCODE_REP || opcode == OPCODE_WHILE;
}
- bool Shader::Instruction::isEndLoopOrSwitch() const
+ bool Shader::Instruction::isEndLoop() const
{
- return opcode == OPCODE_ENDLOOP || opcode == OPCODE_ENDREP || opcode == OPCODE_ENDWHILE || opcode == OPCODE_ENDSWITCH;;
+ return opcode == OPCODE_ENDLOOP || opcode == OPCODE_ENDREP || opcode == OPCODE_ENDWHILE;
}
bool Shader::Instruction::isPredicated() const
@@ -1657,6 +1657,7 @@
int breakDepth = 0;
int continueDepth = 0;
bool leaveReturn = false;
+ unsigned int functionBegin = 0;
for(unsigned int i = 0; i < instruction.size(); i++)
{
@@ -1688,11 +1689,11 @@
if(breakDepth > 0)
{
- if(instruction[i]->isLoopOrSwitch()) // Nested loop or switch, don't make the end of it disable the break execution mask
+ if(instruction[i]->isLoop() || instruction[i]->opcode == OPCODE_SWITCH) // Nested loop or switch, don't make the end of it disable the break execution mask
{
breakDepth++;
}
- else if(instruction[i]->isEndLoopOrSwitch())
+ else if(instruction[i]->isEndLoop() || instruction[i]->opcode == OPCODE_ENDSWITCH)
{
breakDepth--;
}
@@ -1713,11 +1714,11 @@
if(continueDepth > 0)
{
- if(instruction[i]->isLoopOrSwitch()) // Nested loop or switch, don't make the end of it disable the break execution mask
+ if(instruction[i]->isLoop() || instruction[i]->opcode == OPCODE_SWITCH) // Nested loop or switch, don't make the end of it disable the break execution mask
{
continueDepth++;
}
- else if(instruction[i]->isEndLoopOrSwitch())
+ else if(instruction[i]->isEndLoop() || instruction[i]->opcode == OPCODE_ENDSWITCH)
{
continueDepth--;
}
@@ -1734,11 +1735,29 @@
if(instruction[i]->opcode == OPCODE_LEAVE)
{
leaveReturn = true;
+
+ // Mark loop body instructions prior to the return statement
+ for(unsigned int l = functionBegin; l < i; l++)
+ {
+ if(instruction[l]->isLoop())
+ {
+ for(unsigned int r = l + 1; r < i; r++)
+ {
+ instruction[r]->analysisLeave = true;
+ }
+
+ break;
+ }
+ }
}
else if(instruction[i]->opcode == OPCODE_RET) // End of the function
{
leaveReturn = false;
}
+ else if(instruction[i]->opcode == OPCODE_LABEL)
+ {
+ functionBegin = i;
+ }
if(leaveReturn)
{
diff --git a/src/Shader/Shader.hpp b/src/Shader/Shader.hpp
index 404452d..f41d514 100644
--- a/src/Shader/Shader.hpp
+++ b/src/Shader/Shader.hpp
@@ -495,8 +495,8 @@
bool isBranch() const;
bool isCall() const;
bool isBreak() const;
- bool isLoopOrSwitch() const;
- bool isEndLoopOrSwitch() const;
+ bool isLoop() const;
+ bool isEndLoop() const;
bool isPredicated() const;