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:
Ben Clayton 2022-05-13 14:35:37 +00:00 committed by Dawn LUCI CQ
parent 62bfd318ae
commit 77473b4699
7 changed files with 1490 additions and 1449 deletions

View File

@ -956,28 +956,26 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<uint32_t, const char*> { auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<uint32_t, const char*> {
switch (op) { switch (op) {
case ast::UnaryOp::kComplement: case ast::UnaryOp::kComplement:
return {kOperatorComplement, "operator ~ "}; return {kUnaryOperatorComplement, "operator ~ "};
case ast::UnaryOp::kNegation: case ast::UnaryOp::kNegation:
return {kOperatorMinus, "operator - "}; return {kUnaryOperatorMinus, "operator - "};
case ast::UnaryOp::kNot: case ast::UnaryOp::kNot:
return {kOperatorNot, "operator ! "}; return {kUnaryOperatorNot, "operator ! "};
default: default:
return {0, "<unknown>"}; return {0, "<unknown>"};
} }
}(); }();
auto& builtin = kOperators[intrinsic_index]; auto& builtin = kUnaryOperators[intrinsic_index];
for (uint32_t o = 0; o < builtin.num_overloads; o++) { for (uint32_t o = 0; o < builtin.num_overloads; o++) {
int match_score = 1000; int match_score = 1000;
auto& overload = builtin.overloads[o]; auto& overload = builtin.overloads[o];
if (overload.num_parameters == 1) { auto match = Match(intrinsic_name, intrinsic_index, overload, {arg}, match_score);
auto match = Match(intrinsic_name, intrinsic_index, overload, {arg}, match_score); if (match.return_type) {
if (match.return_type) { return UnaryOperator{match.return_type, match.parameters[0].type};
return UnaryOperator{match.return_type, match.parameters[0].type}; }
} if (match_score > 0) {
if (match_score > 0) { candidates.emplace_back(Candidate{&overload, match_score});
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*> { auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<uint32_t, const char*> {
switch (op) { switch (op) {
case ast::BinaryOp::kAnd: case ast::BinaryOp::kAnd:
return {kOperatorAnd, is_compound ? "operator &= " : "operator & "}; return {kBinaryOperatorAnd, is_compound ? "operator &= " : "operator & "};
case ast::BinaryOp::kOr: case ast::BinaryOp::kOr:
return {kOperatorOr, is_compound ? "operator |= " : "operator | "}; return {kBinaryOperatorOr, is_compound ? "operator |= " : "operator | "};
case ast::BinaryOp::kXor: case ast::BinaryOp::kXor:
return {kOperatorXor, is_compound ? "operator ^= " : "operator ^ "}; return {kBinaryOperatorXor, is_compound ? "operator ^= " : "operator ^ "};
case ast::BinaryOp::kLogicalAnd: case ast::BinaryOp::kLogicalAnd:
return {kOperatorLogicalAnd, "operator && "}; return {kBinaryOperatorLogicalAnd, "operator && "};
case ast::BinaryOp::kLogicalOr: case ast::BinaryOp::kLogicalOr:
return {kOperatorLogicalOr, "operator || "}; return {kBinaryOperatorLogicalOr, "operator || "};
case ast::BinaryOp::kEqual: case ast::BinaryOp::kEqual:
return {kOperatorEqual, "operator == "}; return {kBinaryOperatorEqual, "operator == "};
case ast::BinaryOp::kNotEqual: case ast::BinaryOp::kNotEqual:
return {kOperatorNotEqual, "operator != "}; return {kBinaryOperatorNotEqual, "operator != "};
case ast::BinaryOp::kLessThan: case ast::BinaryOp::kLessThan:
return {kOperatorLessThan, "operator < "}; return {kBinaryOperatorLessThan, "operator < "};
case ast::BinaryOp::kGreaterThan: case ast::BinaryOp::kGreaterThan:
return {kOperatorGreaterThan, "operator > "}; return {kBinaryOperatorGreaterThan, "operator > "};
case ast::BinaryOp::kLessThanEqual: case ast::BinaryOp::kLessThanEqual:
return {kOperatorLessThanEqual, "operator <= "}; return {kBinaryOperatorLessThanEqual, "operator <= "};
case ast::BinaryOp::kGreaterThanEqual: case ast::BinaryOp::kGreaterThanEqual:
return {kOperatorGreaterThanEqual, "operator >= "}; return {kBinaryOperatorGreaterThanEqual, "operator >= "};
case ast::BinaryOp::kShiftLeft: case ast::BinaryOp::kShiftLeft:
return {kOperatorShiftLeft, is_compound ? "operator <<= " : "operator << "}; return {kBinaryOperatorShiftLeft, is_compound ? "operator <<= " : "operator << "};
case ast::BinaryOp::kShiftRight: case ast::BinaryOp::kShiftRight:
return {kOperatorShiftRight, is_compound ? "operator >>= " : "operator >> "}; return {kBinaryOperatorShiftRight, is_compound ? "operator >>= " : "operator >> "};
case ast::BinaryOp::kAdd: case ast::BinaryOp::kAdd:
return {kOperatorPlus, is_compound ? "operator += " : "operator + "}; return {kBinaryOperatorPlus, is_compound ? "operator += " : "operator + "};
case ast::BinaryOp::kSubtract: case ast::BinaryOp::kSubtract:
return {kOperatorMinus, is_compound ? "operator -= " : "operator - "}; return {kBinaryOperatorMinus, is_compound ? "operator -= " : "operator - "};
case ast::BinaryOp::kMultiply: case ast::BinaryOp::kMultiply:
return {kOperatorStar, is_compound ? "operator *= " : "operator * "}; return {kBinaryOperatorStar, is_compound ? "operator *= " : "operator * "};
case ast::BinaryOp::kDivide: case ast::BinaryOp::kDivide:
return {kOperatorDivide, is_compound ? "operator /= " : "operator / "}; return {kBinaryOperatorDivide, is_compound ? "operator /= " : "operator / "};
case ast::BinaryOp::kModulo: case ast::BinaryOp::kModulo:
return {kOperatorModulo, is_compound ? "operator %= " : "operator % "}; return {kBinaryOperatorModulo, is_compound ? "operator %= " : "operator % "};
default: default:
return {0, "<unknown>"}; return {0, "<unknown>"};
} }
}(); }();
auto& builtin = kOperators[intrinsic_index]; auto& builtin = kBinaryOperators[intrinsic_index];
for (uint32_t o = 0; o < builtin.num_overloads; o++) { for (uint32_t o = 0; o < builtin.num_overloads; o++) {
int match_score = 1000; int match_score = 1000;
auto& overload = builtin.overloads[o]; auto& overload = builtin.overloads[o];
if (overload.num_parameters == 2) { auto match = Match(intrinsic_name, intrinsic_index, overload, {lhs, rhs}, match_score);
auto match = Match(intrinsic_name, intrinsic_index, overload, {lhs, rhs}, match_score); if (match.return_type) {
if (match.return_type) { return BinaryOperator{match.return_type, match.parameters[0].type,
return BinaryOperator{match.return_type, match.parameters[0].type, match.parameters[1].type};
match.parameters[1].type}; }
} if (match_score > 0) {
if (match_score > 0) { candidates.emplace_back(Candidate{&overload, match_score});
candidates.emplace_back(Candidate{&overload, match_score});
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -119,8 +119,8 @@ constexpr IntrinsicInfo kBuiltins[] = {
{{- end }} {{- end }}
}; };
constexpr IntrinsicInfo kOperators[] = { constexpr IntrinsicInfo kUnaryOperators[] = {
{{- range $i, $o := .Operators }} {{- range $i, $o := .UnaryOperators }}
{ {
/* [{{$i}}] */ /* [{{$i}}] */
{{- range $o.OverloadDescriptions }} {{- range $o.OverloadDescriptions }}
@ -132,8 +132,25 @@ constexpr IntrinsicInfo kOperators[] = {
{{- end }} {{- end }}
}; };
{{- range $i, $o := .Operators }} {{- range $i, $o := .UnaryOperators }}
constexpr uint8_t kOperator{{template "OperatorName" $o.Name}} = {{$i}}; 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 }} {{- end }}
// clang-format on // clang-format on

View File

@ -107,7 +107,11 @@ func (m MatcherDecl) Format(w fmt.State, verb rune) {
type IntrinsicKind string type IntrinsicKind string
const ( 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" Operator IntrinsicKind = "operator"
) )

View File

@ -37,13 +37,14 @@ type IntrinsicTable struct {
NMatchers []sem.Named NMatchers []sem.Named
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
MatcherIndices []int // kMatcherIndices table content MatcherIndices []int // kMatcherIndices table content
OpenTypes []OpenType // kOpenTypes table content OpenTypes []OpenType // kOpenTypes table content
OpenNumbers []OpenNumber // kOpenNumbers table content OpenNumbers []OpenNumber // kOpenNumbers table content
Parameters []Parameter // kParameters table content Parameters []Parameter // kParameters table content
Overloads []Overload // kOverloads table content Overloads []Overload // kOverloads table content
Builtins []Intrinsic // kBuiltins table content Builtins []Intrinsic // kBuiltins table content
Operators []Intrinsic // kOperators table content UnaryOperators []Intrinsic // kUnaryOperators table content
BinaryOperators []Intrinsic // kBinaryOperators table content
} }
// OpenType is used to create the C++ OpenTypeInfo structure // OpenType is used to create the C++ OpenTypeInfo structure
@ -361,9 +362,16 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
b.layoutMatchers(s) b.layoutMatchers(s)
buildIntrinsics := func(in []*sem.Intrinsic) ([]Intrinsic, error) { for _, intrinsics := range []struct {
out := make([]Intrinsic, len(in)) in []*sem.Intrinsic
for i, f := range in { 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)) overloads := make([]Overload, len(f.Overloads))
overloadDescriptions := make([]string, len(f.Overloads)) overloadDescriptions := make([]string, len(f.Overloads))
for i, o := range 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), OverloadsOffset: b.lut.overloads.Add(overloads),
} }
} }
return out, nil *intrinsics.out = out
}
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
} }
b.lut.matcherIndices.Compact() b.lut.matcherIndices.Compact()

View File

@ -29,7 +29,8 @@ type resolver struct {
globals scope globals scope
builtins map[string]*sem.Intrinsic 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 enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
} }
@ -40,7 +41,8 @@ func Resolve(a *ast.AST) (*sem.Sem, error) {
s: sem.New(), s: sem.New(),
globals: newScope(nil), globals: newScope(nil),
builtins: map[string]*sem.Intrinsic{}, 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{}, enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
} }
// Declare and resolve all the enumerators // Declare and resolve all the enumerators
@ -67,10 +69,19 @@ func Resolve(a *ast.AST) (*sem.Sem, error) {
return nil, err return nil, err
} }
} }
// Declare and resolve the operators // Declare and resolve the unary and binary operators
for _, o := range a.Operators { for _, o := range a.Operators {
if err := r.intrinsic(o, r.operators, &r.s.Operators); err != nil { switch len(o.Parameters) {
return nil, err 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) 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 // Resolve the parameters
for i, p := range a.Parameters { for i, p := range a.Parameters {
usage, err := r.fullyQualifiedName(&s, p.Type) 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 { func (r *resolver) calculateUniqueParameterNames() []string {
set := map[string]struct{}{"": {}} set := map[string]struct{}{"": {}}
names := []string{} names := []string{}
for _, f := range r.s.Builtins { for _, intrinsics := range [][]*sem.Intrinsic{
for _, o := range f.Overloads { r.s.Builtins,
for _, p := range o.Parameters { r.s.UnaryOperators,
if _, dup := set[p.Name]; !dup { r.s.BinaryOperators,
set[p.Name] = struct{}{} } {
names = append(names, p.Name) 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)
}
} }
} }
} }

View File

@ -22,12 +22,13 @@ import (
// Sem is the root of the semantic tree // Sem is the root of the semantic tree
type Sem struct { type Sem struct {
Enums []*Enum Enums []*Enum
Types []*Type Types []*Type
TypeMatchers []*TypeMatcher TypeMatchers []*TypeMatcher
EnumMatchers []*EnumMatcher EnumMatchers []*EnumMatcher
Builtins []*Intrinsic Builtins []*Intrinsic
Operators []*Intrinsic UnaryOperators []*Intrinsic
BinaryOperators []*Intrinsic
// Maximum number of open-types used across all builtins // Maximum number of open-types used across all builtins
MaxOpenTypes int MaxOpenTypes int
// Maximum number of open-numbers used across all builtins // Maximum number of open-numbers used across all builtins
@ -39,12 +40,13 @@ type Sem struct {
// New returns a new Sem // New returns a new Sem
func New() *Sem { func New() *Sem {
return &Sem{ return &Sem{
Enums: []*Enum{}, Enums: []*Enum{},
Types: []*Type{}, Types: []*Type{},
TypeMatchers: []*TypeMatcher{}, TypeMatchers: []*TypeMatcher{},
EnumMatchers: []*EnumMatcher{}, EnumMatchers: []*EnumMatcher{},
Builtins: []*Intrinsic{}, Builtins: []*Intrinsic{},
Operators: []*Intrinsic{}, UnaryOperators: []*Intrinsic{},
BinaryOperators: []*Intrinsic{},
} }
} }