internal/shader: refactoring: check dimensions at AreValidTypesForBinaryOp

This commit is contained in:
Hajime Hoshi 2023-07-25 12:02:13 +09:00
parent 6b94de4ef6
commit ad63d0842c
2 changed files with 63 additions and 78 deletions

View File

@ -34,34 +34,6 @@ func canTruncateToFloat(v gconstant.Value) bool {
return gconstant.ToFloat(v).Kind() != gconstant.Unknown return gconstant.ToFloat(v).Kind() != gconstant.Unknown
} }
func isValidForModOp(lhs, rhs *shaderir.Expr, lhst, rhst shaderir.Type) bool {
isInt := func(s *shaderir.Expr, t shaderir.Type) bool {
if t.Main == shaderir.Int {
return true
}
if s.Const == nil {
return false
}
if s.Const.Kind() == gconstant.Int {
return true
}
if canTruncateToInteger(s.Const) {
return true
}
return false
}
if isInt(lhs, lhst) {
return isInt(rhs, rhst)
}
if lhst.Main == shaderir.IVec2 || lhst.Main == shaderir.IVec3 || lhst.Main == shaderir.IVec4 {
return lhst.Equal(&rhst) || isInt(rhs, rhst)
}
return false
}
var textureVariableRe = regexp.MustCompile(`\A__t(\d+)\z`) var textureVariableRe = regexp.MustCompile(`\A__t(\d+)\z`)
func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, markLocalVariableUsed bool) ([]shaderir.Expr, []shaderir.Type, []shaderir.Stmt, bool) { func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, markLocalVariableUsed bool) ([]shaderir.Expr, []shaderir.Type, []shaderir.Stmt, bool) {
@ -227,32 +199,12 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
t = rhst t = rhst
case rhst.Main == shaderir.Float: case rhst.Main == shaderir.Float:
t = lhst t = lhst
case op2 == shaderir.MatrixMul && (lhst.Main == shaderir.Vec2 && rhst.Main == shaderir.Mat2 || case op2 == shaderir.MatrixMul && lhst.IsVector() && rhst.IsMatrix():
lhst.Main == shaderir.Mat2 && rhst.Main == shaderir.Vec2): t = lhst
t = shaderir.Type{Main: shaderir.Vec2} case op2 == shaderir.MatrixMul && lhst.IsMatrix() && rhst.IsVector():
case op2 == shaderir.MatrixMul && (lhst.Main == shaderir.Vec3 && rhst.Main == shaderir.Mat3 || t = rhst
lhst.Main == shaderir.Mat3 && rhst.Main == shaderir.Vec3):
t = shaderir.Type{Main: shaderir.Vec3}
case op2 == shaderir.MatrixMul && (lhst.Main == shaderir.Vec4 && rhst.Main == shaderir.Mat4 ||
lhst.Main == shaderir.Mat4 && rhst.Main == shaderir.Vec4):
t = shaderir.Type{Main: shaderir.Vec4}
default: default:
cs.addError(e.Pos(), fmt.Sprintf("invalid expression: %s %s %s", lhst.String(), e.Op, rhst.String())) panic(fmt.Sprintf("shaderir: invalid expression: %s %s %s", lhst.String(), e.Op, rhst.String()))
return nil, nil, nil, false
}
// For `%`, both types must be deducible to integers.
if op2 == shaderir.ModOp {
if !isValidForModOp(&lhs[0], &rhs[0], lhst, rhst) {
var wrongType shaderir.Type
if lhst.Main != shaderir.Int {
wrongType = lhst
} else {
wrongType = rhst
}
cs.addError(e.Pos(), fmt.Sprintf("invalid operation: operator %% not defined on %s", wrongType.String()))
return nil, nil, nil, false
}
} }
return []shaderir.Expr{ return []shaderir.Expr{

View File

@ -69,25 +69,6 @@ func ResolveUntypedConstsForBinaryOp(lhs, rhs constant.Value, lhst, rhst Type) (
} }
func AreValidTypesForBinaryOp(op Op, lhs, rhs *Expr, lhst, rhst Type) bool { func AreValidTypesForBinaryOp(op Op, lhs, rhs *Expr, lhst, rhst Type) bool {
if op == AndAnd || op == OrOr {
return lhst.Main == Bool && rhst.Main == Bool
}
if op == VectorEqualOp || op == VectorNotEqualOp {
return lhst.IsVector() && rhst.IsVector() && lhst.Equal(&rhst)
}
// Comparing matrices are forbidden (#2187).
if op == LessThanOp || op == LessThanEqualOp || op == GreaterThanOp || op == GreaterThanEqualOp || op == EqualOp || op == NotEqualOp {
if lhst.IsMatrix() || rhst.IsMatrix() {
return false
}
}
if op == Div && rhst.IsMatrix() {
return false
}
// If both are untyped consts, compare the constants and try to truncate them if necessary. // If both are untyped consts, compare the constants and try to truncate them if necessary.
if lhst.Main == None && rhst.Main == None { if lhst.Main == None && rhst.Main == None {
// Assume that the constant types are already adjusted. // Assume that the constant types are already adjusted.
@ -95,6 +76,10 @@ func AreValidTypesForBinaryOp(op Op, lhs, rhs *Expr, lhst, rhst Type) bool {
panic("shaderir: const types for a binary op must be adjusted") panic("shaderir: const types for a binary op must be adjusted")
} }
if op == AndAnd || op == OrOr {
return lhs.Const.Kind() == constant.Bool && rhs.Const.Kind() == constant.Bool
}
// For %, both operands must be integers if both are constants. Truncatable to an integer is not enough. // For %, both operands must be integers if both are constants. Truncatable to an integer is not enough.
if op == ModOp { if op == ModOp {
return lhs.Const.Kind() == constant.Int && rhs.Const.Kind() == constant.Int return lhs.Const.Kind() == constant.Int && rhs.Const.Kind() == constant.Int
@ -107,25 +92,73 @@ func AreValidTypesForBinaryOp(op Op, lhs, rhs *Expr, lhst, rhst Type) bool {
panic("shaderir: cannot resolve untyped values") panic("shaderir: cannot resolve untyped values")
} }
if op == AndAnd || op == OrOr {
return lhst.Main == Bool && rhst.Main == Bool
}
if op == VectorEqualOp || op == VectorNotEqualOp {
return lhst.IsVector() && rhst.IsVector() && lhst.Equal(&rhst)
}
// Comparing matrices are forbidden (#2187).
if op == LessThanOp || op == LessThanEqualOp || op == GreaterThanOp || op == GreaterThanEqualOp || op == EqualOp || op == NotEqualOp {
if lhst.IsMatrix() || rhst.IsMatrix() {
return false
}
return lhst.Equal(&rhst)
}
if op == Div && rhst.IsMatrix() {
return false
}
if op == ModOp {
if lhst.Main == IVec2 && rhst.Main == IVec2 {
return true
}
if lhst.Main == IVec3 && rhst.Main == IVec3 {
return true
}
if lhst.Main == IVec4 && rhst.Main == IVec4 {
return true
}
return (lhst.Main == Int || lhst.isIntVector()) && rhst.Main == Int
}
if lhst.Equal(&rhst) { if lhst.Equal(&rhst) {
return true return true
} }
if op == MatrixMul { if op == MatrixMul {
if lhst.IsMatrix() && (rhst.isFloatVector() || rhst.Main == Float) { if lhst.IsMatrix() && rhst.Main == Float {
// TODO: Check dimensions
return true return true
} }
if rhst.IsMatrix() && (lhst.isFloatVector() || lhst.Main == Float) { if lhst.Main == Mat2 && rhst.Main == Vec2 {
// TODO: Check dimensions return true
}
if lhst.Main == Mat3 && rhst.Main == Vec3 {
return true
}
if lhst.Main == Mat4 && rhst.Main == Vec4 {
return true
}
if lhst.Main == Float && rhst.IsMatrix() {
return true
}
if lhst.Main == Vec2 && rhst.Main == Mat2 {
return true
}
if lhst.Main == Vec3 && rhst.Main == Mat3 {
return true
}
if lhst.Main == Vec4 && rhst.Main == Mat4 {
return true return true
} }
return false return false
} }
if op == Div { if op == Div {
if lhst.IsMatrix() && (rhst.isFloatVector() || rhst.Main == Float) { if lhst.IsMatrix() && rhst.Main == Float {
// TODO: Check dimensions
return true return true
} }
// fallback // fallback