tint: Add operator support to intrinsic-gen
Adapt the builtin parsing and resolving to also support operators.
Will be used to generate intrinsic table entries for operators.
This will simplify maintenance of the operators, and will greatly
simplify the [AbstractInt -> i32|u32] [AbstractFloat -> f32|f16] logic.
Bug: tint:1504
Change-Id: Id75735ea24e501877418812185796f3fba88a521
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89026
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolve.go b/tools/src/cmd/intrinsic-gen/resolver/resolve.go
index f7f662a..3a09f38 100644
--- a/tools/src/cmd/intrinsic-gen/resolver/resolve.go
+++ b/tools/src/cmd/intrinsic-gen/resolver/resolve.go
@@ -28,7 +28,8 @@
s *sem.Sem
globals scope
- functions map[string]*sem.Function
+ builtins map[string]*sem.Intrinsic
+ operators map[string]*sem.Intrinsic
enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
}
@@ -38,7 +39,8 @@
a: a,
s: sem.New(),
globals: newScope(nil),
- functions: map[string]*sem.Function{},
+ builtins: map[string]*sem.Intrinsic{},
+ operators: map[string]*sem.Intrinsic{},
enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
}
// Declare and resolve all the enumerators
@@ -59,9 +61,15 @@
return nil, err
}
}
- // Declare and resolve the functions
- for _, f := range a.Functions {
- if err := r.function(f); err != nil {
+ // Declare and resolve the builtins
+ for _, f := range a.Builtins {
+ if err := r.intrinsic(f, r.builtins, &r.s.Builtins); err != nil {
+ return nil, err
+ }
+ }
+ // Declare and resolve the operators
+ for _, o := range a.Operators {
+ if err := r.intrinsic(o, r.operators, &r.s.Operators); err != nil {
return nil, err
}
}
@@ -220,18 +228,21 @@
return fmt.Errorf("'%v' cannot be used for matcher", a.Name)
}
-// function() resolves a function overload declaration.
-// The the first overload for the function creates and appends the sem.Function
-// to Sem.Functions. Subsequent overloads append their resolved overload to the
-// sem.Function.Overloads list.
-func (r *resolver) function(a ast.FunctionDecl) error {
- // If this is the first overload of the function, create and register the
- // semantic function.
- f := r.functions[a.Name]
- if f == nil {
- f = &sem.Function{Name: a.Name}
- r.functions[a.Name] = f
- r.s.Functions = append(r.s.Functions, f)
+// intrinsic() resolves a intrinsic overload declaration.
+// The the first overload for the intrinsic creates and appends the sem.Intrinsic
+// to Sem.Intrinsics. Subsequent overloads append their resolved overload to the
+// sem.intrinsic.Overloads list.
+func (r *resolver) intrinsic(
+ a ast.IntrinsicDecl,
+ intrinsicsByName map[string]*sem.Intrinsic,
+ semIntrinsics *[]*sem.Intrinsic) error {
+ // If this is the first overload of the intrinsic, create and register the
+ // semantic intrinsic.
+ intrinsic := intrinsicsByName[a.Name]
+ if intrinsic == nil {
+ intrinsic = &sem.Intrinsic{Name: a.Name}
+ intrinsicsByName[a.Name] = intrinsic
+ *semIntrinsics = append(*semIntrinsics, intrinsic)
}
// Create a new scope for resolving template parameters
@@ -246,7 +257,7 @@
// Construct the semantic overload
overload := &sem.Overload{
Decl: a,
- Function: f,
+ Intrinsic: intrinsic,
Parameters: make([]sem.Parameter, len(a.Parameters)),
TemplateParams: templateParams,
}
@@ -285,8 +296,8 @@
return fmt.Errorf("%v unknown decoration", a.Decorations[0].Source)
}
- // Append the overload to the function
- f.Overloads = append(f.Overloads, overload)
+ // Append the overload to the intrinsic
+ intrinsic.Overloads = append(intrinsic.Overloads, overload)
// Sort the template parameters by resolved type. Append these to
// sem.Overload.OpenTypes or sem.Overload.OpenNumbers based on their kind.
@@ -307,6 +318,10 @@
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)
@@ -495,11 +510,11 @@
}
// calculateUniqueParameterNames() iterates over all the parameters of all
-// overloads, calculating the list of unique parameter names
+// builtin overloads, calculating the list of unique parameter names
func (r *resolver) calculateUniqueParameterNames() []string {
set := map[string]struct{}{"": {}}
names := []string{}
- for _, f := range r.s.Functions {
+ for _, f := range r.s.Builtins {
for _, o := range f.Overloads {
for _, p := range o.Parameters {
if _, dup := set[p.Name]; !dup {
diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
index 1768dbf..9f3aac0 100644
--- a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
+++ b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go
@@ -139,7 +139,7 @@
`
type f32
type T<x>
-fn f(T<T<f32>>)`,
+fn f(T< T<f32> >)`,
success,
}, {
`enum E {A A}`,
@@ -299,6 +299,70 @@
`file.txt:4:14 cannot use template enum 'E' as template number`,
}, {
`
+type i
+enum e { a }
+op << (i) -> e`,
+ `file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`,
+ }, {
+ `
+type T<x>
+op << (T<u>)`,
+ `file.txt:2:10 cannot resolve 'u'`,
+ }, {
+ `
+op << ()`,
+ `file.txt:1:4 operators must have either 1 or 2 parameters`,
+ }, {
+ `
+type i
+op << (i, i, i)`,
+ `file.txt:2:4 operators must have either 1 or 2 parameters`,
+ }, {
+ `
+type x
+op << <T>(T<x>)`,
+ `file.txt:2:11 'T' template parameters do not accept template arguments`,
+ }, {
+ `
+type A<N: num>
+type B
+op << (A<B>)`,
+ `file.txt:3:10 cannot use type 'B' as template number`,
+ }, {
+ `
+type A<N>
+enum E { b }
+op << (A<b>)`,
+ `file.txt:3:10 cannot use enum entry 'E.b' as template type`,
+ }, {
+ `
+type T
+type P<N: num>
+match m: T
+op << (P<m>)`,
+ `file.txt:4:10 cannot use type matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { b }
+op << (P<E>)`,
+ `file.txt:3:10 cannot use enum 'E' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+op << (P<m>)`,
+ `file.txt:4:10 cannot use enum matcher 'm' as template number`,
+ }, {
+ `
+type P<N: num>
+enum E { a b }
+match m: a | b
+op << <M: m>(P<M>)`,
+ `file.txt:4:16 cannot use template enum 'E' as template number`,
+ }, {
+ `
enum E { a }
type T<X: a>`,
`file.txt:2:8 invalid template parameter type 'a'`,