Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debugging traces #345

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Checker/checker-linux.fsproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -25,4 +25,8 @@
</ProjectReference>
</ItemGroup>

<PropertyGroup>
<RunWorkingDirectory>$(MSBuildProjectDirectory)/..</RunWorkingDirectory>
</PropertyGroup>

</Project>
6 changes: 3 additions & 3 deletions Checker/main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ let canBeCompiled content =
printfn "compilation failed: %s" info
false

let doMinify content =
let arr = ShaderMinifier.minify [|"input", content|] |> fst |> Array.map (fun s -> s.code)
let doMinify file content =
let arr = ShaderMinifier.minify [|file, content|] |> fst |> Array.map (fun s -> s.code)
Printer.print arr.[0]

let testMinifyAndCompile (file: string) =
Expand All @@ -54,7 +54,7 @@ let testMinifyAndCompile (file: string) =
printfn "Invalid input file '%s'" file
false
else
let minified = doMinify content + "\n"
let minified = doMinify file content + "\n"
if not (canBeCompiled minified) then
printfn "Minification broke the file '%s'" file
printfn "%s" minified
Expand Down
11 changes: 9 additions & 2 deletions src/analyzer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@ module private VariableInlining =
let ident, isConst = def.Value
if not ident.DoNotInline && not ident.ToBeInlined && not ident.VarDecl.Value.isEverWrittenAfterDecl then
match localReferences.TryGetValue(def.Key), allReferences.TryGetValue(def.Key) with
| (_, 1), (_, 1) when isConst -> ident.ToBeInlined <- true
| (_, 0), (_, 0) -> ident.ToBeInlined <- true
| (_, 1), (_, 1) when isConst ->
debug $"inlining variable '{Printer.debugIdent ident}' because it's safe to inline and used only once"
ident.ToBeInlined <- true
| (_, 0), (_, 0) ->
debug $"inlining variable '{Printer.debugIdent ident}' because it's safe to inline and unused"
ident.ToBeInlined <- true
| _ -> ()

let isTrivialExpr = function
Expand Down Expand Up @@ -114,11 +118,13 @@ module private VariableInlining =
// Top-level values are special, in particular in HLSL. Keep them for now.
if not isTopLevel then
// Never-written locals without init should be unused: inline (remove) them.
debug $"inlining (removing) unassigned local '{Printer.debugDecl def}'"
def.name.ToBeInlined <- true
| Some init ->
if canBeInlined init then
// Never-written locals and globals are inlined when their value is "simple enough".
// This can increase non-compressed size but decreases compressed size.
debug $"inlining variable '{Printer.debugDecl def}' because it's never written and has a 'simple' definition"
def.name.ToBeInlined <- true
| _ -> ()

Expand Down Expand Up @@ -322,6 +328,7 @@ module private FunctionInlining =
if not funcInfo.funcType.fName.DoNotInline && verifyArgsUses funcInfo.func callSites then
// Mark both the call site (so that simplifyExpr can remove it) and the function (to remember to remove it).
// We cannot simply rely on unused functions removal, because it might be disabled through its own flag.
debug $"inlining function '{funcInfo.funcType}' into {callSites.Length} call sites"
for callSite in callSites do
callSite.ident.ToBeInlined <- true
funcInfo.funcType.fName.ToBeInlined <- true
Expand Down
1 change: 1 addition & 0 deletions src/api.fs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let private readFile file =
stream.ReadToEnd()

let minify (files: (string*string)[]) =
let names = files |> Array.map (fun (n,_) -> n) |> String.Concat in debug $"----- minifying {names}"
vprintf "Input file size is: %d\n" (files |> Array.sumBy (fun (_, s) -> s.Length))
let shaders = files |> Array.map (fun (f, c) -> Parse.runParser f c)
vprintf "File parsed. "; printSize shaders
Expand Down
8 changes: 8 additions & 0 deletions src/options.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open System.IO
open Argu
open System

let version = "1.3.6" // Shader Minifier version
let debugMode = false
Expand All @@ -23,6 +24,7 @@ type FieldSet =
type CliArguments =
| [<CustomCommandLine("-o")>] OutputName of string
| [<CustomCommandLine("-v")>] Verbose
| [<CustomCommandLine("--debug")>] Debug
| [<CustomCommandLine("--hlsl")>] Hlsl
| [<CustomCommandLine("--format")>] FormatArg of OutputFormat
| [<CustomCommandLine("--field-names")>] FieldNames of FieldSet
Expand All @@ -45,6 +47,7 @@ type CliArguments =
match s with
| OutputName _ -> "Set the output filename (default is shader_code.h)"
| Verbose -> "Verbose, display additional information"
| Debug -> "Debug, display more additional information"
| Hlsl -> "Use HLSL (default is GLSL)"
| FormatArg _ -> "Choose to format the output (use 'text' if you want just the shader)"
| FieldNames _ -> "Choose the field names for vectors: 'rgba', 'xyzw', or 'stpq'"
Expand All @@ -66,6 +69,7 @@ type Options() =
member val outputName = "shader_code.h" with get, set
member val outputFormat = CVariables with get, set
member val verbose = false with get, set
member val debug = false with get, set
member val smoothstepTrick = false with get, set
member val canonicalFieldNames = "xyzw" with get, set
member val preserveExternals = false with get, set
Expand All @@ -88,6 +92,9 @@ module Globals =
// like printfn when verbose option is set
let vprintf fmt = fprintf (if options.verbose then stdout else TextWriter.Null) fmt

let forceDebug = Environment.GetEnvironmentVariable("MINIFIER_DEBUG", EnvironmentVariableTarget.Process ||| EnvironmentVariableTarget.User) <> null
let debug str = fprintfn (if options.debug || forceDebug then stdout else IO.TextWriter.Null) "%s" str

open Globals

let helpTextMessage = sprintf "Shader Minifier %s - https://github.com/laurentlb/Shader_Minifier" version
Expand All @@ -111,6 +118,7 @@ let private initPrivate argv needFiles =
options.outputName <- args.GetResult(OutputName, defaultValue = "shader_code.h")
options.outputFormat <- args.GetResult(FormatArg, defaultValue = CVariables)
options.verbose <- args.Contains(Verbose)
options.debug <- args.Contains(Debug)
options.smoothstepTrick <- args.Contains(Smoothstep)
options.canonicalFieldNames <- (sprintf "%A" (args.GetResult(FieldNames, defaultValue = XYZW))).ToLower()
options.preserveExternals <- args.Contains(PreserveExternals) || args.Contains(PreserveAllGlobals)
Expand Down
13 changes: 13 additions & 0 deletions src/printer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,16 @@ let print tl = printIndented tl |> stripIndentation
let writeSymbols shader = (new PrinterImpl()).WriteSymbols shader
let exprToS x = (new PrinterImpl()).ExprToS 0 x |> stripIndentation
let typeToS ty = (new PrinterImpl()).TypeToS ty |> stripIndentation

let debugDecl (t: DeclElt) =
let size = if t.size = None then "" else $"[{t.size}]"
let init = match t.init with
| Some e -> $" = {exprToS e}"
| None -> ""
let sem = if t.semantics.IsEmpty then "" else $": {t.semantics}" in
$"{t.name.OldName}{size}{init}{sem}"

let debugIdent (ident: Ident) =
match ident.Declaration with
| Declaration.Variable rv -> debugDecl rv.decl
| _ -> ident.OldName.ToString()
12 changes: 9 additions & 3 deletions src/rewriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ module private RewriterImpl =

// Squeeze top-level declarations, e.g. uniforms
let rec squeezeTLDeclarations = function
| []-> []
| [] -> []
| TLDecl(ty1, li1) :: TLDecl(ty2, li2) :: l when ty1 = ty2 ->
squeezeTLDeclarations (TLDecl(ty1, li1 @ li2) :: l)
| e::l -> e :: squeezeTLDeclarations l
Expand Down Expand Up @@ -549,7 +549,9 @@ module private RewriterImpl =
|> List.map (fun c -> c.prototype)
|> List.contains funcInfo.funcType.prototype) // when in doubt wrt overload resolution, keep the function.
canBeRenamed && not isCalled && not funcInfo.funcType.isExternal
let unused = set [for funcInfo in funcInfos do if isUnused funcInfo then yield funcInfo.func]
let unused = [for funcInfo in funcInfos do if isUnused funcInfo then yield funcInfo]
if not unused.IsEmpty then debug($"removing unused functions: " + String.Join(", ", unused |> List.map (fun fi -> fi.funcType)))
let unused = unused |> List.map (fun fi -> fi.func) |> set
let mutable edited = false
let code = code |> List.filter (function
| Function _ as t -> if Set.contains t unused then edited <- true; false else true
Expand Down Expand Up @@ -615,6 +617,7 @@ module private ArgumentInlining =
let argExprs = callSites |> List.map (fun c -> c.argExprs |> List.item argIndex) |> List.distinct
match argExprs with
| [argExpr] when isInlinableExpr argExpr -> // The argExpr must always be the same at all call sites.
debug $"inlining expression '{Printer.exprToS argExpr}' into argument '{Printer.debugDecl varDecl.decl}' of '{funcInfo.funcType}'"
argInlinings <- {func=funcInfo.func; argIndex=argIndex; varDecl=varDecl; argExpr=argExpr} :: argInlinings
| _ -> ()
| _ -> ()
Expand Down Expand Up @@ -677,7 +680,10 @@ let rec private iterateSimplifyAndInline li =

let li = if options.noInlining then li else ArgumentInlining.apply didInline li

if didInline.Value then iterateSimplifyAndInline li else li
if didInline.Value
then debug $"inlining happened: running analysis again..."
iterateSimplifyAndInline li
else li

let simplify li =
li
Expand Down