shader: Bug fix: Treat multiple-context at return correctly

This commit is contained in:
Hajime Hoshi 2020-09-12 17:44:04 +09:00
parent 2fb1033183
commit d001f49ad7
3 changed files with 85 additions and 30 deletions

View File

@ -378,9 +378,10 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
}) })
case *ast.ReturnStmt: case *ast.ReturnStmt:
if len(stmt.Results) != len(outParams) { if len(stmt.Results) != len(outParams) && len(stmt.Results) != 1 {
if !(len(stmt.Results) == 0 && len(outParams) > 0 && outParams[0].name != "") { if !(len(stmt.Results) == 0 && len(outParams) > 0 && outParams[0].name != "") {
// TODO: Implenet multiple-value context. // TODO: Check variable shadowings.
// https://golang.org/ref/spec#Return_statements
cs.addError(stmt.Pos(), fmt.Sprintf("the number of returning variables must be %d but %d", len(outParams), len(stmt.Results))) cs.addError(stmt.Pos(), fmt.Sprintf("the number of returning variables must be %d but %d", len(outParams), len(stmt.Results)))
return nil, false return nil, false
} }
@ -393,42 +394,51 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
} }
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
if len(exprs) == 0 { if len(exprs) == 0 {
if len(exprs) != len(outParams) {
cs.addError(stmt.Pos(), fmt.Sprintf("the number of returning variables must be %d but %d", len(outParams), len(stmt.Results)))
}
continue continue
} }
if len(exprs) > 1 { if len(exprs) > 1 {
cs.addError(r.Pos(), "multiple-value context with return is not implemented yet") if len(stmt.Results) > 1 || len(outParams) == 1 {
continue cs.addError(r.Pos(), "single-value context and multiple-value context cannot be mixed")
} return nil, false
}
t := ts[0] if len(exprs) != len(outParams) {
expr := exprs[0] cs.addError(stmt.Pos(), fmt.Sprintf("the number of returning variables must be %d but %d", len(outParams), len(stmt.Results)))
if expr.Type == shaderir.NumberExpr {
switch outParams[i].typ.Main {
case shaderir.Int:
if !cs.forceToInt(stmt, &expr) {
return nil, false
}
t = shaderir.Type{Main: shaderir.Int}
case shaderir.Float:
t = shaderir.Type{Main: shaderir.Float}
} }
} }
if !t.Equal(&outParams[i].typ) { for j, t := range ts {
cs.addError(stmt.Pos(), fmt.Sprintf("cannot use type %s as type %s in return argument", &t, &outParams[i].typ)) expr := exprs[j]
return nil, false if expr.Type == shaderir.NumberExpr {
} switch outParams[i+j].typ.Main {
case shaderir.Int:
if !cs.forceToInt(stmt, &expr) {
return nil, false
}
t = shaderir.Type{Main: shaderir.Int}
case shaderir.Float:
t = shaderir.Type{Main: shaderir.Float}
}
}
stmts = append(stmts, shaderir.Stmt{ if !t.Equal(&outParams[i+j].typ) {
Type: shaderir.Assign, cs.addError(stmt.Pos(), fmt.Sprintf("cannot use type %s as type %s in return argument", &t, &outParams[i].typ))
Exprs: []shaderir.Expr{ return nil, false
{ }
Type: shaderir.LocalVariable,
Index: len(inParams) + i, stmts = append(stmts, shaderir.Stmt{
Type: shaderir.Assign,
Exprs: []shaderir.Expr{
{
Type: shaderir.LocalVariable,
Index: len(inParams) + i + j,
},
expr,
}, },
expr, })
}, }
})
} }
stmts = append(stmts, shaderir.Stmt{ stmts = append(stmts, shaderir.Stmt{
Type: shaderir.Return, Type: shaderir.Return,

View File

@ -0,0 +1,36 @@
void F0(out float l0, out float l1[4], out vec4 l2);
void F1(out float l0, out float l1[4], out vec4 l2);
void F0(out float l0, out float l1[4], out vec4 l2) {
l0 = float(0);
l1[0] = float(0);
l1[1] = float(0);
l1[2] = float(0);
l1[3] = float(0);
l2 = vec4(0);
return;
}
void F1(out float l0, out float l1[4], out vec4 l2) {
float l3 = float(0);
float l4[4];
l4[0] = float(0);
l4[1] = float(0);
l4[2] = float(0);
l4[3] = float(0);
vec4 l5 = vec4(0);
l0 = float(0);
l1[0] = float(0);
l1[1] = float(0);
l1[2] = float(0);
l1[3] = float(0);
l2 = vec4(0);
F0(l3, l4, l5);
l0 = l3;
l1[0] = l4[0];
l1[1] = l4[1];
l1[2] = l4[2];
l1[3] = l4[3];
l2 = l5;
return;
}

9
internal/shader/testdata/out2.go vendored Normal file
View File

@ -0,0 +1,9 @@
package main
func Foo() (a float, b [4]float, c vec4) {
return
}
func Foo2() (a float, b [4]float, c vec4) {
return Foo()
}