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*> {
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

View File

@ -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

View File

@ -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"
)

View File

@ -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()

View File

@ -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)
}
}
}
}

View File

@ -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{},
}
}