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;