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,21 +956,20 @@ 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};
@ -979,7 +978,6 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
candidates.emplace_back(Candidate{&overload, match_score}); candidates.emplace_back(Candidate{&overload, match_score});
} }
} }
}
// Sort the candidates with the most promising first // Sort the candidates with the most promising first
std::stable_sort(candidates.begin(), candidates.end(), std::stable_sort(candidates.begin(), candidates.end(),
@ -1013,51 +1011,50 @@ 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,
@ -1067,7 +1064,6 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
candidates.emplace_back(Candidate{&overload, match_score}); candidates.emplace_back(Candidate{&overload, match_score});
} }
} }
}
// Sort the candidates with the most promising first // Sort the candidates with the most promising first
std::stable_sort(candidates.begin(), candidates.end(), std::stable_sort(candidates.begin(), candidates.end(),

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 is a builtin function (max, fract, etc).
// Declared with 'fn'.
Builtin IntrinsicKind = "builtin" Builtin IntrinsicKind = "builtin"
// Operator is a unary or binary operator.
// Declared with 'op'.
Operator IntrinsicKind = "operator" Operator IntrinsicKind = "operator"
) )

View File

@ -43,7 +43,8 @@ type IntrinsicTable struct {
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,11 +69,20 @@ 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) {
case 1:
if err := r.intrinsic(o, r.unaryOperators, &r.s.UnaryOperators); err != nil {
return nil, err 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)
}
} }
// Calculate the unique parameter names // Calculate the unique parameter names
@ -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,8 +521,13 @@ 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,
r.s.UnaryOperators,
r.s.BinaryOperators,
} {
for _, i := range intrinsics {
for _, o := range i.Overloads {
for _, p := range o.Parameters { for _, p := range o.Parameters {
if _, dup := set[p.Name]; !dup { if _, dup := set[p.Name]; !dup {
set[p.Name] = struct{}{} set[p.Name] = struct{}{}
@ -524,6 +536,7 @@ func (r *resolver) calculateUniqueParameterNames() []string {
} }
} }
} }
}
sort.Strings(names) sort.Strings(names)
return names return names
} }

View File

@ -27,7 +27,8 @@ type Sem struct {
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
@ -44,7 +45,8 @@ func New() *Sem {
TypeMatchers: []*TypeMatcher{}, TypeMatchers: []*TypeMatcher{},
EnumMatchers: []*EnumMatcher{}, EnumMatchers: []*EnumMatcher{},
Builtins: []*Intrinsic{}, Builtins: []*Intrinsic{},
Operators: []*Intrinsic{}, UnaryOperators: []*Intrinsic{},
BinaryOperators: []*Intrinsic{},
} }
} }