2023-07-23 16:40:22 +02:00
|
|
|
// Copyright 2023 The Ebitengine Authors
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package shaderir
|
|
|
|
|
|
|
|
import (
|
|
|
|
"go/constant"
|
|
|
|
)
|
|
|
|
|
2023-07-24 05:29:27 +02:00
|
|
|
func AdjustConstTypesForBinaryOp(lhs, rhs constant.Value, lhst, rhst Type) (constant.Value, constant.Value, bool) {
|
|
|
|
if lhst.Main == None && rhst.Main == None {
|
|
|
|
if lhs.Kind() == rhs.Kind() {
|
|
|
|
return lhs, rhs, true
|
|
|
|
}
|
|
|
|
if lhs.Kind() == constant.Float && constant.ToFloat(rhs).Kind() != constant.Unknown {
|
|
|
|
return lhs, constant.ToFloat(rhs), true
|
|
|
|
}
|
|
|
|
if rhs.Kind() == constant.Float && constant.ToFloat(lhs).Kind() != constant.Unknown {
|
|
|
|
return constant.ToFloat(lhs), rhs, true
|
|
|
|
}
|
|
|
|
if lhs.Kind() == constant.Int && constant.ToInt(rhs).Kind() != constant.Unknown {
|
|
|
|
return lhs, constant.ToInt(rhs), true
|
|
|
|
}
|
|
|
|
if rhs.Kind() == constant.Int && constant.ToInt(lhs).Kind() != constant.Unknown {
|
|
|
|
return constant.ToInt(lhs), rhs, true
|
|
|
|
}
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
if lhst.Equal(&rhst) {
|
|
|
|
if lhs.Kind() == rhs.Kind() {
|
|
|
|
return lhs, rhs, true
|
|
|
|
}
|
|
|
|
// TODO: When to reach this?
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
if lhst.Main == None {
|
|
|
|
if rhst.Main == Float && constant.ToFloat(lhs).Kind() != constant.Unknown {
|
|
|
|
return constant.ToFloat(lhs), rhs, true
|
|
|
|
}
|
|
|
|
if rhst.Main == Int && constant.ToInt(lhs).Kind() != constant.Unknown {
|
|
|
|
return constant.ToInt(lhs), rhs, true
|
|
|
|
}
|
|
|
|
if rhst.Main == Bool && lhs.Kind() == constant.Bool {
|
|
|
|
return lhs, rhs, true
|
|
|
|
}
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
if rhst.Main == None {
|
|
|
|
if lhst.Main == Float && constant.ToFloat(rhs).Kind() != constant.Unknown {
|
|
|
|
return lhs, constant.ToFloat(rhs), true
|
|
|
|
}
|
|
|
|
if lhst.Main == Int && constant.ToInt(rhs).Kind() != constant.Unknown {
|
|
|
|
return lhs, constant.ToInt(rhs), true
|
|
|
|
}
|
|
|
|
if lhst.Main == Bool && rhs.Kind() == constant.Bool {
|
|
|
|
return lhs, rhs, true
|
|
|
|
}
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
2023-07-23 16:40:22 +02:00
|
|
|
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 both are untyped consts, compare the constants and try to truncate them if necessary.
|
|
|
|
if lhst.Main == None && rhst.Main == None {
|
2023-07-24 05:29:27 +02:00
|
|
|
// Assume that the constant types are already adjusted.
|
|
|
|
if lhs.Const.Kind() != rhs.Const.Kind() {
|
|
|
|
panic("shaderir: const types for a binary op must be adjusted")
|
|
|
|
}
|
|
|
|
|
2023-07-23 19:06:54 +02:00
|
|
|
// For %, both operands must be integers if both are constants. Truncatable to an integer is not enough.
|
|
|
|
if op == ModOp {
|
|
|
|
return lhs.Const.Kind() == constant.Int && rhs.Const.Kind() == constant.Int
|
|
|
|
}
|
2023-07-24 05:29:27 +02:00
|
|
|
return true
|
2023-07-23 16:40:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the types match, that's fine.
|
|
|
|
if lhst.Equal(&rhst) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// If lhs is untyped and rhs is not, compare the constant and the type and try to truncate the constant if necessary.
|
|
|
|
if lhst.Main == None {
|
2023-07-23 19:06:54 +02:00
|
|
|
// For %, if only one of the operands is a constant, try to truncate it.
|
|
|
|
if op == ModOp {
|
|
|
|
return constant.ToInt(lhs.Const).Kind() != constant.Unknown && rhst.Main == Int
|
|
|
|
}
|
2023-07-23 16:40:22 +02:00
|
|
|
if rhst.Main == Float {
|
|
|
|
return constant.ToFloat(lhs.Const).Kind() != constant.Unknown
|
|
|
|
}
|
|
|
|
if rhst.Main == Int {
|
|
|
|
return constant.ToInt(lhs.Const).Kind() != constant.Unknown
|
|
|
|
}
|
|
|
|
if rhst.Main == Bool {
|
|
|
|
return lhs.Const.Kind() == constant.Bool
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ditto.
|
|
|
|
if rhst.Main == None {
|
2023-07-23 19:06:54 +02:00
|
|
|
if op == ModOp {
|
|
|
|
return constant.ToInt(rhs.Const).Kind() != constant.Unknown && lhst.Main == Int
|
|
|
|
}
|
2023-07-23 16:40:22 +02:00
|
|
|
if lhst.Main == Float {
|
|
|
|
return constant.ToFloat(rhs.Const).Kind() != constant.Unknown
|
|
|
|
}
|
|
|
|
if lhst.Main == Int {
|
|
|
|
return constant.ToInt(rhs.Const).Kind() != constant.Unknown
|
|
|
|
}
|
|
|
|
if lhst.Main == Bool {
|
|
|
|
return rhs.Const.Kind() == constant.Bool
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|