tint: Split tables for unary and binary operators
Do the partitioning of unary and binary operators in the intrinsic table generators, instead of searching all operators at runtime. Will allow code to be simplified. Bug: tint:1504 Change-Id: I67246b954e530e0542b1b67c99fb34a756cf532a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90240 Commit-Queue: Ben Clayton <bclayton@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
62bfd318ae
commit
77473b4699
|
@ -956,28 +956,26 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
|||
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<uint32_t, const char*> {
|
||||
switch (op) {
|
||||
case ast::UnaryOp::kComplement:
|
||||
return {kOperatorComplement, "operator ~ "};
|
||||
return {kUnaryOperatorComplement, "operator ~ "};
|
||||
case ast::UnaryOp::kNegation:
|
||||
return {kOperatorMinus, "operator - "};
|
||||
return {kUnaryOperatorMinus, "operator - "};
|
||||
case ast::UnaryOp::kNot:
|
||||
return {kOperatorNot, "operator ! "};
|
||||
return {kUnaryOperatorNot, "operator ! "};
|
||||
default:
|
||||
return {0, "<unknown>"};
|
||||
}
|
||||
}();
|
||||
|
||||
auto& builtin = kOperators[intrinsic_index];
|
||||
auto& builtin = kUnaryOperators[intrinsic_index];
|
||||
for (uint32_t o = 0; o < builtin.num_overloads; o++) {
|
||||
int match_score = 1000;
|
||||
auto& overload = builtin.overloads[o];
|
||||
if (overload.num_parameters == 1) {
|
||||
auto match = Match(intrinsic_name, intrinsic_index, overload, {arg}, match_score);
|
||||
if (match.return_type) {
|
||||
return UnaryOperator{match.return_type, match.parameters[0].type};
|
||||
}
|
||||
if (match_score > 0) {
|
||||
candidates.emplace_back(Candidate{&overload, match_score});
|
||||
}
|
||||
auto match = Match(intrinsic_name, intrinsic_index, overload, {arg}, match_score);
|
||||
if (match.return_type) {
|
||||
return UnaryOperator{match.return_type, match.parameters[0].type};
|
||||
}
|
||||
if (match_score > 0) {
|
||||
candidates.emplace_back(Candidate{&overload, match_score});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,59 +1011,57 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
|||
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<uint32_t, const char*> {
|
||||
switch (op) {
|
||||
case ast::BinaryOp::kAnd:
|
||||
return {kOperatorAnd, is_compound ? "operator &= " : "operator & "};
|
||||
return {kBinaryOperatorAnd, is_compound ? "operator &= " : "operator & "};
|
||||
case ast::BinaryOp::kOr:
|
||||
return {kOperatorOr, is_compound ? "operator |= " : "operator | "};
|
||||
return {kBinaryOperatorOr, is_compound ? "operator |= " : "operator | "};
|
||||
case ast::BinaryOp::kXor:
|
||||
return {kOperatorXor, is_compound ? "operator ^= " : "operator ^ "};
|
||||
return {kBinaryOperatorXor, is_compound ? "operator ^= " : "operator ^ "};
|
||||
case ast::BinaryOp::kLogicalAnd:
|
||||
return {kOperatorLogicalAnd, "operator && "};
|
||||
return {kBinaryOperatorLogicalAnd, "operator && "};
|
||||
case ast::BinaryOp::kLogicalOr:
|
||||
return {kOperatorLogicalOr, "operator || "};
|
||||
return {kBinaryOperatorLogicalOr, "operator || "};
|
||||
case ast::BinaryOp::kEqual:
|
||||
return {kOperatorEqual, "operator == "};
|
||||
return {kBinaryOperatorEqual, "operator == "};
|
||||
case ast::BinaryOp::kNotEqual:
|
||||
return {kOperatorNotEqual, "operator != "};
|
||||
return {kBinaryOperatorNotEqual, "operator != "};
|
||||
case ast::BinaryOp::kLessThan:
|
||||
return {kOperatorLessThan, "operator < "};
|
||||
return {kBinaryOperatorLessThan, "operator < "};
|
||||
case ast::BinaryOp::kGreaterThan:
|
||||
return {kOperatorGreaterThan, "operator > "};
|
||||
return {kBinaryOperatorGreaterThan, "operator > "};
|
||||
case ast::BinaryOp::kLessThanEqual:
|
||||
return {kOperatorLessThanEqual, "operator <= "};
|
||||
return {kBinaryOperatorLessThanEqual, "operator <= "};
|
||||
case ast::BinaryOp::kGreaterThanEqual:
|
||||
return {kOperatorGreaterThanEqual, "operator >= "};
|
||||
return {kBinaryOperatorGreaterThanEqual, "operator >= "};
|
||||
case ast::BinaryOp::kShiftLeft:
|
||||
return {kOperatorShiftLeft, is_compound ? "operator <<= " : "operator << "};
|
||||
return {kBinaryOperatorShiftLeft, is_compound ? "operator <<= " : "operator << "};
|
||||
case ast::BinaryOp::kShiftRight:
|
||||
return {kOperatorShiftRight, is_compound ? "operator >>= " : "operator >> "};
|
||||
return {kBinaryOperatorShiftRight, is_compound ? "operator >>= " : "operator >> "};
|
||||
case ast::BinaryOp::kAdd:
|
||||
return {kOperatorPlus, is_compound ? "operator += " : "operator + "};
|
||||
return {kBinaryOperatorPlus, is_compound ? "operator += " : "operator + "};
|
||||
case ast::BinaryOp::kSubtract:
|
||||
return {kOperatorMinus, is_compound ? "operator -= " : "operator - "};
|
||||
return {kBinaryOperatorMinus, is_compound ? "operator -= " : "operator - "};
|
||||
case ast::BinaryOp::kMultiply:
|
||||
return {kOperatorStar, is_compound ? "operator *= " : "operator * "};
|
||||
return {kBinaryOperatorStar, is_compound ? "operator *= " : "operator * "};
|
||||
case ast::BinaryOp::kDivide:
|
||||
return {kOperatorDivide, is_compound ? "operator /= " : "operator / "};
|
||||
return {kBinaryOperatorDivide, is_compound ? "operator /= " : "operator / "};
|
||||
case ast::BinaryOp::kModulo:
|
||||
return {kOperatorModulo, is_compound ? "operator %= " : "operator % "};
|
||||
return {kBinaryOperatorModulo, is_compound ? "operator %= " : "operator % "};
|
||||
default:
|
||||
return {0, "<unknown>"};
|
||||
}
|
||||
}();
|
||||
|
||||
auto& builtin = kOperators[intrinsic_index];
|
||||
auto& builtin = kBinaryOperators[intrinsic_index];
|
||||
for (uint32_t o = 0; o < builtin.num_overloads; o++) {
|
||||
int match_score = 1000;
|
||||
auto& overload = builtin.overloads[o];
|
||||
if (overload.num_parameters == 2) {
|
||||
auto match = Match(intrinsic_name, intrinsic_index, overload, {lhs, rhs}, match_score);
|
||||
if (match.return_type) {
|
||||
return BinaryOperator{match.return_type, match.parameters[0].type,
|
||||
match.parameters[1].type};
|
||||
}
|
||||
if (match_score > 0) {
|
||||
candidates.emplace_back(Candidate{&overload, match_score});
|
||||
}
|
||||
auto match = Match(intrinsic_name, intrinsic_index, overload, {lhs, rhs}, match_score);
|
||||
if (match.return_type) {
|
||||
return BinaryOperator{match.return_type, match.parameters[0].type,
|
||||
match.parameters[1].type};
|
||||
}
|
||||
if (match_score > 0) {
|
||||
candidates.emplace_back(Candidate{&overload, match_score});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -119,8 +119,8 @@ constexpr IntrinsicInfo kBuiltins[] = {
|
|||
{{- end }}
|
||||
};
|
||||
|
||||
constexpr IntrinsicInfo kOperators[] = {
|
||||
{{- range $i, $o := .Operators }}
|
||||
constexpr IntrinsicInfo kUnaryOperators[] = {
|
||||
{{- range $i, $o := .UnaryOperators }}
|
||||
{
|
||||
/* [{{$i}}] */
|
||||
{{- range $o.OverloadDescriptions }}
|
||||
|
@ -132,8 +132,25 @@ constexpr IntrinsicInfo kOperators[] = {
|
|||
{{- end }}
|
||||
};
|
||||
|
||||
{{- range $i, $o := .Operators }}
|
||||
constexpr uint8_t kOperator{{template "OperatorName" $o.Name}} = {{$i}};
|
||||
{{- range $i, $o := .UnaryOperators }}
|
||||
constexpr uint8_t kUnaryOperator{{template "OperatorName" $o.Name}} = {{$i}};
|
||||
{{- end }}
|
||||
|
||||
constexpr IntrinsicInfo kBinaryOperators[] = {
|
||||
{{- range $i, $o := .BinaryOperators }}
|
||||
{
|
||||
/* [{{$i}}] */
|
||||
{{- range $o.OverloadDescriptions }}
|
||||
/* {{.}} */
|
||||
{{- end }}
|
||||
/* num overloads */ {{$o.NumOverloads}},
|
||||
/* overloads */ &kOverloads[{{$o.OverloadsOffset}}],
|
||||
},
|
||||
{{- end }}
|
||||
};
|
||||
|
||||
{{- range $i, $o := .BinaryOperators }}
|
||||
constexpr uint8_t kBinaryOperator{{template "OperatorName" $o.Name}} = {{$i}};
|
||||
{{- end }}
|
||||
|
||||
// clang-format on
|
||||
|
|
|
@ -107,7 +107,11 @@ func (m MatcherDecl) Format(w fmt.State, verb rune) {
|
|||
type IntrinsicKind string
|
||||
|
||||
const (
|
||||
Builtin IntrinsicKind = "builtin"
|
||||
// Builtin is a builtin function (max, fract, etc).
|
||||
// Declared with 'fn'.
|
||||
Builtin IntrinsicKind = "builtin"
|
||||
// Operator is a unary or binary operator.
|
||||
// Declared with 'op'.
|
||||
Operator IntrinsicKind = "operator"
|
||||
)
|
||||
|
||||
|
|
|
@ -37,13 +37,14 @@ type IntrinsicTable struct {
|
|||
NMatchers []sem.Named
|
||||
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
|
||||
|
||||
MatcherIndices []int // kMatcherIndices table content
|
||||
OpenTypes []OpenType // kOpenTypes table content
|
||||
OpenNumbers []OpenNumber // kOpenNumbers table content
|
||||
Parameters []Parameter // kParameters table content
|
||||
Overloads []Overload // kOverloads table content
|
||||
Builtins []Intrinsic // kBuiltins table content
|
||||
Operators []Intrinsic // kOperators table content
|
||||
MatcherIndices []int // kMatcherIndices table content
|
||||
OpenTypes []OpenType // kOpenTypes table content
|
||||
OpenNumbers []OpenNumber // kOpenNumbers table content
|
||||
Parameters []Parameter // kParameters table content
|
||||
Overloads []Overload // kOverloads table content
|
||||
Builtins []Intrinsic // kBuiltins table content
|
||||
UnaryOperators []Intrinsic // kUnaryOperators table content
|
||||
BinaryOperators []Intrinsic // kBinaryOperators table content
|
||||
}
|
||||
|
||||
// OpenType is used to create the C++ OpenTypeInfo structure
|
||||
|
@ -361,9 +362,16 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
|
|||
|
||||
b.layoutMatchers(s)
|
||||
|
||||
buildIntrinsics := func(in []*sem.Intrinsic) ([]Intrinsic, error) {
|
||||
out := make([]Intrinsic, len(in))
|
||||
for i, f := range in {
|
||||
for _, intrinsics := range []struct {
|
||||
in []*sem.Intrinsic
|
||||
out *[]Intrinsic
|
||||
}{
|
||||
{s.Builtins, &b.Builtins},
|
||||
{s.UnaryOperators, &b.UnaryOperators},
|
||||
{s.BinaryOperators, &b.BinaryOperators},
|
||||
} {
|
||||
out := make([]Intrinsic, len(intrinsics.in))
|
||||
for i, f := range intrinsics.in {
|
||||
overloads := make([]Overload, len(f.Overloads))
|
||||
overloadDescriptions := make([]string, len(f.Overloads))
|
||||
for i, o := range f.Overloads {
|
||||
|
@ -380,15 +388,7 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
|
|||
OverloadsOffset: b.lut.overloads.Add(overloads),
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
if b.Builtins, err = buildIntrinsics(s.Builtins); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b.Operators, err = buildIntrinsics(s.Operators); err != nil {
|
||||
return nil, err
|
||||
*intrinsics.out = out
|
||||
}
|
||||
|
||||
b.lut.matcherIndices.Compact()
|
||||
|
|
|
@ -29,7 +29,8 @@ type resolver struct {
|
|||
|
||||
globals scope
|
||||
builtins map[string]*sem.Intrinsic
|
||||
operators map[string]*sem.Intrinsic
|
||||
unaryOperators map[string]*sem.Intrinsic
|
||||
binaryOperators map[string]*sem.Intrinsic
|
||||
enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,8 @@ func Resolve(a *ast.AST) (*sem.Sem, error) {
|
|||
s: sem.New(),
|
||||
globals: newScope(nil),
|
||||
builtins: map[string]*sem.Intrinsic{},
|
||||
operators: map[string]*sem.Intrinsic{},
|
||||
unaryOperators: map[string]*sem.Intrinsic{},
|
||||
binaryOperators: map[string]*sem.Intrinsic{},
|
||||
enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
|
||||
}
|
||||
// Declare and resolve all the enumerators
|
||||
|
@ -67,10 +69,19 @@ func Resolve(a *ast.AST) (*sem.Sem, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
// Declare and resolve the operators
|
||||
// Declare and resolve the unary and binary operators
|
||||
for _, o := range a.Operators {
|
||||
if err := r.intrinsic(o, r.operators, &r.s.Operators); err != nil {
|
||||
return nil, err
|
||||
switch len(o.Parameters) {
|
||||
case 1:
|
||||
if err := r.intrinsic(o, r.unaryOperators, &r.s.UnaryOperators); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 2:
|
||||
if err := r.intrinsic(o, r.binaryOperators, &r.s.BinaryOperators); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("%v operators must have either 1 or 2 parameters", o.Source)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,10 +329,6 @@ func (r *resolver) intrinsic(
|
|||
r.s.MaxOpenNumbers = len(overload.OpenNumbers)
|
||||
}
|
||||
|
||||
if a.Kind == ast.Operator && (len(a.Parameters) < 1 || len(a.Parameters) > 2) {
|
||||
return fmt.Errorf("%v operators must have either 1 or 2 parameters", a.Source)
|
||||
}
|
||||
|
||||
// Resolve the parameters
|
||||
for i, p := range a.Parameters {
|
||||
usage, err := r.fullyQualifiedName(&s, p.Type)
|
||||
|
@ -514,12 +521,18 @@ func (r *resolver) lookupNamed(s *scope, a ast.TemplatedName) (sem.Named, error)
|
|||
func (r *resolver) calculateUniqueParameterNames() []string {
|
||||
set := map[string]struct{}{"": {}}
|
||||
names := []string{}
|
||||
for _, f := range r.s.Builtins {
|
||||
for _, o := range f.Overloads {
|
||||
for _, p := range o.Parameters {
|
||||
if _, dup := set[p.Name]; !dup {
|
||||
set[p.Name] = struct{}{}
|
||||
names = append(names, p.Name)
|
||||
for _, intrinsics := range [][]*sem.Intrinsic{
|
||||
r.s.Builtins,
|
||||
r.s.UnaryOperators,
|
||||
r.s.BinaryOperators,
|
||||
} {
|
||||
for _, i := range intrinsics {
|
||||
for _, o := range i.Overloads {
|
||||
for _, p := range o.Parameters {
|
||||
if _, dup := set[p.Name]; !dup {
|
||||
set[p.Name] = struct{}{}
|
||||
names = append(names, p.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,12 +22,13 @@ import (
|
|||
|
||||
// Sem is the root of the semantic tree
|
||||
type Sem struct {
|
||||
Enums []*Enum
|
||||
Types []*Type
|
||||
TypeMatchers []*TypeMatcher
|
||||
EnumMatchers []*EnumMatcher
|
||||
Builtins []*Intrinsic
|
||||
Operators []*Intrinsic
|
||||
Enums []*Enum
|
||||
Types []*Type
|
||||
TypeMatchers []*TypeMatcher
|
||||
EnumMatchers []*EnumMatcher
|
||||
Builtins []*Intrinsic
|
||||
UnaryOperators []*Intrinsic
|
||||
BinaryOperators []*Intrinsic
|
||||
// Maximum number of open-types used across all builtins
|
||||
MaxOpenTypes int
|
||||
// Maximum number of open-numbers used across all builtins
|
||||
|
@ -39,12 +40,13 @@ type Sem struct {
|
|||
// New returns a new Sem
|
||||
func New() *Sem {
|
||||
return &Sem{
|
||||
Enums: []*Enum{},
|
||||
Types: []*Type{},
|
||||
TypeMatchers: []*TypeMatcher{},
|
||||
EnumMatchers: []*EnumMatcher{},
|
||||
Builtins: []*Intrinsic{},
|
||||
Operators: []*Intrinsic{},
|
||||
Enums: []*Enum{},
|
||||
Types: []*Type{},
|
||||
TypeMatchers: []*TypeMatcher{},
|
||||
EnumMatchers: []*EnumMatcher{},
|
||||
Builtins: []*Intrinsic{},
|
||||
UnaryOperators: []*Intrinsic{},
|
||||
BinaryOperators: []*Intrinsic{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue