[tint][fuzz] Generate `dictionary.txt` from .def files
Change-Id: I7f575a0f65cb371183aa8a3543cd762071f62345
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184163
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt b/src/tint/cmd/fuzz/wgsl/dictionary.txt
index 59742d7..cc0d9d3 100644
--- a/src/tint/cmd/fuzz/wgsl/dictionary.txt
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt
@@ -1,3 +1,39 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
"!"
"!="
"%"
@@ -38,17 +74,48 @@
"^"
"^="
"_"
-"{"
-"|"
-"|="
-"||"
-"}"
-"~"
+"__atomic_compare_exchange_result"
+"__atomic_compare_exchange_result_i32"
+"__atomic_compare_exchange_result_u32"
+"__frexp_result"
+"__frexp_result_abstract"
+"__frexp_result_f16"
+"__frexp_result_f32"
+"__frexp_result_vec"
+"__frexp_result_vec2_abstract"
+"__frexp_result_vec2_f16"
+"__frexp_result_vec2_f32"
+"__frexp_result_vec3_abstract"
+"__frexp_result_vec3_f16"
+"__frexp_result_vec3_f32"
+"__frexp_result_vec4_abstract"
+"__frexp_result_vec4_f16"
+"__frexp_result_vec4_f32"
+"__in"
+"__modf_result"
+"__modf_result_abstract"
+"__modf_result_f16"
+"__modf_result_f32"
+"__modf_result_vec"
+"__modf_result_vec2_abstract"
+"__modf_result_vec2_f16"
+"__modf_result_vec2_f32"
+"__modf_result_vec3_abstract"
+"__modf_result_vec3_f16"
+"__modf_result_vec3_f32"
+"__modf_result_vec4_abstract"
+"__modf_result_vec4_f16"
+"__modf_result_vec4_f32"
+"__out"
+"__packed_vec3"
+"__point_size"
+"__tint_materialize"
"a"
"abs"
"acos"
"acosh"
-"@align"
+"alias"
+"align"
"all"
"any"
"array"
@@ -61,6 +128,8 @@
"atomic"
"atomicAdd"
"atomicAnd"
+"atomicCompareExchangeWeak"
+"atomicExchange"
"atomicLoad"
"atomicMax"
"atomicMin"
@@ -69,31 +138,35 @@
"atomicSub"
"atomicXor"
"b"
-"@binding"
+"bgra8unorm"
+"binding"
"bitcast"
+"blend_src"
"bool"
"break"
-"@builtin"
-"@builtin(frag_depth)"
-"@builtin(front_facing)"
-"@builtin(global_invocation_id)"
-"@builtin(instance_index)"
-"@builtin(local_invocation_id)"
-"@builtin(local_invocation_index)"
-"@builtin(num_workgroups)"
-"@builtin(position)"
-"@builtin(sample_index)"
-"@builtin(sample_mask)"
-"@builtin(vertex_index)"
-"@builtin(workgroup_id)"
+"builtin"
"case"
"ceil"
"center"
"centroid"
+"chromium_disable_uniformity_analysis"
+"chromium_experimental_framebuffer_fetch"
+"chromium_experimental_pixel_local"
+"chromium_experimental_push_constant"
+"chromium_experimental_subgroups"
+"chromium_internal_dual_source_blending"
+"chromium_internal_graphite"
+"chromium_internal_relaxed_uniform_layout"
+"chromium_testing_experimental"
+"chromium_testing_shipped"
+"chromium_testing_shipped_with_killswitch"
+"chromium_testing_unimplemented"
+"chromium_testing_unsafe_experimental"
"clamp"
-"@compute"
-"@const"
+"color"
+"compute"
"const"
+"const_assert"
"continue"
"continuing"
"cos"
@@ -104,7 +177,9 @@
"cross"
"default"
"degrees"
+"derivative_uniformity"
"determinant"
+"diagnostic"
"discard"
"distance"
"dot"
@@ -118,11 +193,13 @@
"dpdyFine"
"else"
"enable"
+"error"
"exp"
"exp2"
"extractBits"
"f16"
"f32"
+"fa"
"faceForward"
"fallthrough"
"false"
@@ -135,7 +212,7 @@
"for"
"fract"
"frag_depth"
-"@fragment"
+"fragment"
"frexp"
"front_facing"
"function"
@@ -144,14 +221,17 @@
"fwidthFine"
"g"
"global_invocation_id"
-"@group"
+"group"
+"handle"
"i32"
-"@id"
+"ia"
+"id"
"if"
+"info"
"insertBits"
"instance_index"
-"@interpolate"
-"@invariant"
+"interpolate"
+"invariant"
"inverseSqrt"
"ldexp"
"length"
@@ -159,46 +239,80 @@
"linear"
"local_invocation_id"
"local_invocation_index"
-"@location"
+"location"
"log"
"log2"
"loop"
+"mat"
"mat2x2"
+"mat2x2f"
+"mat2x2h"
"mat2x3"
+"mat2x3f"
+"mat2x3h"
"mat2x4"
+"mat2x4f"
+"mat2x4h"
"mat3x2"
+"mat3x2f"
+"mat3x2h"
"mat3x3"
+"mat3x3f"
+"mat3x3h"
"mat3x4"
+"mat3x4f"
+"mat3x4h"
"mat4x2"
+"mat4x2f"
+"mat4x2h"
"mat4x3"
+"mat4x3f"
+"mat4x3h"
"mat4x4"
+"mat4x4f"
+"mat4x4h"
"max"
"min"
"mix"
"modf"
+"must_use"
"normalize"
"num_workgroups"
+"off"
"override"
"pack2x16float"
"pack2x16snorm"
"pack2x16unorm"
"pack4x8snorm"
"pack4x8unorm"
+"pack4xI8"
+"pack4xI8Clamp"
+"pack4xU8"
+"pack4xU8Clamp"
+"packedVec3"
+"packed_4x8_integer_dot_product"
"perspective"
+"pixel_local"
+"pointer_composite_access"
"position"
"pow"
"private"
"ptr"
+"push_constant"
"quantizeToF16"
"r"
"r32float"
"r32sint"
"r32uint"
+"r8unorm"
"radians"
"read"
"read_write"
+"readonly_and_readwrite_storage_textures"
+"ref"
"reflect"
"refract"
+"requires"
"return"
"reverseBits"
"rg32float"
@@ -225,17 +339,36 @@
"sign"
"sin"
"sinh"
-"@size"
+"size"
"smoothstep"
"sqrt"
-"staticAssert"
"step"
"storage"
"storageBarrier"
"struct"
+"subgroupBallot"
+"subgroupBroadcast"
+"subgroup_invocation_id"
+"subgroup_size"
"switch"
"tan"
"tanh"
+"textureBarrier"
+"textureDimensions"
+"textureGather"
+"textureGatherCompare"
+"textureLoad"
+"textureNumLayers"
+"textureNumLevels"
+"textureNumSamples"
+"textureSample"
+"textureSampleBaseClampToEdge"
+"textureSampleBias"
+"textureSampleCompare"
+"textureSampleCompareLevel"
+"textureSampleGrad"
+"textureSampleLevel"
+"textureStore"
"texture_1d"
"texture_2d"
"texture_2d_array"
@@ -247,29 +380,15 @@
"texture_depth_cube"
"texture_depth_cube_array"
"texture_depth_multisampled_2d"
-"textureDimensions"
-"textureGather"
-"textureGatherCompare"
-"textureLoad"
+"texture_external"
"texture_multisampled_2d"
-"textureNumLayers"
-"textureNumLevels"
-"textureNumSamples"
-"textureSample"
-"textureSampleBias"
-"textureSampleCompare"
-"textureSampleCompareLevel"
-"textureSampleGrad"
-"textureSampleLevel"
"texture_storage_1d"
"texture_storage_2d"
"texture_storage_2d_array"
"texture_storage_3d"
-"textureStore"
"transpose"
"true"
"trunc"
-"type"
"u32"
"uniform"
"unpack2x16float"
@@ -277,20 +396,44 @@
"unpack2x16unorm"
"unpack4x8snorm"
"unpack4x8unorm"
+"unpack4xI8"
+"unpack4xU8"
+"unreachable_code"
+"unrestricted_pointer_parameters"
"var"
+"vec"
"vec2"
+"vec2f"
+"vec2h"
+"vec2i"
+"vec2u"
"vec3"
+"vec3f"
+"vec3h"
+"vec3i"
+"vec3u"
"vec4"
-"@vertex"
+"vec4f"
+"vec4h"
+"vec4i"
+"vec4u"
+"vertex"
"vertex_index"
"w"
+"warning"
"while"
"workgroup"
"workgroupBarrier"
"workgroupUniformLoad"
"workgroup_id"
-"@workgroup_size"
+"workgroup_size"
"write"
"x"
"y"
"z"
+"{"
+"|"
+"|="
+"||"
+"}"
+"~"
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl b/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
new file mode 100644
index 0000000..5ffad37
--- /dev/null
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt.tmpl
@@ -0,0 +1,129 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate dictionary.txt
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- SetCommentPrefix "#" -}}
+{{- $W := LoadIntrinsics "src/tint/lang/wgsl/wgsl.def" -}}
+{{- $C := LoadIntrinsics "src/tint/lang/core/core.def" -}}
+
+{{- $tokens := List}}
+
+{{- /* ============================== Operators ============================== */ -}}
+{{- $tokens = Append $tokens
+ "!"
+ "!="
+ "%"
+ "%="
+ "&"
+ "&&"
+ "&="
+ "("
+ ")"
+ "*"
+ "*="
+ "+"
+ "++"
+ "+="
+ ","
+ "-"
+ "--"
+ "-="
+ "->"
+ "."
+ "/"
+ "/="
+ ":"
+ ";"
+ "<"
+ "<<"
+ "<<="
+ "<="
+ "="
+ "=="
+ ">"
+ ">="
+ ">>"
+ ">>="
+ "@"
+ "["
+ "]"
+ "^"
+ "^="
+ "_"
+ "{"
+ "|"
+ "|="
+ "||"
+ "}"
+ "~"
+ "alias"
+ "break"
+ "case"
+ "const"
+ "const_assert"
+ "continue"
+ "continuing"
+ "diagnostic"
+ "discard"
+ "default"
+ "else"
+ "enable"
+ "fallthrough"
+ "false"
+ "fn"
+ "for"
+ "if"
+ "let"
+ "loop"
+ "override"
+ "return"
+ "requires"
+ "struct"
+ "switch"
+ "true"
+ "var"
+ "while"
+-}}
+
+{{- /* ============================== Swizzles =============================== */ -}}
+{{- $tokens = Append $tokens
+ "x" "y" "z" "w"
+ "r" "g" "b" "a"
+-}}
+
+{{- /* ============================ Boolean values =========================== */ -}}
+{{- $tokens = Append $tokens
+ "true" "false"
+-}}
+
+{{- /* ========================== Builtin functions ========================== */ -}}
+{{- range $W.Sem.Builtins}}{{$tokens = Append $tokens .Name}}{{end -}}
+
+{{- /* ================================ Types ================================ */ -}}
+{{- range $W.Sem.Types}}{{$tokens = Append $tokens .Name}}{{end -}}
+
+{{- /* ============================= Enumerators ============================= */ -}}
+{{- range $W.Sem.Enums}}
+ {{- range .Entries}}
+ {{- $tokens = Append $tokens .Name}}
+ {{- end}}
+{{- end}}
+{{- range $C.Sem.Enums}}
+ {{- range .Entries}}
+ {{- $tokens = Append $tokens .Name}}
+ {{- end}}
+{{- end}}
+
+{{- $tokens = SortUnique $tokens}}
+
+{{- range $tokens}}"{{.}}"
+{{end -}}
diff --git a/tools/src/cmd/gen/templates/templates.go b/tools/src/cmd/gen/templates/templates.go
index 5dd5b16..99158bf 100644
--- a/tools/src/cmd/gen/templates/templates.go
+++ b/tools/src/cmd/gen/templates/templates.go
@@ -31,7 +31,6 @@
"context"
"flag"
"fmt"
- "io"
"math/rand"
"os"
"path/filepath"
@@ -118,9 +117,23 @@
// Create or update the file at relPath if the file content has changed,
// preserving the copyright year in the header.
// relPath is a path relative to the template
- writeFile := func(relPath, body string) error {
+ writeFile := func(relPath, body, commentPrefix string) error {
+ if strings.TrimSpace(body) == "" {
+ // Don't write empty files
+ return nil
+ }
+
outPath := filepath.Join(tmplDir, relPath)
+ switch filepath.Ext(relPath) {
+ case ".cc", ".h", ".inl":
+ var err error
+ body, err = common.ClangFormat(body)
+ if err != nil {
+ return err
+ }
+ }
+
// Load the old file
existing, err := os.ReadFile(outPath)
if err != nil {
@@ -132,7 +145,7 @@
fmt.Println(" writing", outPath)
}
sb := strings.Builder{}
- sb.WriteString(common.Header(string(existing), filepath.ToSlash(relTmplPath), "//"))
+ sb.WriteString(common.Header(string(existing), filepath.ToSlash(relTmplPath), commentPrefix))
sb.WriteString("\n")
sb.WriteString(body)
oldContent, newContent := string(existing), sb.String()
@@ -154,28 +167,11 @@
}
// Write the content generated using the template and semantic info
- sb := strings.Builder{}
- if err := generate(tmplPath, cache, &sb, writeFile); err != nil {
+ _, tmplFileName := filepath.Split(tmplPath)
+ outPath := strings.TrimSuffix(tmplFileName, ".tmpl")
+ if err := generate(tmplPath, outPath, cache, writeFile); err != nil {
return fmt.Errorf("while processing '%v': %w", tmplPath, err)
}
-
- if body := sb.String(); body != "" {
- _, tmplFileName := filepath.Split(tmplPath)
- outFileName := strings.TrimSuffix(tmplFileName, ".tmpl")
-
- switch filepath.Ext(outFileName) {
- case ".cc", ".h", ".inl":
- var err error
- body, err = common.ClangFormat(body)
- if err != nil {
- return err
- }
- }
-
- if err := writeFile(outFileName, body); err != nil {
- return err
- }
- }
}
if len(staleFiles) > 0 {
@@ -274,28 +270,38 @@
}
type generator struct {
- cache *genCache
- writeFile WriteFile
- rnd *rand.Rand
+ cache *genCache
+ writeFile WriteFile
+ rnd *rand.Rand
+ commentPrefix string
+}
+
+// setCommentPrefix sets the prefix used for comments, as used by the template
+func (g *generator) setCommentPrefix(commentPrefix string) string {
+ g.commentPrefix = commentPrefix
+ return ""
}
// WriteFile is a function that Generate() may call to emit a new file from a
// template.
// relPath is the relative path from the currently executing template.
// content is the file content to write.
-type WriteFile func(relPath, content string) error
+// comment is the prefix used for line comments
+type WriteFile func(relPath, content, comment string) error
-// generate executes the template tmpl, writing the output to w.
+// generate executes the template tmpl, calling writeFile with the output.
// See https://golang.org/pkg/text/template/ for documentation on the template
// syntax.
-func generate(tmplPath string, cache *genCache, w io.Writer, writeFile WriteFile) error {
+func generate(tmplPath, outPath string, cache *genCache, writeFile WriteFile) error {
g := generator{
- cache: cache,
- writeFile: writeFile,
- rnd: rand.New(rand.NewSource(4561123)),
+ cache: cache,
+ writeFile: writeFile,
+ rnd: rand.New(rand.NewSource(4561123)),
+ commentPrefix: "//",
}
funcs := map[string]any{
+ "SetCommentPrefix": g.setCommentPrefix,
"SplitDisplayName": gen.SplitDisplayName,
"Scramble": g.scramble,
"IsEnumEntry": is(sem.EnumEntry{}),
@@ -316,13 +322,19 @@
"IsFirstIn": isFirstIn,
"IsLastIn": isLastIn,
"LoadIntrinsics": func(path string) *intrinsicCache { return g.cache.intrinsics(path) },
- "WriteFile": func(relPath, content string) (string, error) { return "", g.writeFile(relPath, content) },
+ "WriteFile": func(relPath, content string) (string, error) {
+ return "", g.writeFile(relPath, content, g.commentPrefix)
+ },
}
t, err := template.FromFile(tmplPath)
if err != nil {
return err
}
- return t.Run(w, nil, funcs)
+ w := &strings.Builder{}
+ if err := t.Run(w, nil, funcs); err != nil {
+ return err
+ }
+ return writeFile(outPath, w.String(), g.commentPrefix)
}
// scramble randomly modifies the input string so that it is no longer equal to
diff --git a/tools/src/template/template.go b/tools/src/template/template.go
index 5af3ef6..313de30 100644
--- a/tools/src/template/template.go
+++ b/tools/src/template/template.go
@@ -25,7 +25,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// package template wraps the golang "text/template" package to provide an
+// Package template wraps the golang "text/template" package to provide an
// enhanced template generator.
package template
@@ -39,8 +39,10 @@
"strings"
"text/template"
+ "dawn.googlesource.com/dawn/tools/src/container"
"dawn.googlesource.com/dawn/tools/src/fileutils"
"dawn.googlesource.com/dawn/tools/src/text"
+ "dawn.googlesource.com/dawn/tools/src/transform"
)
// The template function binding table
@@ -79,30 +81,33 @@
// Add a bunch of generic useful functions
g.funcs = Functions{
+ "Append": listAppend,
+ "Concat": listConcat,
"Contains": strings.Contains,
"Eval": g.eval,
"Globals": func() Map { return globals },
"HasPrefix": strings.HasPrefix,
"HasSuffix": strings.HasSuffix,
"Import": g.importTmpl,
+ "Index": index,
"Is": is,
"Iterate": iterate,
+ "Join": strings.Join,
"List": list,
"Map": newMap,
"PascalCase": text.PascalCase,
- "ToUpper": strings.ToUpper,
- "ToLower": strings.ToLower,
"Repeat": strings.Repeat,
+ "Replace": replace,
+ "SortUnique": listSortUnique,
"Split": strings.Split,
- "Join": strings.Join,
+ "Sum": sum,
"Title": strings.Title,
+ "ToLower": strings.ToLower,
+ "ToUpper": strings.ToUpper,
"TrimLeft": strings.TrimLeft,
"TrimPrefix": strings.TrimPrefix,
"TrimRight": strings.TrimRight,
"TrimSuffix": strings.TrimSuffix,
- "Replace": replace,
- "Index": index,
- "Sum": sum,
"Error": func(err string, args ...any) string { panic(fmt.Errorf(err, args...)) },
}
@@ -235,8 +240,34 @@
return out
}
+// listAppend returns the slice list with items appended
+func listAppend(list any, items ...any) any {
+ itemValues := transform.SliceNoErr(items, reflect.ValueOf)
+ return reflect.Append(reflect.ValueOf(list), itemValues...).Interface()
+}
+
+// listConcat returns a slice formed from concatenating all the elements of all
+// the slice arguments
+func listConcat(firstList any, otherLists ...any) any {
+ out := reflect.ValueOf(firstList)
+ for _, list := range otherLists {
+ out = reflect.AppendSlice(out, reflect.ValueOf(list))
+ }
+ return out.Interface()
+}
+
+// listSortUnique returns items sorted by the string-formatted value of each element, with
+// items with the same strings deduplicated.
+func listSortUnique(items []any) []any {
+ m := make(container.Map[string, any], len(items))
+ for _, item := range items {
+ m.Add(fmt.Sprint(item), item)
+ }
+ return m.Values()
+}
+
// list returns a new slice of elements from the argument list
-// Useful for: {{- range Slice "a" "b" "c" -}}{{.}}{{end}}
+// Useful for: {{- range List "a" "b" "c" -}}{{.}}{{end}}
func list(elements ...any) []any { return elements }
func index(obj any, indices ...any) (any, error) {