@thi.ng/shader-ast-optimize 0.3.54 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2024-03-01T15:22:50Z
3
+ - **Last updated**: 2024-03-07T20:40:47Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,21 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/shader-ast-optimize@0.4.0) (2024-03-07)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add defOptimized(), rename source file ([b1dc3c0](https://github.com/thi-ng/umbrella/commit/b1dc3c0))
17
+ - add defOptimized() wrapper fn
18
+ - fix spelling in file name
19
+ - update example in docs
20
+ - expand constantFolding() features, bug fixes ([1350bf7](https://github.com/thi-ng/umbrella/commit/1350bf7))
21
+ - add support scalar comparisons
22
+ - div-by-zero checks
23
+ - fix non-scalar mul & sub handling
24
+ - add support for exp2(), pow()
25
+ - add tests
26
+
12
27
  ### [0.3.27](https://github.com/thi-ng/umbrella/tree/@thi.ng/shader-ast-optimize@0.3.27) (2023-11-09)
13
28
 
14
29
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -15,6 +15,7 @@
15
15
  > GitHub](https://github.com/sponsors/postspectacular). Thank you! ❤️
16
16
 
17
17
  - [About](#about)
18
+ - [defOptimized()](#defoptimized)
18
19
  - [Tree optimizations](#tree-optimizations)
19
20
  - [Constant folding](#constant-folding)
20
21
  - [Status](#status)
@@ -29,60 +30,79 @@
29
30
 
30
31
  Shader AST code optimization passes/strategies. This is a support package for [@thi.ng/shader-ast](https://github.com/thi-ng/umbrella/tree/develop/packages/shader-ast).
31
32
 
33
+ ### defOptimized()
34
+
35
+ The function
36
+ [`defOptimize()`](https://docs.thi.ng/umbrella/shader-ast-optimize/functions/defOptimized.html)
37
+ can be used as direct replacement for [thi.ng/shader-ast]()'s
38
+ [`defMain()`](https://docs.thi.ng/umbrella/shader-ast/functions/defMain.html) to
39
+ define automatically optimized shader `main()` functions.
40
+
32
41
  ### Tree optimizations
33
42
 
34
- Currently, only the following operations are supported / considered:
43
+ Currently, only the following operations are supported/considered:
35
44
 
36
45
  #### Constant folding
37
46
 
38
- - scalar math operators
39
- - scalar math built-in functions
47
+ - scalar math operators (incl. some vector versions)
48
+ - scalar math built-in functions (incl. some vector versions)
49
+ - scalar comparisons
40
50
  - single component vector swizzling
41
51
  - literal hoisting
42
52
 
43
- ```ts
44
- import { $x, $y, add, defn, float, mul, neg, ret } from "@thi.ng/shader-ast";
53
+ (See tests for some more examples, non-exhaustive...)
54
+
55
+ **Note:** The static optimizer throws an error if it detects a division-by-zero...
56
+
57
+ ```ts tangle:export/readme1.ts
58
+ import {
59
+ add, defn, float, mul, neg, ret, scope, vec2, $x, $y
60
+ } from "@thi.ng/shader-ast";
45
61
  import { targetGLSL } from "@thi.ng/shader-ast-glsl";
46
62
  import { constantFolding } from "@thi.ng/shader-ast-optimize";
47
63
 
64
+ // function def
48
65
  const foo = defn("float", "foo", ["float"], (x) => [
49
- ret(mul(x, add(neg(float(10)), float(42))))
66
+ ret(mul(x, add(neg(float(10)), 42)))
50
67
  ]);
51
68
 
52
69
  const bar = vec2(100, 200);
53
70
 
71
+ // program def
54
72
  const prog = scope([
55
73
  foo,
56
74
  foo(add(float(1), float(2))),
57
75
  foo(add($x(bar), $y(bar)))
58
76
  ], true);
59
77
 
78
+ // GLSL codegen
60
79
  const glsl = targetGLSL();
61
80
 
62
81
  // unoptimized AST as GLSL (see section above)
63
- glsl(prog);
64
-
65
- // float foo(in float _sym0) {
66
- // return (_sym0 * (-10.0 + 42.0));
67
- // };
82
+ console.log(glsl(prog));
83
+ // #version 300 es
84
+ // float foo(in float _s0) {
85
+ // return (_s0 * ((-10.0) + 42.0));
86
+ // }
68
87
  // foo((1.0 + 2.0));
69
88
  // foo((vec2(100.0, 200.0).x + vec2(100.0, 200.0).y));
70
89
 
71
- // same tree after constant folding optimizations
72
- glsl(constantFolding(prog))
73
-
74
- // float foo(in float _sym0) {
75
- // return (_sym0 * 32.0);
76
- // };
90
+ // with constant folding
91
+ console.log(glsl(constantFolding(prog)))
92
+ // #version 300 es
93
+ // float foo(in float _s0) {
94
+ // return (_s0 * 32.0);
95
+ // }
77
96
  // foo(3.0);
78
97
  // foo(300.0);
79
98
 
80
99
  const expr = mul(float(4), $x(vec2(2)))
81
100
 
82
- glsl(expr)
101
+ console.log(glsl(expr))
83
102
  // (4.0 * vec2(2.0).x)
84
103
 
85
- glsl(constantFolding(expr))
104
+ // optimize single expression
105
+ console.log(glsl(constantFolding(expr)))
86
106
  // 8.0
87
107
  ```
88
108
 
@@ -112,12 +132,13 @@ For Node.js REPL:
112
132
  const shaderAstOptimize = await import("@thi.ng/shader-ast-optimize");
113
133
  ```
114
134
 
115
- Package sizes (brotli'd, pre-treeshake): ESM: 1014 bytes
135
+ Package sizes (brotli'd, pre-treeshake): ESM: 1.24 KB
116
136
 
117
137
  ## Dependencies
118
138
 
119
139
  - [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
120
140
  - [@thi.ng/defmulti](https://github.com/thi-ng/umbrella/tree/develop/packages/defmulti)
141
+ - [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
121
142
  - [@thi.ng/logger](https://github.com/thi-ng/umbrella/tree/develop/packages/logger)
122
143
  - [@thi.ng/math](https://github.com/thi-ng/umbrella/tree/develop/packages/math)
123
144
  - [@thi.ng/shader-ast](https://github.com/thi-ng/umbrella/tree/develop/packages/shader-ast)
@@ -1,6 +1,23 @@
1
- import type { Term } from "@thi.ng/shader-ast";
1
+ import { type FnCall, type Term } from "@thi.ng/shader-ast";
2
2
  /** @internal */
3
3
  export declare const foldNode: import("@thi.ng/defmulti/api").MultiFn1<Term<any>, boolean | undefined>;
4
+ /**
5
+ * Similar to {@link foldNode}, but specialized for function calls of builtin's
6
+ * (aka `call_i` AST nodes).
7
+ *
8
+ * @remarks
9
+ * Currently, implementations are only dealing with these builtins:
10
+ *
11
+ * - exp2
12
+ * - pow
13
+ *
14
+ * This function delegates based on the function name of the builtin and is
15
+ * extensible, i.e. custom optimizations can be added by calling
16
+ * `foldBuiltin.add("functionname", (node) => ...)`.
17
+ *
18
+ * @internal
19
+ */
20
+ export declare const foldBuiltin: import("@thi.ng/defmulti/api").MultiFn1<FnCall<any>, boolean | undefined>;
4
21
  /**
5
22
  * Traverses given AST (potentially several times) and applies constant folding
6
23
  * optimizations where possible. Returns possibly updated tree (mutates
@@ -15,18 +32,17 @@ export declare const foldNode: import("@thi.ng/defmulti/api").MultiFn1<Term<any>
15
32
  * - literal hoisting
16
33
  *
17
34
  * @example
18
- * ```ts
35
+ * ```ts tangle:../export/constant-folding.ts
19
36
  * import {
20
- * add, defn, float, mul, neg, ret, scope, vec2
21
- * $x, $y
37
+ * add, defn, float, mul, neg, ret, scope, vec2, $x, $y
22
38
  * } from "@thi.ng/shader-ast";
23
39
  * import { targetGLSL } from "@thi.ng/shader-ast-glsl";
24
40
  * import { constantFolding } from "@thi.ng/shader-ast-optimize";
25
41
  *
26
42
  * // function def
27
43
  * const foo = defn("float", "foo", ["float"], (x) => [
28
- * ret(mul(x, add(neg(float(10)), float(42))))]
29
- * )
44
+ * ret(mul(x, add(neg(float(10)), 42)))
45
+ * ]);
30
46
  *
31
47
  * const bar = vec2(100, 200);
32
48
  *
@@ -37,36 +53,38 @@ export declare const foldNode: import("@thi.ng/defmulti/api").MultiFn1<Term<any>
37
53
  * foo(add($x(bar), $y(bar)))
38
54
  * ], true);
39
55
  *
40
- * // serialized (GLSL)
56
+ * // GLSL codegen
41
57
  * const glsl = targetGLSL();
42
- * glsl(prog);
43
58
  *
44
- * // float foo(in float _sym0) {
45
- * // return (_sym0 * (-10.0 + 42.0));
46
- * // };
59
+ * // unoptimized AST as GLSL (see section above)
60
+ * console.log(glsl(prog));
61
+ * // #version 300 es
62
+ * // float foo(in float _s0) {
63
+ * // return (_s0 * ((-10.0) + 42.0));
64
+ * // }
47
65
  * // foo((1.0 + 2.0));
48
66
  * // foo((vec2(100.0, 200.0).x + vec2(100.0, 200.0).y));
49
67
  *
50
68
  * // with constant folding
51
- * glsl(constantFolding(prog))
52
- *
53
- * // float foo(in float _sym0) {
54
- * // return (_sym0 * 32.0);
55
- * // };
69
+ * console.log(glsl(constantFolding(prog)))
70
+ * // #version 300 es
71
+ * // float foo(in float _s0) {
72
+ * // return (_s0 * 32.0);
73
+ * // }
56
74
  * // foo(3.0);
57
75
  * // foo(300.0);
58
76
  *
59
77
  * const expr = mul(float(4), $x(vec2(2)))
60
78
  *
61
- * glsl(expr)
79
+ * console.log(glsl(expr))
62
80
  * // (4.0 * vec2(2.0).x)
63
81
  *
64
82
  * // optimize single expression
65
- * glsl(constantFolding(expr))
83
+ * console.log(glsl(constantFolding(expr)))
66
84
  * // 8.0
67
85
  * ```
68
86
  *
69
87
  * @param tree -
70
88
  */
71
89
  export declare const constantFolding: (tree: Term<any>) => Term<any>;
72
- //# sourceMappingURL=contant-folding.d.ts.map
90
+ //# sourceMappingURL=constant-folding.d.ts.map
@@ -1,17 +1,32 @@
1
1
  import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
2
+ import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
2
3
  import { LogLevel } from "@thi.ng/logger/api";
3
4
  import { deg, rad } from "@thi.ng/math/angle";
4
5
  import { clamp } from "@thi.ng/math/interval";
5
6
  import { mix } from "@thi.ng/math/mix";
6
7
  import { fract, mod } from "@thi.ng/math/prec";
8
+ import {
9
+ matchingPrimFor,
10
+ neg
11
+ } from "@thi.ng/shader-ast";
7
12
  import {
8
13
  isFloat,
9
14
  isInt,
15
+ isLitNumOrVecConst,
10
16
  isLitNumericConst,
11
17
  isLitVecConst,
12
18
  isUint
13
19
  } from "@thi.ng/shader-ast/ast/checks";
14
- import { FLOAT0, float, int, lit, uint } from "@thi.ng/shader-ast/ast/lit";
20
+ import {
21
+ FLOAT0,
22
+ FLOAT1,
23
+ FLOAT2,
24
+ bool,
25
+ float,
26
+ int,
27
+ lit,
28
+ uint
29
+ } from "@thi.ng/shader-ast/ast/lit";
15
30
  import { allChildren, walk } from "@thi.ng/shader-ast/ast/scope";
16
31
  import { LOGGER } from "@thi.ng/shader-ast/logger";
17
32
  const replaceNode = (node, next) => {
@@ -31,7 +46,10 @@ const replaceNumericNode = (node, res) => {
31
46
  node.type === "uint" && (res >>>= 0);
32
47
  return replaceNode(node, lit(node.type, res));
33
48
  };
34
- const maybeFoldMath = (op, l, r) => op === "+" ? l + r : op === "-" ? l - r : op === "*" ? l * r : op === "/" ? l / r : void 0;
49
+ const replaceBooleanNode = (node, res) => replaceNode(node, bool(res));
50
+ const replaceWithConst = (node, ref, n) => replaceNode(node, matchingPrimFor(ref, n));
51
+ const maybeFoldMath = (op, l, r) => op === "+" ? l + r : op === "-" ? l - r : op === "*" ? l * r : op === "/" ? r != 0 ? l / r : illegalArgs(`division by zero: ${l}/${r}`) : void 0;
52
+ const maybeFoldCompare = (op, l, r) => op === "==" ? l === r : op === "!=" ? l !== r : op === "<" ? l < r : op === "<=" ? l <= r : op === ">=" ? l >= r : op === ">" ? l > r : void 0;
35
53
  const COMPS = { x: 0, y: 1, z: 2, w: 3 };
36
54
  const BUILTINS = {
37
55
  abs: ([a]) => Math.abs(a),
@@ -79,24 +97,38 @@ const foldNode = defmulti(
79
97
  const isNumL = isLitNumericConst(l);
80
98
  const isNumR = isLitNumericConst(r);
81
99
  if (isNumL && isNumR) {
82
- let res = maybeFoldMath(op, l.val, r.val);
83
- if (res !== void 0)
84
- return replaceNumericNode(node, res);
100
+ const num = maybeFoldMath(op, l.val, r.val);
101
+ if (num !== void 0)
102
+ return replaceNumericNode(node, num);
103
+ const bool2 = maybeFoldCompare(op, l.val, r.val);
104
+ if (bool2 !== void 0)
105
+ return replaceBooleanNode(node, bool2);
85
106
  } else if (op === "*") {
86
- if (isNumL && l.val === 0 || isNumR && r.val === 0)
87
- return replaceNode(node, FLOAT0);
107
+ if (isNumL && l.val === 0)
108
+ return replaceWithConst(node, r, FLOAT0);
109
+ if (isNumR && r.val === 0)
110
+ return replaceWithConst(node, l, FLOAT0);
88
111
  if (isNumL && l.val === 1)
89
112
  return replaceNode(node, r);
90
113
  if (isNumR && r.val === 1)
91
114
  return replaceNode(node, l);
92
115
  } else if (op === "/") {
116
+ if (isNumL && l.val === 0)
117
+ return replaceWithConst(node, r, FLOAT0);
118
+ if (isNumR && r.val === 0)
119
+ illegalArgs("division by zero");
93
120
  if (isNumR && r.val === 1)
94
121
  return replaceNode(node, l);
95
- } else if (op === "+" || op === "-") {
122
+ } else if (op === "+") {
96
123
  if (isNumL && l.val === 0)
97
124
  return replaceNode(node, r);
98
125
  if (isNumR && r.val === 0)
99
126
  return replaceNode(node, l);
127
+ } else if (op === "-") {
128
+ if (isNumL && l.val === 0)
129
+ return replaceNode(node, neg(r));
130
+ if (isNumR && r.val === 0)
131
+ return replaceNode(node, l);
100
132
  }
101
133
  },
102
134
  call_i: (node) => {
@@ -109,6 +141,8 @@ const foldNode = defmulti(
109
141
  op($node.args.map((x) => x.val))
110
142
  );
111
143
  }
144
+ } else {
145
+ return foldBuiltin($node);
112
146
  }
113
147
  },
114
148
  lit: (node) => {
@@ -139,6 +173,31 @@ const foldNode = defmulti(
139
173
  }
140
174
  }
141
175
  );
176
+ const foldBuiltin = defmulti(
177
+ (x) => x.id,
178
+ {},
179
+ {
180
+ [DEFAULT]: () => false,
181
+ exp2: (node) => {
182
+ const a = node.args[0];
183
+ if (isLitNumOrVecConst(a, 0)) {
184
+ return replaceWithConst(node, a, FLOAT1);
185
+ }
186
+ if (isLitNumOrVecConst(a, 1)) {
187
+ return replaceWithConst(node, a, FLOAT2);
188
+ }
189
+ },
190
+ pow: (node) => {
191
+ const [a, b] = node.args;
192
+ if (isLitNumOrVecConst(b, 0)) {
193
+ return replaceWithConst(node, a, FLOAT1);
194
+ }
195
+ if (isLitNumOrVecConst(b, 1)) {
196
+ return replaceNode(node, a);
197
+ }
198
+ }
199
+ }
200
+ );
142
201
  const constantFolding = (tree) => {
143
202
  let exec = true;
144
203
  while (exec) {
@@ -157,5 +216,6 @@ const constantFolding = (tree) => {
157
216
  };
158
217
  export {
159
218
  constantFolding,
219
+ foldBuiltin,
160
220
  foldNode
161
221
  };
@@ -0,0 +1,9 @@
1
+ import type { FnBody0 } from "@thi.ng/shader-ast";
2
+ /**
3
+ * Same as [defMain()](), but applies optimizations (e.g.
4
+ * {@link constantFolding}) to the given function body.
5
+ *
6
+ * @param fn
7
+ */
8
+ export declare const defOptimized: (fn: FnBody0) => import("@thi.ng/shader-ast").TaggedFn0<"void">;
9
+ //# sourceMappingURL=defoptimized.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { defMain } from "@thi.ng/shader-ast/ast/function";
2
+ import { constantFolding } from "./constant-folding.js";
3
+ const defOptimized = (fn) => constantFolding(defMain(fn));
4
+ export {
5
+ defOptimized
6
+ };
package/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export * from "./contant-folding.js";
1
+ export * from "./constant-folding.js";
2
+ export * from "./defoptimized.js";
2
3
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1 +1,2 @@
1
- export * from "./contant-folding.js";
1
+ export * from "./constant-folding.js";
2
+ export * from "./defoptimized.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/shader-ast-optimize",
3
- "version": "0.3.54",
3
+ "version": "0.4.0",
4
4
  "description": "Shader AST code optimization passes/strategies",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -32,14 +32,16 @@
32
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
33
33
  "doc:readme": "bun ../../tools/src/module-stats.ts && bun ../../tools/src/readme.ts",
34
34
  "pub": "yarn npm publish --access public",
35
- "test": "bun test"
35
+ "test": "bun test",
36
+ "tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
36
37
  },
37
38
  "dependencies": {
38
- "@thi.ng/api": "^8.9.27",
39
- "@thi.ng/defmulti": "^3.0.28",
40
- "@thi.ng/logger": "^3.0.4",
41
- "@thi.ng/math": "^5.10.4",
42
- "@thi.ng/shader-ast": "^0.13.16"
39
+ "@thi.ng/api": "^8.9.28",
40
+ "@thi.ng/defmulti": "^3.0.29",
41
+ "@thi.ng/errors": "^2.4.20",
42
+ "@thi.ng/logger": "^3.0.5",
43
+ "@thi.ng/math": "^5.10.5",
44
+ "@thi.ng/shader-ast": "^0.15.0"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@microsoft/api-extractor": "^7.40.1",
@@ -69,13 +71,16 @@
69
71
  ".": {
70
72
  "default": "./index.js"
71
73
  },
72
- "./contant-folding": {
73
- "default": "./contant-folding.js"
74
+ "./constant-folding": {
75
+ "default": "./constant-folding.js"
76
+ },
77
+ "./defoptimized": {
78
+ "default": "./defoptimized.js"
74
79
  }
75
80
  },
76
81
  "thi.ng": {
77
82
  "parent": "@thi.ng/shader-ast",
78
83
  "year": 2019
79
84
  },
80
- "gitHead": "df9e312af741d87e6b450afcfea6a6e381662b1e\n"
85
+ "gitHead": "a421058a65ba76608d94129ac29451bfedaf201c\n"
81
86
  }