From 9e5390971ca0c79fa8038c354fd81e44ab07929d Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Mon, 15 Jul 2024 15:58:52 -0700 Subject: [PATCH] Treat as external the global fields of an interface block (#431), fixes #430 Interface blocks without an instance name introduce external global variables. --- src/ast.fs | 6 ++++-- src/renamer.fs | 17 +++++++++-------- tests/commands.txt | 1 + tests/unit/interface-block-renaming.expected | 18 ++++++++++++++++++ tests/unit/interface-block-renaming1.frag | 4 ++++ tests/unit/interface-block-renaming2.frag | 4 ++++ 6 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 tests/unit/interface-block-renaming.expected create mode 100644 tests/unit/interface-block-renaming1.frag create mode 100644 tests/unit/interface-block-renaming2.frag diff --git a/src/ast.fs b/src/ast.fs index 34de58d7..32fcf28e 100644 --- a/src/ast.fs +++ b/src/ast.fs @@ -79,8 +79,10 @@ and Expr = and TypeSpec = | TypeName of string - // e.g. struct foo { float x; float y; } + // struct or interface block, e.g. struct foo { float x; float y; } | TypeBlock of string(*type*) * Ident option(*name*) * Decl list + // An interface block followed by an instance name (in a TLDecl), like structs, declares an instance. + // An interface block without an instance name (in a TypeDecl), unlike structs, introduces a set of external global variables. and Type = { name: TypeSpec // e.g. int @@ -167,7 +169,7 @@ and TopLevel = | TLDirective of string list | Function of FunctionType * Stmt | TLDecl of Decl - | TypeDecl of TypeSpec // structs + | TypeDecl of TypeSpec // structs or interface blocks | Precision of Type let makeType name tyQ sizes = {Type.name=name; typeQ=tyQ; arraySizes=sizes} diff --git a/src/renamer.fs b/src/renamer.fs index 91ca8a11..c44eb40c 100644 --- a/src/renamer.fs +++ b/src/renamer.fs @@ -234,11 +234,12 @@ type private RenamerImpl(options: Options.Options) = | e -> e mapExpr (mapEnvExpr options mapper) expr |> ignore - let renDecl level env (ty:Type, vars) = + let renDecl level isFieldOfAnInterfaceBlockWithoutInstanceName env (ty:Type, vars) = let aux (env: Env) (decl: Ast.DeclElt) = Option.iter (renExpr env) decl.init Option.iter (renExpr env) decl.size - let isExternal = level = Level.TopLevel && (ty.IsExternal || options.hlsl) + let isExternal = (level = Level.TopLevel && (ty.IsExternal || options.hlsl)) || + isFieldOfAnInterfaceBlockWithoutInstanceName if (level = Level.TopLevel && options.preserveAllGlobals) || List.contains decl.name.Name options.noRenamingList then @@ -280,7 +281,7 @@ type private RenamerImpl(options: Options.Options) = function | Expr e -> renExpr env e; env | Decl d -> - renDecl Level.InFunc env d + renDecl Level.InFunc false env d | Block b -> renList env renStmt b |> ignore env @@ -291,7 +292,7 @@ type private RenamerImpl(options: Options.Options) = env | ForD(init, cond, inc, body) as stmt -> let newEnv = env.onEnterFunction env stmt - let newEnv = renDecl Level.InFunc newEnv init + let newEnv = renDecl Level.InFunc false newEnv init renStmt newEnv body |> ignore Option.iter (renExpr newEnv) cond Option.iter (renExpr newEnv) inc @@ -332,12 +333,12 @@ type private RenamerImpl(options: Options.Options) = let renTyBlock (env: Env) = function | TypeBlock("struct", _, _) -> env | TypeBlock(_, _, fields) -> - // treat the fields as if they were global variables - renList env (renDecl Level.TopLevel) fields + // interface block without an instance name: the fields are treated as external global variables + renList env (renDecl Level.TopLevel true) fields | _ -> env let rec renTopLevelName env = function - | TLDecl d -> renDecl Level.TopLevel env d + | TLDecl d -> renDecl Level.TopLevel false env d | TypeDecl tyDecl -> renTyBlock env tyDecl | Function(fct, _) -> renFctName env fct | _ -> env @@ -345,7 +346,7 @@ type private RenamerImpl(options: Options.Options) = let rec renTopLevelBody (env: Env) = function | Function(fct, body) -> let env = env.onEnterFunction env body - let env = renList env (renDecl Level.InFunc) fct.args + let env = renList env (renDecl Level.InFunc false) fct.args renStmt env body |> ignore | _ -> () diff --git a/tests/commands.txt b/tests/commands.txt index eb400f3a..0e7644ad 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -63,6 +63,7 @@ # Multifile tests --no-remove-unused --move-declarations --format c-array -o tests/unit/inout.expected tests/unit/inout.frag tests/unit/inout2.frag +--no-remove-unused --format c-array -o tests/unit/interface-block-renaming.expected tests/unit/interface-block-renaming1.frag tests/unit/interface-block-renaming2.frag # kkp symbols tests diff --git a/tests/unit/interface-block-renaming.expected b/tests/unit/interface-block-renaming.expected new file mode 100644 index 00000000..c183df5e --- /dev/null +++ b/tests/unit/interface-block-renaming.expected @@ -0,0 +1,18 @@ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) +#ifndef SHADER_MINIFIER_IMPL +#ifndef SHADER_MINIFIER_HEADER +# define SHADER_MINIFIER_HEADER +# define VAR_field "U" +#endif + +#else // if SHADER_MINIFIER_IMPL + +// tests/unit/interface-block-renaming1.frag + "#version 460\n" + "uniform Uniform1{vec4 U;};", + +// tests/unit/interface-block-renaming2.frag + "#version 460\n" + "uniform Uniform1{vec4 U;};", + +#endif diff --git a/tests/unit/interface-block-renaming1.frag b/tests/unit/interface-block-renaming1.frag new file mode 100644 index 00000000..d114a60b --- /dev/null +++ b/tests/unit/interface-block-renaming1.frag @@ -0,0 +1,4 @@ +#version 460 +// https://github.com/laurentlb/shader-minifier/issues/430 +uniform Uniform1 { vec4 field; }; +//uniform Uniform2 { vec4 field; } instance; // TODO diff --git a/tests/unit/interface-block-renaming2.frag b/tests/unit/interface-block-renaming2.frag new file mode 100644 index 00000000..d114a60b --- /dev/null +++ b/tests/unit/interface-block-renaming2.frag @@ -0,0 +1,4 @@ +#version 460 +// https://github.com/laurentlb/shader-minifier/issues/430 +uniform Uniform1 { vec4 field; }; +//uniform Uniform2 { vec4 field; } instance; // TODO