| // Copyright (C) 2016 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package resolver |
| |
| import ( |
| "sort" |
| "strconv" |
| |
| "android.googlesource.com/platform/tools/gpu/api/ast" |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| ) |
| |
| func apiNames(rv *resolver, in *ast.API) { |
| if in.Index != nil { |
| if n, e := strconv.ParseUint(in.Index.Value, 10, 4); e == nil { |
| rv.api.Index = new(semantic.Uint8Value) |
| *rv.api.Index = semantic.Uint8Value(n) |
| } else { |
| rv.errorf(in.Index, "cannot convert API index %q into 4-bit unsigned integer", in.Index.Value) |
| } |
| } |
| // Build and register the high level semantic objects |
| for _, e := range in.Enums { |
| n := &semantic.Enum{AST: e, Named: semantic.Named(e.Name.Value)} |
| rv.api.Enums = append(rv.api.Enums, n) |
| semantic.Add(rv.api, n) |
| rv.addType(n) |
| } |
| for _, c := range in.Classes { |
| n := &semantic.Class{AST: c, Named: semantic.Named(c.Name.Value)} |
| rv.api.Classes = append(rv.api.Classes, n) |
| semantic.Add(rv.api, n) |
| rv.addType(n) |
| } |
| for _, p := range in.Pseudonyms { |
| n := &semantic.Pseudonym{AST: p, Named: semantic.Named(p.Name.Value)} |
| rv.api.Pseudonyms = append(rv.api.Pseudonyms, n) |
| semantic.Add(rv.api, n) |
| rv.addType(n) |
| } |
| for _, e := range in.Externs { |
| n := &semantic.Function{AST: e, Named: semantic.Named(e.Generic.Name.Value), Extern: true} |
| rv.api.Externs = append(rv.api.Externs, n) |
| semantic.Add(rv.api, n) |
| } |
| for _, m := range in.Commands { |
| f := &semantic.Function{AST: m, Named: semantic.Named(m.Generic.Name.Value)} |
| if !m.Parameters[0].This { |
| rv.api.Functions = append(rv.api.Functions, f) |
| semantic.Add(rv.api, f) |
| } else { |
| rv.api.Methods = append(rv.api.Methods, f) |
| } |
| } |
| for _, m := range in.Subroutines { |
| if m.Parameters[0].This { |
| rv.errorf(m.Parameters[0], "cannot use this on subroutines") |
| continue |
| } |
| if len(m.Generic.Arguments) > 0 { |
| rv.genericSubroutines[m.Generic.Name.Value] = newGenericSubroutine(rv, m) |
| } else { |
| f := &semantic.Function{AST: m, Named: semantic.Named(m.Generic.Name.Value), Subroutine: true} |
| rv.api.Subroutines = append(rv.api.Subroutines, f) |
| semantic.Add(rv.api, f) |
| } |
| } |
| for _, f := range in.Fields { |
| n := &semantic.Global{AST: f, Named: semantic.Named(f.Name.Value)} |
| rv.api.Globals = append(rv.api.Globals, n) |
| semantic.Add(rv.api, n) |
| } |
| // Add all the alias remaps |
| for _, a := range in.Aliases { |
| rv.addType(&semantic.Alias{AST: a, Named: semantic.Named(a.Name.Value)}) |
| } |
| for _, c := range in.Definitions { |
| n := &semantic.Definition{AST: c, Named: semantic.Named(c.Name.Value)} |
| rv.api.Definitions = append(rv.api.Definitions, n) |
| rv.addNamed(n) |
| } |
| for _, e := range in.LabelGroups { |
| labeledTypeName := e.LabeledType.Value |
| for _, al := range e.Labels { |
| sl := &semantic.Label{ |
| AST: al, |
| Named: semantic.Named(al.Name.Value), |
| } |
| |
| lls, ok := rv.labels[labeledTypeName] |
| if !ok { |
| rv.labels[labeledTypeName] = []*semantic.Label{sl} |
| } else { |
| rv.labels[labeledTypeName] = append(lls, sl) |
| } |
| } |
| } |
| } |
| |
| func resolve(rv *resolver) { |
| rv.globals = rv.scope |
| |
| if rv.api.Imported != nil { |
| rv.addSymbols(rv.api.Imported) |
| } |
| rv.addMembers(rv.api) |
| // First resolve enum entries |
| for _, e := range rv.api.Enums { |
| enum(rv, e) |
| } |
| // Now build collapsed enum lists |
| for _, e := range rv.api.Enums { |
| enumEntries(rv, e, e) |
| } |
| for _, p := range rv.api.Pseudonyms { |
| pseudonym(rv, p) |
| } |
| // Resolve and merge label entries |
| resolveLabels(rv) |
| |
| for _, c := range rv.api.Definitions { |
| definition(rv, c) |
| } |
| for _, g := range rv.api.Globals { |
| global(rv, g) |
| } |
| for _, e := range rv.api.Externs { |
| functionSignature(rv, e) |
| functionBody(rv, nil, e) |
| } |
| for _, c := range rv.api.Classes { |
| class(rv, c) |
| } |
| for _, s := range rv.api.Subroutines { |
| functionSignature(rv, s) |
| for _, p := range s.FullParameters { |
| if p.Type == semantic.AnyType { |
| rv.errorf(p, "cannot use any as parameter type on subroutines") |
| } |
| } |
| } |
| for _, s := range rv.api.Subroutines { |
| functionBody(rv, nil, s) |
| } |
| for _, f := range rv.api.Functions { |
| functionSignature(rv, f) |
| functionBody(rv, nil, f) |
| } |
| for _, f := range rv.api.Subroutines { |
| extractCalls(rv, f.Block) |
| removeDeadCode(rv, f.Block) |
| } |
| for _, f := range rv.api.Functions { |
| extractCalls(rv, f.Block) |
| removeDeadCode(rv, f.Block) |
| } |
| for _, f := range rv.api.Functions { |
| resolveFenceOrder(rv, f, visitedFuncs{}) |
| } |
| for _, m := range rv.api.Methods { |
| method(rv, m) |
| } |
| sort.Sort(functionsByName(rv.api.Externs)) |
| sort.Sort(slicesByName(rv.api.Slices)) |
| sort.Sort(mapsByName(rv.api.Maps)) |
| } |
| |
| func annotations(rv *resolver, in ast.Annotations) semantic.Annotations { |
| if len(in) == 0 { |
| return nil |
| } |
| out := semantic.Annotations{} |
| for _, a := range in { |
| entry := &semantic.Annotation{AST: a, Named: semantic.Named(a.Name.Value)} |
| for _, arg := range a.Arguments { |
| entry.Arguments = append(entry.Arguments, expression(rv, arg)) |
| } |
| out = append(out, entry) |
| rv.mappings.add(a, entry) |
| } |
| return out |
| } |
| |
| func global(rv *resolver, out *semantic.Global) { |
| if out.Type != nil { |
| return // already resolved. |
| } |
| |
| // Begin by assigning a void type to the global. |
| // This is done to avoid a stack overflow if the global's type resolves to |
| // the same global (for example 'x.y x'). |
| out.Type = semantic.VoidType |
| |
| in := out.AST |
| out.Annotations = annotations(rv, in.Annotations) |
| out.Type = type_(rv, in.Type) |
| if isVoid(out.Type) { |
| rv.errorf(in, "void typed global variable %s", out.Name()) |
| } |
| if in.Default != nil { |
| rv.with(out.Type, func() { |
| out.Default = expression(rv, in.Default) |
| }) |
| dt := out.Default.ExpressionType() |
| if !assignable(out.Type, dt) { |
| rv.errorf(in, "cannot assign %s to %s", typename(dt), typename(out.Type)) |
| } |
| } |
| rv.mappings.add(in, out) |
| } |
| |
| // slicesByName is used to sort the slice list by name for generated code stability |
| type slicesByName []*semantic.Slice |
| |
| func (a slicesByName) Len() int { return len(a) } |
| func (a slicesByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a slicesByName) Less(i, j int) bool { return a[i].Name() < a[j].Name() } |
| |
| // mapsByName is used to sort the map list by name for generated code stability |
| type mapsByName []*semantic.Map |
| |
| func (a mapsByName) Len() int { return len(a) } |
| func (a mapsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a mapsByName) Less(i, j int) bool { return a[i].Name() < a[j].Name() } |
| |
| // mapsByName is used to sort the map list by name for generated code stability |
| type functionsByName []*semantic.Function |
| |
| func (a functionsByName) Len() int { return len(a) } |
| func (a functionsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a functionsByName) Less(i, j int) bool { return a[i].Name() < a[j].Name() } |
| |
| // labelsByName is used to sort a slice of labels by their name |
| type labelsByName []*semantic.Label |
| |
| func (a labelsByName) Len() int { return len(a) } |
| func (a labelsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a labelsByName) Less(i, j int) bool { return a[i].Name() < a[j].Name() } |