Detect functions that fail to return a value, without using CFG.
This check now runs at function finalization time, before constant propagation has occurred; this affected the "DeadIfStatement" test. Our detection isn't smart enough to realize that a loop will run zero times, so it treats `for` and `while` loops as always running at least once. This isn't strictly correct, but it actually mirrors how the CFG implementation works anyway. The only downside is that we would not flag code like `for (i=0; i<0; ++i) { return x; }` as an error. Change-Id: I5e43a6ee3a3993045559f0fb0646d36112543a94 Bug: skia:11377 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/379056 Commit-Queue: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
daed2592bb
commit
b3dcbb12ef
@ -397,6 +397,8 @@ sksl_shared_tests = [
|
||||
"/sksl/shared/ResizeMatrixNonsquare.sksl",
|
||||
"/sksl/shared/ReturnBadTypeFromMain.sksl",
|
||||
"/sksl/shared/ReturnColorFromMain.sksl",
|
||||
"/sksl/shared/ReturnsValueOnEveryPathES2.sksl",
|
||||
"/sksl/shared/ReturnsValueOnEveryPathES3.sksl",
|
||||
"/sksl/shared/SampleLocations.vert",
|
||||
"/sksl/shared/SampleMask.sksl",
|
||||
"/sksl/shared/ScalarConversionConstructorsES2.sksl",
|
||||
|
@ -1,4 +1,98 @@
|
||||
// Expect 1 error
|
||||
/*#pragma settings NoControlFlowAnalysis*/
|
||||
|
||||
int not_detected() { if (sqrt(1) == 1) return 3; } // function finalizer doesn't analyze all paths
|
||||
int is_detected() { if (2 > 5) return 3; } // optimizer reduces this to an empty function
|
||||
// Expect 17 errors
|
||||
|
||||
int variable = 0;
|
||||
uniform half mystery;
|
||||
|
||||
int if_only() { if (variable == 1) return 0; }
|
||||
int return_on_if_but_not_else() { if (variable == 1) return 0; else variable *= 2; }
|
||||
int return_on_else_but_not_if() { if (variable == 1) variable *= 2; else return 1; }
|
||||
|
||||
int for_with_conditional_return() { for (;;) { if (variable == 1) return 0; } }
|
||||
int for_with_conditional_break() { for (;;) { if (variable == 1) break; return 0; } }
|
||||
int for_with_conditional_continue() { for (;;) { if (variable == 1) continue; return 0; } }
|
||||
|
||||
bool bad_if_else_chain() {
|
||||
if (mystery == 1)
|
||||
return true;
|
||||
else if (mystery == 2)
|
||||
return false;
|
||||
else if (mystery == 3)
|
||||
return true;
|
||||
else if (mystery == 4)
|
||||
variable *= 2; // doesn't return
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool conditional_inside_do_loop() {
|
||||
do {
|
||||
if (mystery == 123) return true;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
int switch_empty() {
|
||||
switch (variable) {}
|
||||
}
|
||||
|
||||
int switch_with_no_default() {
|
||||
switch (variable) {
|
||||
case 1: return 1;
|
||||
case 2: return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_break() {
|
||||
switch (variable) {
|
||||
case 1: return 1;
|
||||
case 2: break;
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_continue() {
|
||||
for (;;) switch (variable) {
|
||||
case 1: return 1;
|
||||
case 2: return 2;
|
||||
default: continue;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_fallthrough_off_bottom() {
|
||||
switch (variable) {
|
||||
case 1: return 1;
|
||||
case 2: return 2;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_conditional_break() {
|
||||
switch (variable) {
|
||||
case 1: if (mystery == 123) break; return 1;
|
||||
case 2: return 2;
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_conditional_continue() {
|
||||
for (;;) switch (variable) {
|
||||
case 1: if (mystery == 123) ; else continue; return 1;
|
||||
case 2: return 2;
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_conditional_if_then_return() {
|
||||
switch (variable) {
|
||||
case 1: if (mystery == 123) break; return 1;
|
||||
default: return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int switch_with_conditional_break_then_fallthrough() {
|
||||
switch (variable) {
|
||||
case 1: if (mystery == 123) {} else break;
|
||||
default: return 2;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform half4 colorGreen, colorRed;
|
||||
|
||||
half4 main() {
|
||||
bool x = true;
|
||||
if (x) return colorGreen;
|
||||
const bool x = true;
|
||||
if (!x) return colorRed;
|
||||
if (x) return colorGreen;
|
||||
}
|
||||
|
47
resources/sksl/shared/ReturnsValueOnEveryPathES2.sksl
Normal file
47
resources/sksl/shared/ReturnsValueOnEveryPathES2.sksl
Normal file
@ -0,0 +1,47 @@
|
||||
uniform half4 colorGreen, colorRed;
|
||||
uniform half unknownInput; // = 1
|
||||
|
||||
bool simple() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool return_on_both_sides() {
|
||||
if (unknownInput == 1) return true; else return true;
|
||||
}
|
||||
|
||||
bool for_inside_body() {
|
||||
for (int x=0; x<=10; ++x) { return true; }
|
||||
}
|
||||
|
||||
bool after_for_body() {
|
||||
for (int x=0; x<=10; ++x) { simple(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool for_with_double_sided_conditional_return() {
|
||||
for (int x=0; x<=10; ++x) {
|
||||
if (unknownInput == 1) return true; else return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool if_else_chain() {
|
||||
if (unknownInput == 1)
|
||||
return true;
|
||||
else if (unknownInput == 2)
|
||||
return false;
|
||||
else if (unknownInput == 3)
|
||||
return true;
|
||||
else if (unknownInput == 4)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
half4 main() {
|
||||
return simple() &&
|
||||
return_on_both_sides() &&
|
||||
for_inside_body() &&
|
||||
after_for_body() &&
|
||||
for_with_double_sided_conditional_return() &&
|
||||
if_else_chain() ? colorGreen : colorRed;
|
||||
}
|
152
resources/sksl/shared/ReturnsValueOnEveryPathES3.sksl
Normal file
152
resources/sksl/shared/ReturnsValueOnEveryPathES3.sksl
Normal file
@ -0,0 +1,152 @@
|
||||
/*#pragma settings NoControlFlowAnalysis*/
|
||||
|
||||
uniform half4 colorGreen, colorRed;
|
||||
uniform half unknownInput; // = 1
|
||||
|
||||
bool simple() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool return_on_both_sides() {
|
||||
if (unknownInput == 1) return true; else return true;
|
||||
}
|
||||
|
||||
bool for_inside_body() {
|
||||
for (int x=0; x<=10; ++x) { return true; }
|
||||
}
|
||||
|
||||
bool after_for_body() {
|
||||
for (int x=0; x<=10; ++x) { simple(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool for_with_double_sided_conditional_return() {
|
||||
for (int x=0; x<=10; ++x) {
|
||||
if (unknownInput == 1) return true; else return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool if_else_chain() {
|
||||
if (unknownInput == 1)
|
||||
return true;
|
||||
else if (unknownInput == 2)
|
||||
return false;
|
||||
else if (unknownInput == 3)
|
||||
return true;
|
||||
else if (unknownInput == 4)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool conditional_inside_while_loop() {
|
||||
while (unknownInput == 123) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool inside_do_loop() {
|
||||
do {
|
||||
return true;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
bool inside_while_loop() {
|
||||
while (true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool after_do_loop() {
|
||||
do {
|
||||
break;
|
||||
} while (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool after_while_loop() {
|
||||
while (true) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool switch_with_all_returns() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: return true;
|
||||
case 2: return true;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_only_default() {
|
||||
switch (int(unknownInput)) {
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_fallthrough() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: return true;
|
||||
case 2:
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_fallthrough_twice() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
case 2:
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_with_break_in_loop() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: for (int x=0; x<=10; ++x) { break; }
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_with_continue_in_loop() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: for (int x=0; x<=10; ++x) { continue; }
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_with_if_that_returns() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: if (unknownInput == 123) return true; else return true;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_with_one_sided_if_then_fallthrough() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1: if (unknownInput == 123) return true;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
half4 main() {
|
||||
return simple() &&
|
||||
return_on_both_sides() &&
|
||||
for_inside_body() &&
|
||||
after_for_body() &&
|
||||
for_with_double_sided_conditional_return() &&
|
||||
if_else_chain() &&
|
||||
conditional_inside_while_loop() &&
|
||||
inside_do_loop() &&
|
||||
inside_while_loop() &&
|
||||
after_do_loop() &&
|
||||
after_while_loop() &&
|
||||
switch_with_all_returns() &&
|
||||
switch_only_default() &&
|
||||
switch_fallthrough() &&
|
||||
switch_fallthrough_twice() &&
|
||||
switch_with_break_in_loop() &&
|
||||
switch_with_continue_in_loop() &&
|
||||
switch_with_if_that_returns() &&
|
||||
switch_with_one_sided_if_then_fallthrough() ? colorGreen : colorRed;
|
||||
}
|
@ -392,6 +392,143 @@ public:
|
||||
using INHERITED = ProgramVisitor;
|
||||
};
|
||||
|
||||
class ReturnsOnAllPathsVisitor : public ProgramVisitor {
|
||||
public:
|
||||
bool visitExpression(const Expression& expr) override {
|
||||
// We can avoid processing expressions entirely.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visitStatement(const Statement& stmt) override {
|
||||
switch (stmt.kind()) {
|
||||
// Returns, breaks, or continues will stop the scan, so only one of these should ever be
|
||||
// true.
|
||||
case Statement::Kind::kReturn:
|
||||
fFoundReturn = true;
|
||||
return true;
|
||||
|
||||
case Statement::Kind::kBreak:
|
||||
fFoundBreak = true;
|
||||
return true;
|
||||
|
||||
case Statement::Kind::kContinue:
|
||||
fFoundContinue = true;
|
||||
return true;
|
||||
|
||||
case Statement::Kind::kIf: {
|
||||
const IfStatement& i = stmt.as<IfStatement>();
|
||||
ReturnsOnAllPathsVisitor trueVisitor;
|
||||
ReturnsOnAllPathsVisitor falseVisitor;
|
||||
trueVisitor.visitStatement(*i.ifTrue());
|
||||
if (i.ifFalse()) {
|
||||
falseVisitor.visitStatement(*i.ifFalse());
|
||||
}
|
||||
// If either branch leads to a break or continue, we report the entire if as
|
||||
// containing a break or continue, since we don't know which side will be reached.
|
||||
fFoundBreak = (trueVisitor.fFoundBreak || falseVisitor.fFoundBreak);
|
||||
fFoundContinue = (trueVisitor.fFoundContinue || falseVisitor.fFoundContinue);
|
||||
// On the other hand, we only want to report returns that definitely happen, so we
|
||||
// require those to be found on both sides.
|
||||
fFoundReturn = (trueVisitor.fFoundReturn && falseVisitor.fFoundReturn);
|
||||
return fFoundBreak || fFoundContinue || fFoundReturn;
|
||||
}
|
||||
case Statement::Kind::kFor: {
|
||||
const ForStatement& f = stmt.as<ForStatement>();
|
||||
// We assume a for/while loop runs for at least one iteration; this isn't strictly
|
||||
// guaranteed, but it's better to be slightly over-permissive here than to fail on
|
||||
// reasonable code.
|
||||
ReturnsOnAllPathsVisitor forVisitor;
|
||||
forVisitor.visitStatement(*f.statement());
|
||||
// A for loop that contains a break or continue is safe; it won't exit the entire
|
||||
// function, just the loop. So we disregard those signals.
|
||||
fFoundReturn = forVisitor.fFoundReturn;
|
||||
return fFoundReturn;
|
||||
}
|
||||
case Statement::Kind::kDo: {
|
||||
const DoStatement& d = stmt.as<DoStatement>();
|
||||
// Do-while blocks are always entered at least once.
|
||||
ReturnsOnAllPathsVisitor doVisitor;
|
||||
doVisitor.visitStatement(*d.statement());
|
||||
// A do-while loop that contains a break or continue is safe; it won't exit the
|
||||
// entire function, just the loop. So we disregard those signals.
|
||||
fFoundReturn = doVisitor.fFoundReturn;
|
||||
return fFoundReturn;
|
||||
}
|
||||
case Statement::Kind::kBlock:
|
||||
// Blocks are definitely entered and don't imply any additional control flow.
|
||||
// If the block contains a break, continue or return, we want to keep that.
|
||||
return INHERITED::visitStatement(stmt);
|
||||
|
||||
case Statement::Kind::kSwitch: {
|
||||
// Switches are the most complex control flow we need to deal with; fortunately we
|
||||
// already have good primitives for dissecting them. We need to verify that:
|
||||
// - a default case exists, so that every possible input value is covered
|
||||
// - every switch-case either (a) returns unconditionally, or
|
||||
// (b) falls through to another case that does
|
||||
const SwitchStatement& s = stmt.as<SwitchStatement>();
|
||||
bool foundDefault = false;
|
||||
bool fellThrough = false;
|
||||
for (const std::unique_ptr<SwitchCase>& sc : s.cases()) {
|
||||
// The default case is indicated by a null value. A switch without a default
|
||||
// case cannot definitively return, as its value might not be in the cases list.
|
||||
if (!sc->value()) {
|
||||
foundDefault = true;
|
||||
}
|
||||
// Scan this switch-case for any exit (break, continue or return).
|
||||
ReturnsOnAllPathsVisitor caseVisitor;
|
||||
caseVisitor.visitStatement(*sc);
|
||||
|
||||
// If we found a break or continue, whether conditional or not, this switch case
|
||||
// can't be called an unconditional return. Switches absorb breaks but not
|
||||
// continues.
|
||||
if (caseVisitor.fFoundContinue) {
|
||||
fFoundContinue = true;
|
||||
return false;
|
||||
}
|
||||
if (caseVisitor.fFoundBreak) {
|
||||
return false;
|
||||
}
|
||||
// We just confirmed that there weren't any breaks or continues. If we didn't
|
||||
// find an unconditional return either, the switch is considered fallen-through.
|
||||
// (There might be a conditional return, but that doesn't count.)
|
||||
fellThrough = !caseVisitor.fFoundReturn;
|
||||
}
|
||||
|
||||
// If we didn't find a default case, or the very last case fell through, this switch
|
||||
// doesn't meet our criteria.
|
||||
if (fellThrough || !foundDefault) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We scanned the entire switch, found a default case, and every section either fell
|
||||
// through or contained an unconditional return.
|
||||
fFoundReturn = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Statement::Kind::kSwitchCase:
|
||||
// Recurse into the switch-case.
|
||||
return INHERITED::visitStatement(stmt);
|
||||
|
||||
case Statement::Kind::kDiscard:
|
||||
case Statement::Kind::kExpression:
|
||||
case Statement::Kind::kInlineMarker:
|
||||
case Statement::Kind::kNop:
|
||||
case Statement::Kind::kVarDeclaration:
|
||||
// None of these statements could contain a return.
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fFoundReturn = false;
|
||||
bool fFoundBreak = false;
|
||||
bool fFoundContinue = false;
|
||||
|
||||
using INHERITED = ProgramVisitor;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -906,6 +1043,12 @@ bool Analysis::IsConstantExpression(const Expression& expr) {
|
||||
return !visitor.visitExpression(expr);
|
||||
}
|
||||
|
||||
bool Analysis::CanExitWithoutReturningValue(const FunctionDefinition& funcDef) {
|
||||
ReturnsOnAllPathsVisitor visitor;
|
||||
visitor.visitStatement(*funcDef.body());
|
||||
return !visitor.fFoundReturn;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ProgramVisitor
|
||||
|
||||
|
@ -48,6 +48,13 @@ struct Analysis {
|
||||
*/
|
||||
static bool SwitchCaseContainsUnconditionalExit(Statement& stmt);
|
||||
|
||||
/**
|
||||
* A switch-case "falls through" when it doesn't have an unconditional exit.
|
||||
*/
|
||||
static bool SwitchCaseFallsThrough(Statement& stmt) {
|
||||
return !SwitchCaseContainsUnconditionalExit(stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds conditional exits from a switch-case. Returns true if this statement contains a
|
||||
* conditional that wraps a potential exit from the switch (via continue, break or return).
|
||||
@ -127,6 +134,9 @@ struct Analysis {
|
||||
ErrorReporter* errors);
|
||||
|
||||
static void ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors);
|
||||
|
||||
// Detects functions that fail to return a value on at least one path.
|
||||
static bool CanExitWithoutReturningValue(const FunctionDefinition& funcDef);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -931,24 +931,12 @@ void IRGenerator::finalizeFunction(FunctionDefinition& f) {
|
||||
~Finalizer() override {
|
||||
SkASSERT(!fBreakableLevel);
|
||||
SkASSERT(!fContinuableLevel);
|
||||
|
||||
if (!fEncounteredReturnValue && this->functionReturnsValue()) {
|
||||
// It's a non-void function, but it never created a result expression--that is, it
|
||||
// never returned anything.
|
||||
fIRGenerator->errorReporter().error(
|
||||
fFunction->fOffset,
|
||||
"function '" + fFunction->name() + "' exits without returning a value");
|
||||
}
|
||||
}
|
||||
|
||||
bool functionReturnsValue() const {
|
||||
return fFunction->returnType() != *fIRGenerator->fContext.fTypes.fVoid;
|
||||
}
|
||||
|
||||
bool encounteredReturnValue() const {
|
||||
return fEncounteredReturnValue;
|
||||
}
|
||||
|
||||
bool visitStatement(Statement& stmt) override {
|
||||
switch (stmt.kind()) {
|
||||
case Statement::Kind::kReturn: {
|
||||
@ -968,7 +956,6 @@ void IRGenerator::finalizeFunction(FunctionDefinition& f) {
|
||||
// Coerce return expression to the function's return type.
|
||||
returnStmt.setExpression(fIRGenerator->coerce(
|
||||
std::move(returnStmt.expression()), returnType));
|
||||
fEncounteredReturnValue = true;
|
||||
} else {
|
||||
// Returning something from a function with a void return type.
|
||||
fIRGenerator->errorReporter().error(returnStmt.fOffset,
|
||||
@ -1023,12 +1010,17 @@ void IRGenerator::finalizeFunction(FunctionDefinition& f) {
|
||||
int fBreakableLevel = 0;
|
||||
// how deeply nested we are in continuable constructs (for, do).
|
||||
int fContinuableLevel = 0;
|
||||
// have we found a return statement with a return value?
|
||||
bool fEncounteredReturnValue = false;
|
||||
|
||||
using INHERITED = ProgramWriter;
|
||||
};
|
||||
Finalizer(this, &f.declaration()).visitStatement(*f.body());
|
||||
|
||||
Finalizer finalizer{this, &f.declaration()};
|
||||
finalizer.visitStatement(*f.body());
|
||||
|
||||
if (finalizer.functionReturnsValue() && Analysis::CanExitWithoutReturningValue(f)) {
|
||||
this->errorReporter().error(f.fOffset, "function '" + f.declaration().name() +
|
||||
"' can exit without returning a value");
|
||||
}
|
||||
}
|
||||
|
||||
void IRGenerator::convertFunction(const ASTNode& f) {
|
||||
|
@ -1066,14 +1066,23 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLFunction, r, ctxInfo) {
|
||||
}
|
||||
|
||||
{
|
||||
ExpectError error(r, "error: expected function to return 'float'\n"
|
||||
"error: function 'broken' exits without returning a value\n");
|
||||
ExpectError error(r, "error: expected function to return 'float'\n");
|
||||
DSLWriter::ProgramElements().clear();
|
||||
DSLFunction(kFloat, "broken").define(
|
||||
Return()
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
ExpectError error(r, "error: function 'broken' can exit without returning a value\n");
|
||||
DSLWriter::ProgramElements().clear();
|
||||
Var x(kFloat, "x");
|
||||
DSLFunction(kFloat, "broken").define(
|
||||
Declare(x, 0),
|
||||
If(x == 1, Return(x))
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
ExpectError error(r, "error: may not return a value from a void function\n");
|
||||
DSLWriter::ProgramElements().clear();
|
||||
@ -1082,14 +1091,12 @@ DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLFunction, r, ctxInfo) {
|
||||
);
|
||||
}
|
||||
|
||||
/* TODO: detect this case
|
||||
{
|
||||
ExpectError error(r, "error: expected function to return 'float'\n");
|
||||
ExpectError error(r, "error: function 'broken' can exit without returning a value\n");
|
||||
DSLWriter::ProgramElements().clear();
|
||||
DSLFunction(kFloat, "broken").define(
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLIf, r, ctxInfo) {
|
||||
|
@ -170,6 +170,7 @@ SKSL_TEST(SkSLOperatorsES2, "shared/OperatorsES2.sksl")
|
||||
SKSL_TEST(SkSLOutParams, "shared/OutParams.sksl")
|
||||
SKSL_TEST(SkSLOutParamsTricky, "shared/OutParamsTricky.sksl")
|
||||
SKSL_TEST(SkSLResizeMatrix, "shared/ResizeMatrix.sksl")
|
||||
SKSL_TEST(SkSLReturnsValueOnEveryPathES2, "shared/ReturnsValueOnEveryPathES2.sksl")
|
||||
SKSL_TEST(SkSLScalarConversionConstructorsES2, "shared/ScalarConversionConstructorsES2.sksl")
|
||||
SKSL_TEST(SkSLStackingVectorCasts, "shared/StackingVectorCasts.sksl")
|
||||
SKSL_TEST(SkSLStaticIf, "shared/StaticIf.sksl")
|
||||
@ -213,6 +214,7 @@ SKSL_TEST(SkSLHexUnsigned, "shared/HexUnsigned.sksl")
|
||||
SKSL_TEST(SkSLMatricesNonsquare, "shared/MatricesNonsquare.sksl")
|
||||
SKSL_TEST(SkSLOperatorsES3, "shared/OperatorsES3.sksl")
|
||||
SKSL_TEST(SkSLResizeMatrixNonsquare, "shared/ResizeMatrixNonsquare.sksl")
|
||||
SKSL_TEST(SkSLReturnsValueOnEveryPathES3, "shared/ReturnsValueOnEveryPathES3.sksl")
|
||||
SKSL_TEST(SkSLScalarConversionConstructorsES3, "shared/ScalarConversionConstructorsES3.sksl")
|
||||
SKSL_TEST(SkSLSwizzleByIndex, "shared/SwizzleByIndex.sksl")
|
||||
SKSL_TEST(SkSLWhileLoopControlFlow, "shared/WhileLoopControlFlow.sksl")
|
||||
|
@ -1,4 +1,20 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 4: function 'is_detected' exits without returning a value
|
||||
1 error
|
||||
error: 8: function 'if_only' can exit without returning a value
|
||||
error: 9: function 'return_on_if_but_not_else' can exit without returning a value
|
||||
error: 10: function 'return_on_else_but_not_if' can exit without returning a value
|
||||
error: 12: function 'for_with_conditional_return' can exit without returning a value
|
||||
error: 13: function 'for_with_conditional_break' can exit without returning a value
|
||||
error: 14: function 'for_with_conditional_continue' can exit without returning a value
|
||||
error: 16: function 'bad_if_else_chain' can exit without returning a value
|
||||
error: 29: function 'conditional_inside_do_loop' can exit without returning a value
|
||||
error: 35: function 'switch_empty' can exit without returning a value
|
||||
error: 39: function 'switch_with_no_default' can exit without returning a value
|
||||
error: 46: function 'switch_with_break' can exit without returning a value
|
||||
error: 54: function 'switch_with_continue' can exit without returning a value
|
||||
error: 62: function 'switch_with_fallthrough_off_bottom' can exit without returning a value
|
||||
error: 70: function 'switch_with_conditional_break' can exit without returning a value
|
||||
error: 78: function 'switch_with_conditional_continue' can exit without returning a value
|
||||
error: 86: function 'switch_with_conditional_if_then_return' can exit without returning a value
|
||||
error: 93: function 'switch_with_conditional_break_then_fallthrough' can exit without returning a value
|
||||
17 errors
|
||||
|
@ -1,4 +1,4 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: function 'n' exits without returning a value
|
||||
error: 1: function 'n' can exit without returning a value
|
||||
1 error
|
||||
|
@ -1,5 +1,4 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: expected function to return 'int'
|
||||
error: 1: function 'foo' exits without returning a value
|
||||
2 errors
|
||||
1 error
|
||||
|
262
tests/sksl/shared/ReturnsValueOnEveryPathES2.asm.frag
Normal file
262
tests/sksl/shared/ReturnsValueOnEveryPathES2.asm.frag
Normal file
@ -0,0 +1,262 @@
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %_entrypoint "_entrypoint" %sk_FragColor %sk_Clockwise
|
||||
OpExecutionMode %_entrypoint OriginUpperLeft
|
||||
OpName %sk_FragColor "sk_FragColor"
|
||||
OpName %sk_Clockwise "sk_Clockwise"
|
||||
OpName %_UniformBuffer "_UniformBuffer"
|
||||
OpMemberName %_UniformBuffer 0 "colorGreen"
|
||||
OpMemberName %_UniformBuffer 1 "colorRed"
|
||||
OpMemberName %_UniformBuffer 2 "unknownInput"
|
||||
OpName %_entrypoint "_entrypoint"
|
||||
OpName %for_inside_body "for_inside_body"
|
||||
OpName %x "x"
|
||||
OpName %after_for_body "after_for_body"
|
||||
OpName %x_0 "x"
|
||||
OpName %for_with_double_sided_conditional_return "for_with_double_sided_conditional_return"
|
||||
OpName %x_1 "x"
|
||||
OpName %if_else_chain "if_else_chain"
|
||||
OpName %main "main"
|
||||
OpName %_0_return_on_both_sides "_0_return_on_both_sides"
|
||||
OpDecorate %sk_FragColor RelaxedPrecision
|
||||
OpDecorate %sk_FragColor Location 0
|
||||
OpDecorate %sk_FragColor Index 0
|
||||
OpDecorate %sk_Clockwise RelaxedPrecision
|
||||
OpDecorate %sk_Clockwise BuiltIn FrontFacing
|
||||
OpMemberDecorate %_UniformBuffer 0 Offset 0
|
||||
OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
|
||||
OpMemberDecorate %_UniformBuffer 1 Offset 16
|
||||
OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
|
||||
OpMemberDecorate %_UniformBuffer 2 Offset 32
|
||||
OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
|
||||
OpDecorate %_UniformBuffer Block
|
||||
OpDecorate %14 Binding 0
|
||||
OpDecorate %14 DescriptorSet 0
|
||||
OpDecorate %63 RelaxedPrecision
|
||||
OpDecorate %73 RelaxedPrecision
|
||||
OpDecorate %79 RelaxedPrecision
|
||||
OpDecorate %87 RelaxedPrecision
|
||||
OpDecorate %94 RelaxedPrecision
|
||||
OpDecorate %105 RelaxedPrecision
|
||||
OpDecorate %110 RelaxedPrecision
|
||||
OpDecorate %134 RelaxedPrecision
|
||||
OpDecorate %136 RelaxedPrecision
|
||||
OpDecorate %137 RelaxedPrecision
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%sk_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Input_bool = OpTypePointer Input %bool
|
||||
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
|
||||
%_UniformBuffer = OpTypeStruct %v4float %v4float %float
|
||||
%_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
|
||||
%14 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
|
||||
%void = OpTypeVoid
|
||||
%19 = OpTypeFunction %void
|
||||
%22 = OpTypeFunction %bool
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%true = OpConstantTrue %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%int_2 = OpConstant %int 2
|
||||
%float_1 = OpConstant %float 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%false = OpConstantFalse %bool
|
||||
%float_3 = OpConstant %float 3
|
||||
%float_4 = OpConstant %float 4
|
||||
%100 = OpTypeFunction %v4float
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
|
||||
%_entrypoint = OpFunction %void None %19
|
||||
%20 = OpLabel
|
||||
%21 = OpFunctionCall %v4float %main
|
||||
OpStore %sk_FragColor %21
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%for_inside_body = OpFunction %bool None %22
|
||||
%23 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x %int_0
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
OpLoopMerge %32 %31 None
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%33 = OpLoad %int %x
|
||||
%35 = OpSLessThanEqual %bool %33 %int_10
|
||||
OpBranchConditional %35 %30 %32
|
||||
%30 = OpLabel
|
||||
OpReturnValue %true
|
||||
%31 = OpLabel
|
||||
%38 = OpLoad %int %x
|
||||
%39 = OpIAdd %int %38 %int_1
|
||||
OpStore %x %39
|
||||
OpBranch %28
|
||||
%32 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%after_for_body = OpFunction %bool None %22
|
||||
%40 = OpLabel
|
||||
%x_0 = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x_0 %int_0
|
||||
OpBranch %42
|
||||
%42 = OpLabel
|
||||
OpLoopMerge %46 %45 None
|
||||
OpBranch %43
|
||||
%43 = OpLabel
|
||||
%47 = OpLoad %int %x_0
|
||||
%48 = OpSLessThanEqual %bool %47 %int_10
|
||||
OpBranchConditional %48 %44 %46
|
||||
%44 = OpLabel
|
||||
OpBranch %45
|
||||
%45 = OpLabel
|
||||
%49 = OpLoad %int %x_0
|
||||
%50 = OpIAdd %int %49 %int_1
|
||||
OpStore %x_0 %50
|
||||
OpBranch %42
|
||||
%46 = OpLabel
|
||||
OpReturnValue %true
|
||||
OpFunctionEnd
|
||||
%for_with_double_sided_conditional_return = OpFunction %bool None %22
|
||||
%51 = OpLabel
|
||||
%x_1 = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x_1 %int_0
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
OpLoopMerge %57 %56 None
|
||||
OpBranch %54
|
||||
%54 = OpLabel
|
||||
%58 = OpLoad %int %x_1
|
||||
%59 = OpSLessThanEqual %bool %58 %int_10
|
||||
OpBranchConditional %59 %55 %57
|
||||
%55 = OpLabel
|
||||
%60 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%63 = OpLoad %float %60
|
||||
%65 = OpFOrdEqual %bool %63 %float_1
|
||||
OpSelectionMerge %68 None
|
||||
OpBranchConditional %65 %66 %67
|
||||
%66 = OpLabel
|
||||
OpReturnValue %true
|
||||
%67 = OpLabel
|
||||
OpReturnValue %true
|
||||
%68 = OpLabel
|
||||
OpBranch %56
|
||||
%56 = OpLabel
|
||||
%69 = OpLoad %int %x_1
|
||||
%70 = OpIAdd %int %69 %int_1
|
||||
OpStore %x_1 %70
|
||||
OpBranch %53
|
||||
%57 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%if_else_chain = OpFunction %bool None %22
|
||||
%71 = OpLabel
|
||||
%72 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%73 = OpLoad %float %72
|
||||
%74 = OpFOrdEqual %bool %73 %float_1
|
||||
OpSelectionMerge %77 None
|
||||
OpBranchConditional %74 %75 %76
|
||||
%75 = OpLabel
|
||||
OpReturnValue %true
|
||||
%76 = OpLabel
|
||||
%78 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%79 = OpLoad %float %78
|
||||
%81 = OpFOrdEqual %bool %79 %float_2
|
||||
OpSelectionMerge %84 None
|
||||
OpBranchConditional %81 %82 %83
|
||||
%82 = OpLabel
|
||||
OpReturnValue %false
|
||||
%83 = OpLabel
|
||||
%86 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%87 = OpLoad %float %86
|
||||
%89 = OpFOrdEqual %bool %87 %float_3
|
||||
OpSelectionMerge %92 None
|
||||
OpBranchConditional %89 %90 %91
|
||||
%90 = OpLabel
|
||||
OpReturnValue %true
|
||||
%91 = OpLabel
|
||||
%93 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%94 = OpLoad %float %93
|
||||
%96 = OpFOrdEqual %bool %94 %float_4
|
||||
OpSelectionMerge %99 None
|
||||
OpBranchConditional %96 %97 %98
|
||||
%97 = OpLabel
|
||||
OpReturnValue %false
|
||||
%98 = OpLabel
|
||||
OpReturnValue %true
|
||||
%99 = OpLabel
|
||||
OpBranch %92
|
||||
%92 = OpLabel
|
||||
OpBranch %84
|
||||
%84 = OpLabel
|
||||
OpBranch %77
|
||||
%77 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %v4float None %100
|
||||
%101 = OpLabel
|
||||
%_0_return_on_both_sides = OpVariable %_ptr_Function_bool Function
|
||||
%127 = OpVariable %_ptr_Function_v4float Function
|
||||
%104 = OpAccessChain %_ptr_Uniform_float %14 %int_2
|
||||
%105 = OpLoad %float %104
|
||||
%106 = OpFOrdEqual %bool %105 %float_1
|
||||
OpSelectionMerge %109 None
|
||||
OpBranchConditional %106 %107 %108
|
||||
%107 = OpLabel
|
||||
OpStore %_0_return_on_both_sides %true
|
||||
OpBranch %109
|
||||
%108 = OpLabel
|
||||
OpStore %_0_return_on_both_sides %true
|
||||
OpBranch %109
|
||||
%109 = OpLabel
|
||||
%110 = OpLoad %bool %_0_return_on_both_sides
|
||||
OpSelectionMerge %112 None
|
||||
OpBranchConditional %110 %111 %112
|
||||
%111 = OpLabel
|
||||
%113 = OpFunctionCall %bool %for_inside_body
|
||||
OpBranch %112
|
||||
%112 = OpLabel
|
||||
%114 = OpPhi %bool %false %109 %113 %111
|
||||
OpSelectionMerge %116 None
|
||||
OpBranchConditional %114 %115 %116
|
||||
%115 = OpLabel
|
||||
%117 = OpFunctionCall %bool %after_for_body
|
||||
OpBranch %116
|
||||
%116 = OpLabel
|
||||
%118 = OpPhi %bool %false %112 %117 %115
|
||||
OpSelectionMerge %120 None
|
||||
OpBranchConditional %118 %119 %120
|
||||
%119 = OpLabel
|
||||
%121 = OpFunctionCall %bool %for_with_double_sided_conditional_return
|
||||
OpBranch %120
|
||||
%120 = OpLabel
|
||||
%122 = OpPhi %bool %false %116 %121 %119
|
||||
OpSelectionMerge %124 None
|
||||
OpBranchConditional %122 %123 %124
|
||||
%123 = OpLabel
|
||||
%125 = OpFunctionCall %bool %if_else_chain
|
||||
OpBranch %124
|
||||
%124 = OpLabel
|
||||
%126 = OpPhi %bool %false %120 %125 %123
|
||||
OpSelectionMerge %131 None
|
||||
OpBranchConditional %126 %129 %130
|
||||
%129 = OpLabel
|
||||
%132 = OpAccessChain %_ptr_Uniform_v4float %14 %int_0
|
||||
%134 = OpLoad %v4float %132
|
||||
OpStore %127 %134
|
||||
OpBranch %131
|
||||
%130 = OpLabel
|
||||
%135 = OpAccessChain %_ptr_Uniform_v4float %14 %int_1
|
||||
%136 = OpLoad %v4float %135
|
||||
OpStore %127 %136
|
||||
OpBranch %131
|
||||
%131 = OpLabel
|
||||
%137 = OpLoad %v4float %127
|
||||
OpReturnValue %137
|
||||
OpFunctionEnd
|
30
tests/sksl/shared/ReturnsValueOnEveryPathES2.glsl
Normal file
30
tests/sksl/shared/ReturnsValueOnEveryPathES2.glsl
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
out vec4 sk_FragColor;
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
uniform float unknownInput;
|
||||
bool for_inside_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_for_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool for_with_double_sided_conditional_return() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
if (unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
}
|
||||
bool if_else_chain() {
|
||||
if (unknownInput == 1.0) return true; else if (unknownInput == 2.0) return false; else if (unknownInput == 3.0) return true; else if (unknownInput == 4.0) return false; else return true;
|
||||
}
|
||||
vec4 main() {
|
||||
bool _0_return_on_both_sides;
|
||||
if (unknownInput == 1.0) _0_return_on_both_sides = true; else _0_return_on_both_sides = true;
|
||||
return (((_0_return_on_both_sides && for_inside_body()) && after_for_body()) && for_with_double_sided_conditional_return()) && if_else_chain() ? colorGreen : colorRed;
|
||||
|
||||
|
||||
}
|
44
tests/sksl/shared/ReturnsValueOnEveryPathES2.metal
Normal file
44
tests/sksl/shared/ReturnsValueOnEveryPathES2.metal
Normal file
@ -0,0 +1,44 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
using namespace metal;
|
||||
struct Uniforms {
|
||||
float4 colorGreen;
|
||||
float4 colorRed;
|
||||
float unknownInput;
|
||||
};
|
||||
struct Inputs {
|
||||
};
|
||||
struct Outputs {
|
||||
float4 sk_FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool for_inside_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_for_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool for_with_double_sided_conditional_return(Uniforms _uniforms) {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
if (_uniforms.unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
}
|
||||
bool if_else_chain(Uniforms _uniforms) {
|
||||
if (_uniforms.unknownInput == 1.0) return true; else if (_uniforms.unknownInput == 2.0) return false; else if (_uniforms.unknownInput == 3.0) return true; else if (_uniforms.unknownInput == 4.0) return false; else return true;
|
||||
}
|
||||
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
|
||||
Outputs _out;
|
||||
(void)_out;
|
||||
bool _0_return_on_both_sides;
|
||||
if (_uniforms.unknownInput == 1.0) _0_return_on_both_sides = true; else _0_return_on_both_sides = true;
|
||||
_out.sk_FragColor = (((_0_return_on_both_sides && for_inside_body()) && after_for_body()) && for_with_double_sided_conditional_return(_uniforms)) && if_else_chain(_uniforms) ? _uniforms.colorGreen : _uniforms.colorRed;
|
||||
return _out;
|
||||
|
||||
|
||||
}
|
633
tests/sksl/shared/ReturnsValueOnEveryPathES3.asm.frag
Normal file
633
tests/sksl/shared/ReturnsValueOnEveryPathES3.asm.frag
Normal file
@ -0,0 +1,633 @@
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %_entrypoint "_entrypoint" %sk_FragColor %sk_Clockwise
|
||||
OpExecutionMode %_entrypoint OriginUpperLeft
|
||||
OpName %sk_FragColor "sk_FragColor"
|
||||
OpName %sk_Clockwise "sk_Clockwise"
|
||||
OpName %_UniformBuffer "_UniformBuffer"
|
||||
OpMemberName %_UniformBuffer 0 "colorGreen"
|
||||
OpMemberName %_UniformBuffer 1 "colorRed"
|
||||
OpMemberName %_UniformBuffer 2 "unknownInput"
|
||||
OpName %_entrypoint "_entrypoint"
|
||||
OpName %return_on_both_sides "return_on_both_sides"
|
||||
OpName %for_inside_body "for_inside_body"
|
||||
OpName %x "x"
|
||||
OpName %after_for_body "after_for_body"
|
||||
OpName %x_0 "x"
|
||||
OpName %for_with_double_sided_conditional_return "for_with_double_sided_conditional_return"
|
||||
OpName %x_1 "x"
|
||||
OpName %if_else_chain "if_else_chain"
|
||||
OpName %conditional_inside_while_loop "conditional_inside_while_loop"
|
||||
OpName %inside_do_loop "inside_do_loop"
|
||||
OpName %inside_while_loop "inside_while_loop"
|
||||
OpName %after_do_loop "after_do_loop"
|
||||
OpName %after_while_loop "after_while_loop"
|
||||
OpName %switch_with_all_returns "switch_with_all_returns"
|
||||
OpName %switch_only_default "switch_only_default"
|
||||
OpName %switch_fallthrough "switch_fallthrough"
|
||||
OpName %switch_fallthrough_twice "switch_fallthrough_twice"
|
||||
OpName %switch_with_break_in_loop "switch_with_break_in_loop"
|
||||
OpName %x_2 "x"
|
||||
OpName %switch_with_continue_in_loop "switch_with_continue_in_loop"
|
||||
OpName %x_3 "x"
|
||||
OpName %switch_with_if_that_returns "switch_with_if_that_returns"
|
||||
OpName %switch_with_one_sided_if_then_fallthrough "switch_with_one_sided_if_then_fallthrough"
|
||||
OpName %main "main"
|
||||
OpDecorate %sk_FragColor RelaxedPrecision
|
||||
OpDecorate %sk_FragColor Location 0
|
||||
OpDecorate %sk_FragColor Index 0
|
||||
OpDecorate %sk_Clockwise RelaxedPrecision
|
||||
OpDecorate %sk_Clockwise BuiltIn FrontFacing
|
||||
OpMemberDecorate %_UniformBuffer 0 Offset 0
|
||||
OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
|
||||
OpMemberDecorate %_UniformBuffer 1 Offset 16
|
||||
OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
|
||||
OpMemberDecorate %_UniformBuffer 2 Offset 32
|
||||
OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
|
||||
OpDecorate %_UniformBuffer Block
|
||||
OpDecorate %28 Binding 0
|
||||
OpDecorate %28 DescriptorSet 0
|
||||
OpDecorate %42 RelaxedPrecision
|
||||
OpDecorate %85 RelaxedPrecision
|
||||
OpDecorate %94 RelaxedPrecision
|
||||
OpDecorate %100 RelaxedPrecision
|
||||
OpDecorate %108 RelaxedPrecision
|
||||
OpDecorate %115 RelaxedPrecision
|
||||
OpDecorate %128 RelaxedPrecision
|
||||
OpDecorate %157 RelaxedPrecision
|
||||
OpDecorate %165 RelaxedPrecision
|
||||
OpDecorate %171 RelaxedPrecision
|
||||
OpDecorate %179 RelaxedPrecision
|
||||
OpDecorate %187 RelaxedPrecision
|
||||
OpDecorate %204 RelaxedPrecision
|
||||
OpDecorate %221 RelaxedPrecision
|
||||
OpDecorate %227 RelaxedPrecision
|
||||
OpDecorate %234 RelaxedPrecision
|
||||
OpDecorate %240 RelaxedPrecision
|
||||
OpDecorate %325 RelaxedPrecision
|
||||
OpDecorate %327 RelaxedPrecision
|
||||
OpDecorate %328 RelaxedPrecision
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%sk_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Input_bool = OpTypePointer Input %bool
|
||||
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
|
||||
%_UniformBuffer = OpTypeStruct %v4float %v4float %float
|
||||
%_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
|
||||
%28 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
|
||||
%void = OpTypeVoid
|
||||
%33 = OpTypeFunction %void
|
||||
%36 = OpTypeFunction %bool
|
||||
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||
%int = OpTypeInt 32 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%float_1 = OpConstant %float 1
|
||||
%true = OpConstantTrue %bool
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%false = OpConstantFalse %bool
|
||||
%float_3 = OpConstant %float 3
|
||||
%float_4 = OpConstant %float 4
|
||||
%float_123 = OpConstant %float 123
|
||||
%244 = OpTypeFunction %v4float
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
|
||||
%_entrypoint = OpFunction %void None %33
|
||||
%34 = OpLabel
|
||||
%35 = OpFunctionCall %v4float %main
|
||||
OpStore %sk_FragColor %35
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%return_on_both_sides = OpFunction %bool None %36
|
||||
%37 = OpLabel
|
||||
%38 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%42 = OpLoad %float %38
|
||||
%44 = OpFOrdEqual %bool %42 %float_1
|
||||
OpSelectionMerge %47 None
|
||||
OpBranchConditional %44 %45 %46
|
||||
%45 = OpLabel
|
||||
OpReturnValue %true
|
||||
%46 = OpLabel
|
||||
OpReturnValue %true
|
||||
%47 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%for_inside_body = OpFunction %bool None %36
|
||||
%49 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x %int_0
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
OpLoopMerge %57 %56 None
|
||||
OpBranch %54
|
||||
%54 = OpLabel
|
||||
%58 = OpLoad %int %x
|
||||
%60 = OpSLessThanEqual %bool %58 %int_10
|
||||
OpBranchConditional %60 %55 %57
|
||||
%55 = OpLabel
|
||||
OpReturnValue %true
|
||||
%56 = OpLabel
|
||||
%62 = OpLoad %int %x
|
||||
%63 = OpIAdd %int %62 %int_1
|
||||
OpStore %x %63
|
||||
OpBranch %53
|
||||
%57 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%after_for_body = OpFunction %bool None %36
|
||||
%64 = OpLabel
|
||||
%x_0 = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x_0 %int_0
|
||||
OpBranch %66
|
||||
%66 = OpLabel
|
||||
OpLoopMerge %70 %69 None
|
||||
OpBranch %67
|
||||
%67 = OpLabel
|
||||
%71 = OpLoad %int %x_0
|
||||
%72 = OpSLessThanEqual %bool %71 %int_10
|
||||
OpBranchConditional %72 %68 %70
|
||||
%68 = OpLabel
|
||||
OpBranch %69
|
||||
%69 = OpLabel
|
||||
%73 = OpLoad %int %x_0
|
||||
%74 = OpIAdd %int %73 %int_1
|
||||
OpStore %x_0 %74
|
||||
OpBranch %66
|
||||
%70 = OpLabel
|
||||
OpReturnValue %true
|
||||
OpFunctionEnd
|
||||
%for_with_double_sided_conditional_return = OpFunction %bool None %36
|
||||
%75 = OpLabel
|
||||
%x_1 = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x_1 %int_0
|
||||
OpBranch %77
|
||||
%77 = OpLabel
|
||||
OpLoopMerge %81 %80 None
|
||||
OpBranch %78
|
||||
%78 = OpLabel
|
||||
%82 = OpLoad %int %x_1
|
||||
%83 = OpSLessThanEqual %bool %82 %int_10
|
||||
OpBranchConditional %83 %79 %81
|
||||
%79 = OpLabel
|
||||
%84 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%85 = OpLoad %float %84
|
||||
%86 = OpFOrdEqual %bool %85 %float_1
|
||||
OpSelectionMerge %89 None
|
||||
OpBranchConditional %86 %87 %88
|
||||
%87 = OpLabel
|
||||
OpReturnValue %true
|
||||
%88 = OpLabel
|
||||
OpReturnValue %true
|
||||
%89 = OpLabel
|
||||
OpBranch %80
|
||||
%80 = OpLabel
|
||||
%90 = OpLoad %int %x_1
|
||||
%91 = OpIAdd %int %90 %int_1
|
||||
OpStore %x_1 %91
|
||||
OpBranch %77
|
||||
%81 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%if_else_chain = OpFunction %bool None %36
|
||||
%92 = OpLabel
|
||||
%93 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%94 = OpLoad %float %93
|
||||
%95 = OpFOrdEqual %bool %94 %float_1
|
||||
OpSelectionMerge %98 None
|
||||
OpBranchConditional %95 %96 %97
|
||||
%96 = OpLabel
|
||||
OpReturnValue %true
|
||||
%97 = OpLabel
|
||||
%99 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%100 = OpLoad %float %99
|
||||
%102 = OpFOrdEqual %bool %100 %float_2
|
||||
OpSelectionMerge %105 None
|
||||
OpBranchConditional %102 %103 %104
|
||||
%103 = OpLabel
|
||||
OpReturnValue %false
|
||||
%104 = OpLabel
|
||||
%107 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%108 = OpLoad %float %107
|
||||
%110 = OpFOrdEqual %bool %108 %float_3
|
||||
OpSelectionMerge %113 None
|
||||
OpBranchConditional %110 %111 %112
|
||||
%111 = OpLabel
|
||||
OpReturnValue %true
|
||||
%112 = OpLabel
|
||||
%114 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%115 = OpLoad %float %114
|
||||
%117 = OpFOrdEqual %bool %115 %float_4
|
||||
OpSelectionMerge %120 None
|
||||
OpBranchConditional %117 %118 %119
|
||||
%118 = OpLabel
|
||||
OpReturnValue %false
|
||||
%119 = OpLabel
|
||||
OpReturnValue %true
|
||||
%120 = OpLabel
|
||||
OpBranch %113
|
||||
%113 = OpLabel
|
||||
OpBranch %105
|
||||
%105 = OpLabel
|
||||
OpBranch %98
|
||||
%98 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%conditional_inside_while_loop = OpFunction %bool None %36
|
||||
%121 = OpLabel
|
||||
OpBranch %122
|
||||
%122 = OpLabel
|
||||
OpLoopMerge %126 %125 None
|
||||
OpBranch %123
|
||||
%123 = OpLabel
|
||||
%127 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%128 = OpLoad %float %127
|
||||
%130 = OpFOrdEqual %bool %128 %float_123
|
||||
OpBranchConditional %130 %124 %126
|
||||
%124 = OpLabel
|
||||
OpReturnValue %true
|
||||
%125 = OpLabel
|
||||
OpBranch %122
|
||||
%126 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%inside_do_loop = OpFunction %bool None %36
|
||||
%131 = OpLabel
|
||||
OpBranch %132
|
||||
%132 = OpLabel
|
||||
OpLoopMerge %136 %135 None
|
||||
OpBranch %133
|
||||
%133 = OpLabel
|
||||
OpReturnValue %true
|
||||
%134 = OpLabel
|
||||
OpBranchConditional %true %135 %136
|
||||
%135 = OpLabel
|
||||
OpBranch %132
|
||||
%136 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%inside_while_loop = OpFunction %bool None %36
|
||||
%137 = OpLabel
|
||||
OpBranch %138
|
||||
%138 = OpLabel
|
||||
OpLoopMerge %142 %141 None
|
||||
OpBranch %139
|
||||
%139 = OpLabel
|
||||
OpBranchConditional %true %140 %142
|
||||
%140 = OpLabel
|
||||
OpReturnValue %true
|
||||
%141 = OpLabel
|
||||
OpBranch %138
|
||||
%142 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%after_do_loop = OpFunction %bool None %36
|
||||
%143 = OpLabel
|
||||
OpBranch %144
|
||||
%144 = OpLabel
|
||||
OpLoopMerge %148 %147 None
|
||||
OpBranch %145
|
||||
%145 = OpLabel
|
||||
OpBranch %148
|
||||
%146 = OpLabel
|
||||
OpBranchConditional %true %147 %148
|
||||
%147 = OpLabel
|
||||
OpBranch %144
|
||||
%148 = OpLabel
|
||||
OpReturnValue %true
|
||||
OpFunctionEnd
|
||||
%after_while_loop = OpFunction %bool None %36
|
||||
%149 = OpLabel
|
||||
OpBranch %150
|
||||
%150 = OpLabel
|
||||
OpLoopMerge %154 %153 None
|
||||
OpBranch %151
|
||||
%151 = OpLabel
|
||||
OpBranchConditional %true %152 %154
|
||||
%152 = OpLabel
|
||||
OpBranch %154
|
||||
%153 = OpLabel
|
||||
OpBranch %150
|
||||
%154 = OpLabel
|
||||
OpReturnValue %true
|
||||
OpFunctionEnd
|
||||
%switch_with_all_returns = OpFunction %bool None %36
|
||||
%155 = OpLabel
|
||||
%156 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%157 = OpLoad %float %156
|
||||
%158 = OpConvertFToS %int %157
|
||||
OpSelectionMerge %159 None
|
||||
OpSwitch %158 %162 1 %160 2 %161
|
||||
%160 = OpLabel
|
||||
OpReturnValue %true
|
||||
%161 = OpLabel
|
||||
OpReturnValue %true
|
||||
%162 = OpLabel
|
||||
OpReturnValue %true
|
||||
%159 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_only_default = OpFunction %bool None %36
|
||||
%163 = OpLabel
|
||||
%164 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%165 = OpLoad %float %164
|
||||
%166 = OpConvertFToS %int %165
|
||||
OpSelectionMerge %167 None
|
||||
OpSwitch %166 %168
|
||||
%168 = OpLabel
|
||||
OpReturnValue %true
|
||||
%167 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_fallthrough = OpFunction %bool None %36
|
||||
%169 = OpLabel
|
||||
%170 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%171 = OpLoad %float %170
|
||||
%172 = OpConvertFToS %int %171
|
||||
OpSelectionMerge %173 None
|
||||
OpSwitch %172 %176 1 %174 2 %175
|
||||
%174 = OpLabel
|
||||
OpReturnValue %true
|
||||
%175 = OpLabel
|
||||
OpBranch %176
|
||||
%176 = OpLabel
|
||||
OpReturnValue %true
|
||||
%173 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_fallthrough_twice = OpFunction %bool None %36
|
||||
%177 = OpLabel
|
||||
%178 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%179 = OpLoad %float %178
|
||||
%180 = OpConvertFToS %int %179
|
||||
OpSelectionMerge %181 None
|
||||
OpSwitch %180 %184 1 %182 2 %183
|
||||
%182 = OpLabel
|
||||
OpBranch %183
|
||||
%183 = OpLabel
|
||||
OpBranch %184
|
||||
%184 = OpLabel
|
||||
OpReturnValue %true
|
||||
%181 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_with_break_in_loop = OpFunction %bool None %36
|
||||
%185 = OpLabel
|
||||
%x_2 = OpVariable %_ptr_Function_int Function
|
||||
%186 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%187 = OpLoad %float %186
|
||||
%188 = OpConvertFToS %int %187
|
||||
OpSelectionMerge %189 None
|
||||
OpSwitch %188 %191 1 %190
|
||||
%190 = OpLabel
|
||||
OpStore %x_2 %int_0
|
||||
OpBranch %193
|
||||
%193 = OpLabel
|
||||
OpLoopMerge %197 %196 None
|
||||
OpBranch %194
|
||||
%194 = OpLabel
|
||||
%198 = OpLoad %int %x_2
|
||||
%199 = OpSLessThanEqual %bool %198 %int_10
|
||||
OpBranchConditional %199 %195 %197
|
||||
%195 = OpLabel
|
||||
OpBranch %197
|
||||
%196 = OpLabel
|
||||
%200 = OpLoad %int %x_2
|
||||
%201 = OpIAdd %int %200 %int_1
|
||||
OpStore %x_2 %201
|
||||
OpBranch %193
|
||||
%197 = OpLabel
|
||||
OpBranch %191
|
||||
%191 = OpLabel
|
||||
OpReturnValue %true
|
||||
%189 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_with_continue_in_loop = OpFunction %bool None %36
|
||||
%202 = OpLabel
|
||||
%x_3 = OpVariable %_ptr_Function_int Function
|
||||
%203 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%204 = OpLoad %float %203
|
||||
%205 = OpConvertFToS %int %204
|
||||
OpSelectionMerge %206 None
|
||||
OpSwitch %205 %208 1 %207
|
||||
%207 = OpLabel
|
||||
OpStore %x_3 %int_0
|
||||
OpBranch %210
|
||||
%210 = OpLabel
|
||||
OpLoopMerge %214 %213 None
|
||||
OpBranch %211
|
||||
%211 = OpLabel
|
||||
%215 = OpLoad %int %x_3
|
||||
%216 = OpSLessThanEqual %bool %215 %int_10
|
||||
OpBranchConditional %216 %212 %214
|
||||
%212 = OpLabel
|
||||
OpBranch %213
|
||||
%213 = OpLabel
|
||||
%217 = OpLoad %int %x_3
|
||||
%218 = OpIAdd %int %217 %int_1
|
||||
OpStore %x_3 %218
|
||||
OpBranch %210
|
||||
%214 = OpLabel
|
||||
OpBranch %208
|
||||
%208 = OpLabel
|
||||
OpReturnValue %true
|
||||
%206 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_with_if_that_returns = OpFunction %bool None %36
|
||||
%219 = OpLabel
|
||||
%220 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%221 = OpLoad %float %220
|
||||
%222 = OpConvertFToS %int %221
|
||||
OpSelectionMerge %223 None
|
||||
OpSwitch %222 %225 1 %224
|
||||
%224 = OpLabel
|
||||
%226 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%227 = OpLoad %float %226
|
||||
%228 = OpFOrdEqual %bool %227 %float_123
|
||||
OpSelectionMerge %231 None
|
||||
OpBranchConditional %228 %229 %230
|
||||
%229 = OpLabel
|
||||
OpReturnValue %true
|
||||
%230 = OpLabel
|
||||
OpReturnValue %true
|
||||
%231 = OpLabel
|
||||
OpBranch %225
|
||||
%225 = OpLabel
|
||||
OpReturnValue %true
|
||||
%223 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%switch_with_one_sided_if_then_fallthrough = OpFunction %bool None %36
|
||||
%232 = OpLabel
|
||||
%233 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%234 = OpLoad %float %233
|
||||
%235 = OpConvertFToS %int %234
|
||||
OpSelectionMerge %236 None
|
||||
OpSwitch %235 %238 1 %237
|
||||
%237 = OpLabel
|
||||
%239 = OpAccessChain %_ptr_Uniform_float %28 %int_2
|
||||
%240 = OpLoad %float %239
|
||||
%241 = OpFOrdEqual %bool %240 %float_123
|
||||
OpSelectionMerge %243 None
|
||||
OpBranchConditional %241 %242 %243
|
||||
%242 = OpLabel
|
||||
OpReturnValue %true
|
||||
%243 = OpLabel
|
||||
OpBranch %238
|
||||
%238 = OpLabel
|
||||
OpReturnValue %true
|
||||
%236 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %v4float None %244
|
||||
%245 = OpLabel
|
||||
%318 = OpVariable %_ptr_Function_v4float Function
|
||||
OpSelectionMerge %247 None
|
||||
OpBranchConditional %true %246 %247
|
||||
%246 = OpLabel
|
||||
%248 = OpFunctionCall %bool %return_on_both_sides
|
||||
OpBranch %247
|
||||
%247 = OpLabel
|
||||
%249 = OpPhi %bool %false %245 %248 %246
|
||||
OpSelectionMerge %251 None
|
||||
OpBranchConditional %249 %250 %251
|
||||
%250 = OpLabel
|
||||
%252 = OpFunctionCall %bool %for_inside_body
|
||||
OpBranch %251
|
||||
%251 = OpLabel
|
||||
%253 = OpPhi %bool %false %247 %252 %250
|
||||
OpSelectionMerge %255 None
|
||||
OpBranchConditional %253 %254 %255
|
||||
%254 = OpLabel
|
||||
%256 = OpFunctionCall %bool %after_for_body
|
||||
OpBranch %255
|
||||
%255 = OpLabel
|
||||
%257 = OpPhi %bool %false %251 %256 %254
|
||||
OpSelectionMerge %259 None
|
||||
OpBranchConditional %257 %258 %259
|
||||
%258 = OpLabel
|
||||
%260 = OpFunctionCall %bool %for_with_double_sided_conditional_return
|
||||
OpBranch %259
|
||||
%259 = OpLabel
|
||||
%261 = OpPhi %bool %false %255 %260 %258
|
||||
OpSelectionMerge %263 None
|
||||
OpBranchConditional %261 %262 %263
|
||||
%262 = OpLabel
|
||||
%264 = OpFunctionCall %bool %if_else_chain
|
||||
OpBranch %263
|
||||
%263 = OpLabel
|
||||
%265 = OpPhi %bool %false %259 %264 %262
|
||||
OpSelectionMerge %267 None
|
||||
OpBranchConditional %265 %266 %267
|
||||
%266 = OpLabel
|
||||
%268 = OpFunctionCall %bool %conditional_inside_while_loop
|
||||
OpBranch %267
|
||||
%267 = OpLabel
|
||||
%269 = OpPhi %bool %false %263 %268 %266
|
||||
OpSelectionMerge %271 None
|
||||
OpBranchConditional %269 %270 %271
|
||||
%270 = OpLabel
|
||||
%272 = OpFunctionCall %bool %inside_do_loop
|
||||
OpBranch %271
|
||||
%271 = OpLabel
|
||||
%273 = OpPhi %bool %false %267 %272 %270
|
||||
OpSelectionMerge %275 None
|
||||
OpBranchConditional %273 %274 %275
|
||||
%274 = OpLabel
|
||||
%276 = OpFunctionCall %bool %inside_while_loop
|
||||
OpBranch %275
|
||||
%275 = OpLabel
|
||||
%277 = OpPhi %bool %false %271 %276 %274
|
||||
OpSelectionMerge %279 None
|
||||
OpBranchConditional %277 %278 %279
|
||||
%278 = OpLabel
|
||||
%280 = OpFunctionCall %bool %after_do_loop
|
||||
OpBranch %279
|
||||
%279 = OpLabel
|
||||
%281 = OpPhi %bool %false %275 %280 %278
|
||||
OpSelectionMerge %283 None
|
||||
OpBranchConditional %281 %282 %283
|
||||
%282 = OpLabel
|
||||
%284 = OpFunctionCall %bool %after_while_loop
|
||||
OpBranch %283
|
||||
%283 = OpLabel
|
||||
%285 = OpPhi %bool %false %279 %284 %282
|
||||
OpSelectionMerge %287 None
|
||||
OpBranchConditional %285 %286 %287
|
||||
%286 = OpLabel
|
||||
%288 = OpFunctionCall %bool %switch_with_all_returns
|
||||
OpBranch %287
|
||||
%287 = OpLabel
|
||||
%289 = OpPhi %bool %false %283 %288 %286
|
||||
OpSelectionMerge %291 None
|
||||
OpBranchConditional %289 %290 %291
|
||||
%290 = OpLabel
|
||||
%292 = OpFunctionCall %bool %switch_only_default
|
||||
OpBranch %291
|
||||
%291 = OpLabel
|
||||
%293 = OpPhi %bool %false %287 %292 %290
|
||||
OpSelectionMerge %295 None
|
||||
OpBranchConditional %293 %294 %295
|
||||
%294 = OpLabel
|
||||
%296 = OpFunctionCall %bool %switch_fallthrough
|
||||
OpBranch %295
|
||||
%295 = OpLabel
|
||||
%297 = OpPhi %bool %false %291 %296 %294
|
||||
OpSelectionMerge %299 None
|
||||
OpBranchConditional %297 %298 %299
|
||||
%298 = OpLabel
|
||||
%300 = OpFunctionCall %bool %switch_fallthrough_twice
|
||||
OpBranch %299
|
||||
%299 = OpLabel
|
||||
%301 = OpPhi %bool %false %295 %300 %298
|
||||
OpSelectionMerge %303 None
|
||||
OpBranchConditional %301 %302 %303
|
||||
%302 = OpLabel
|
||||
%304 = OpFunctionCall %bool %switch_with_break_in_loop
|
||||
OpBranch %303
|
||||
%303 = OpLabel
|
||||
%305 = OpPhi %bool %false %299 %304 %302
|
||||
OpSelectionMerge %307 None
|
||||
OpBranchConditional %305 %306 %307
|
||||
%306 = OpLabel
|
||||
%308 = OpFunctionCall %bool %switch_with_continue_in_loop
|
||||
OpBranch %307
|
||||
%307 = OpLabel
|
||||
%309 = OpPhi %bool %false %303 %308 %306
|
||||
OpSelectionMerge %311 None
|
||||
OpBranchConditional %309 %310 %311
|
||||
%310 = OpLabel
|
||||
%312 = OpFunctionCall %bool %switch_with_if_that_returns
|
||||
OpBranch %311
|
||||
%311 = OpLabel
|
||||
%313 = OpPhi %bool %false %307 %312 %310
|
||||
OpSelectionMerge %315 None
|
||||
OpBranchConditional %313 %314 %315
|
||||
%314 = OpLabel
|
||||
%316 = OpFunctionCall %bool %switch_with_one_sided_if_then_fallthrough
|
||||
OpBranch %315
|
||||
%315 = OpLabel
|
||||
%317 = OpPhi %bool %false %311 %316 %314
|
||||
OpSelectionMerge %322 None
|
||||
OpBranchConditional %317 %320 %321
|
||||
%320 = OpLabel
|
||||
%323 = OpAccessChain %_ptr_Uniform_v4float %28 %int_0
|
||||
%325 = OpLoad %v4float %323
|
||||
OpStore %318 %325
|
||||
OpBranch %322
|
||||
%321 = OpLabel
|
||||
%326 = OpAccessChain %_ptr_Uniform_v4float %28 %int_1
|
||||
%327 = OpLoad %v4float %326
|
||||
OpStore %318 %327
|
||||
OpBranch %322
|
||||
%322 = OpLabel
|
||||
%328 = OpLoad %v4float %318
|
||||
OpReturnValue %328
|
||||
OpFunctionEnd
|
128
tests/sksl/shared/ReturnsValueOnEveryPathES3.glsl
Normal file
128
tests/sksl/shared/ReturnsValueOnEveryPathES3.glsl
Normal file
@ -0,0 +1,128 @@
|
||||
|
||||
out vec4 sk_FragColor;
|
||||
uniform vec4 colorGreen;
|
||||
uniform vec4 colorRed;
|
||||
uniform float unknownInput;
|
||||
bool return_on_both_sides() {
|
||||
if (unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
bool for_inside_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_for_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
true;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool for_with_double_sided_conditional_return() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
if (unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
}
|
||||
bool if_else_chain() {
|
||||
if (unknownInput == 1.0) return true; else if (unknownInput == 2.0) return false; else if (unknownInput == 3.0) return true; else if (unknownInput == 4.0) return false; else return true;
|
||||
}
|
||||
bool conditional_inside_while_loop() {
|
||||
while (unknownInput == 123.0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool inside_do_loop() {
|
||||
do {
|
||||
return true;
|
||||
} while (true);
|
||||
}
|
||||
bool inside_while_loop() {
|
||||
while (true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_do_loop() {
|
||||
do {
|
||||
break;
|
||||
} while (true);
|
||||
return true;
|
||||
}
|
||||
bool after_while_loop() {
|
||||
while (true) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool switch_with_all_returns() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_only_default() {
|
||||
switch (int(unknownInput)) {
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_fallthrough() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_fallthrough_twice() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
case 2:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_break_in_loop() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_continue_in_loop() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_if_that_returns() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
if (unknownInput == 123.0) return true; else return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_one_sided_if_then_fallthrough() {
|
||||
switch (int(unknownInput)) {
|
||||
case 1:
|
||||
if (unknownInput == 123.0) return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
vec4 main() {
|
||||
return (((((((((((((((((true && return_on_both_sides()) && for_inside_body()) && after_for_body()) && for_with_double_sided_conditional_return()) && if_else_chain()) && conditional_inside_while_loop()) && inside_do_loop()) && inside_while_loop()) && after_do_loop()) && after_while_loop()) && switch_with_all_returns()) && switch_only_default()) && switch_fallthrough()) && switch_fallthrough_twice()) && switch_with_break_in_loop()) && switch_with_continue_in_loop()) && switch_with_if_that_returns()) && switch_with_one_sided_if_then_fallthrough() ? colorGreen : colorRed;
|
||||
|
||||
}
|
142
tests/sksl/shared/ReturnsValueOnEveryPathES3.metal
Normal file
142
tests/sksl/shared/ReturnsValueOnEveryPathES3.metal
Normal file
@ -0,0 +1,142 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
using namespace metal;
|
||||
struct Uniforms {
|
||||
float4 colorGreen;
|
||||
float4 colorRed;
|
||||
float unknownInput;
|
||||
};
|
||||
struct Inputs {
|
||||
};
|
||||
struct Outputs {
|
||||
float4 sk_FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool return_on_both_sides(Uniforms _uniforms) {
|
||||
if (_uniforms.unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
bool for_inside_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_for_body() {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
true;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool for_with_double_sided_conditional_return(Uniforms _uniforms) {
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
if (_uniforms.unknownInput == 1.0) return true; else return true;
|
||||
}
|
||||
}
|
||||
bool if_else_chain(Uniforms _uniforms) {
|
||||
if (_uniforms.unknownInput == 1.0) return true; else if (_uniforms.unknownInput == 2.0) return false; else if (_uniforms.unknownInput == 3.0) return true; else if (_uniforms.unknownInput == 4.0) return false; else return true;
|
||||
}
|
||||
bool conditional_inside_while_loop(Uniforms _uniforms) {
|
||||
while (_uniforms.unknownInput == 123.0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool inside_do_loop() {
|
||||
do {
|
||||
return true;
|
||||
} while (true);
|
||||
}
|
||||
bool inside_while_loop() {
|
||||
while (true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool after_do_loop() {
|
||||
do {
|
||||
break;
|
||||
} while (true);
|
||||
return true;
|
||||
}
|
||||
bool after_while_loop() {
|
||||
while (true) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool switch_with_all_returns(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_only_default(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_fallthrough(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_fallthrough_twice(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
case 2:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_break_in_loop(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_continue_in_loop(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
for (int x = 0;x <= 10; ++x) {
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_if_that_returns(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
if (_uniforms.unknownInput == 123.0) return true; else return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool switch_with_one_sided_if_then_fallthrough(Uniforms _uniforms) {
|
||||
switch (int(_uniforms.unknownInput)) {
|
||||
case 1:
|
||||
if (_uniforms.unknownInput == 123.0) return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
|
||||
Outputs _out;
|
||||
(void)_out;
|
||||
_out.sk_FragColor = (((((((((((((((((true && return_on_both_sides(_uniforms)) && for_inside_body()) && after_for_body()) && for_with_double_sided_conditional_return(_uniforms)) && if_else_chain(_uniforms)) && conditional_inside_while_loop(_uniforms)) && inside_do_loop()) && inside_while_loop()) && after_do_loop()) && after_while_loop()) && switch_with_all_returns(_uniforms)) && switch_only_default(_uniforms)) && switch_fallthrough(_uniforms)) && switch_fallthrough_twice(_uniforms)) && switch_with_break_in_loop(_uniforms)) && switch_with_continue_in_loop(_uniforms)) && switch_with_if_that_returns(_uniforms)) && switch_with_one_sided_if_then_fallthrough(_uniforms) ? _uniforms.colorGreen : _uniforms.colorRed;
|
||||
return _out;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user