Skip to content

Commit

Permalink
Unused functions are removed by default (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
eldritchconundrum authored Dec 30, 2022
1 parent 247b787 commit d3cfc0e
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 188 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ local.properties
## Visual Studio
#################

.vs/

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

Expand Down
2 changes: 2 additions & 0 deletions src/api.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ let minify (files: (string*string)[]) =
vprintf "File parsed. "; printSize shaders

for shader in shaders do
if not options.noRemoveUnused then
shader.code <- Rewriter.removeUnused shader.code
if shader.reorderFunctions then
shader.code <- Rewriter.reorder shader.code
shader.code <- Rewriter.simplify shader.code
Expand Down
4 changes: 4 additions & 0 deletions src/options.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type CliArguments =
| [<CustomCommandLine("--no-renaming-list")>] NoRenamingList of string
| [<CustomCommandLine("--no-sequence")>] NoSequence
| [<CustomCommandLine("--smoothstep")>] Smoothstep
| [<CustomCommandLine("--no-remove-unused")>] NoRemoveUnused
| [<MainCommand>] Filenames of filename:string list

interface IArgParserTemplate with
Expand All @@ -53,6 +54,7 @@ type CliArguments =
| NoRenamingList _ -> "Comma-separated list of functions to preserve"
| NoSequence -> "Do not use the comma operator trick"
| Smoothstep -> "Use IQ's smoothstep trick"
| NoRemoveUnused -> "Do not remove unused code"
| Filenames _ -> "List of files to minify"

type Options() =
Expand All @@ -69,6 +71,7 @@ type Options() =
member val noSequence = false with get, set
member val noRenaming = false with get, set
member val noRenamingList = ["main"] with get, set
member val noRemoveUnused = false with get, set
member val filenames = [||]: string[] with get, set

module Globals =
Expand Down Expand Up @@ -109,6 +112,7 @@ let private initPrivate argv needFiles =
options.aggroInlining <- args.Contains(AggroInlining) && not (args.Contains(NoInlining))
options.noSequence <- args.Contains(NoSequence)
options.noRenaming <- args.Contains(NoRenaming)
options.noRemoveUnused <- args.Contains(NoRemoveUnused)
options.noRenamingList <- noRenamingList
options.filenames <- filenames
true
Expand Down
50 changes: 35 additions & 15 deletions src/rewriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -289,25 +289,32 @@ let simplify li =
(* Reorder functions because of forward declarations *)


type CallGraphNode = {
func: TopLevel
funcType: FunctionType
name: string
callees: string list
}

let rec private findRemove callback = function
| (name, [], content) :: l ->
| node :: l when node.callees.IsEmpty ->
//printfn "=> %s" name
callback name content
callback node
l
| [] -> failwith "Cannot reorder functions (probably because of a recursion)."
| x :: l -> x :: findRemove callback l

// slow, but who cares?
let private graphReorder deps =
let private graphReorder nodes =
let mutable list = []
let mutable lastName = ""

let rec loop deps =
let deps = findRemove (fun (s: Ident) x -> lastName <- s.Name; list <- x :: list) deps
let deps = deps |> List.map (fun (n, d, c) -> n, List.filter ((<>) lastName) d, c)
if deps <> [] then loop deps
let rec loop nodes =
let nodes = findRemove (fun node -> lastName <- node.name; list <- node.func :: list) nodes
let nodes = nodes |> List.map (fun n -> { n with callees = List.filter ((<>) lastName) n.callees })
if nodes <> [] then loop nodes

if deps <> [] then loop deps
if nodes <> [] then loop nodes
list |> List.rev


Expand All @@ -324,14 +331,27 @@ let private computeDependencies block =

// This function assumes that functions are NOT overloaded
let private computeAllDependencies code =
let fct = code |> List.choose (function
| Function(fct, block) as f -> Some (fct.fName, block, f)
let functions = code |> List.choose (function
| Function(funcType, block) as f -> Some (funcType, funcType.fName.Name, block, f)
| _ -> None)
let deps = fct |> List.map (fun (name, block, f) ->
let dep = computeDependencies block
|> List.filter (fun name -> fct |> List.exists (fun (x,_,_) -> name = x.Name))
name, dep, f)
deps
let nodes = functions |> List.map (fun (funcType, name, block, f) ->
let callees = computeDependencies block
|> List.filter (fun name2 -> functions |> List.exists (fun (_,n,_,_) -> name2 = n))
{ CallGraphNode.func = f; funcType = funcType; name = name; callees = callees })
nodes


let removeUnused code =
let nodes = computeAllDependencies code
let isUnused node =
let canBeRenamed = not (options.noRenamingList |> List.contains node.name) // noRenamingList includes "main"
let isCalled = (nodes |> List.exists (fun n -> n.callees |> List.contains node.name))
let isExternal = options.hlsl && node.funcType.semantics <> []
canBeRenamed && not isCalled && not isExternal
let unused = set [for node in nodes do if isUnused node then yield node.func]
code |> List.filter (function
| Function _ as t -> not (unused |> Set.contains t)
| _ -> true)

// reorder functions if there were forward declarations
let reorder code =
Expand Down
48 changes: 24 additions & 24 deletions tests/commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,52 @@

# Unit tests

--no-renaming --format c-variables -o tests/unit/blocks.expected tests/unit/blocks.frag
--hlsl --no-inlining --no-renaming --format c-variables -o tests/unit/geometry.hlsl.expected tests/unit/geometry.hlsl
--no-renaming --no-inlining --format c-array -o tests/unit/operators.expected tests/unit/operators.frag
--no-remove-unused --no-renaming --format c-variables -o tests/unit/blocks.expected tests/unit/blocks.frag
--no-remove-unused --hlsl --no-inlining --no-renaming --format c-variables -o tests/unit/geometry.hlsl.expected tests/unit/geometry.hlsl
--no-remove-unused --no-renaming --no-inlining --format c-array -o tests/unit/operators.expected tests/unit/operators.frag
--no-renaming --no-inlining --format c-array -o tests/unit/minus-zero.expected tests/unit/minus-zero.frag
--no-renaming --format c-array --no-inlining -o tests/unit/float.frag.expected tests/unit/float.frag
--no-renaming --format indented --no-inlining -o tests/unit/nested_if.frag.expected tests/unit/nested_if.frag
--no-remove-unused --no-renaming --format c-array --no-inlining -o tests/unit/float.frag.expected tests/unit/float.frag
--no-remove-unused --no-renaming --format indented --no-inlining -o tests/unit/nested_if.frag.expected tests/unit/nested_if.frag
--format indented -o tests/unit/precision.frag.expected tests/unit/precision.frag
--format c-array --no-inlining --no-renaming -o tests/unit/verbatim.frag.expected tests/unit/verbatim.frag
--format indented --no-renaming -o tests/unit/forward_declaration.frag.expected tests/unit/forward_declaration.frag
--no-remove-unused --format c-array --no-inlining --no-renaming -o tests/unit/verbatim.frag.expected tests/unit/verbatim.frag
--no-remove-unused --format indented --no-renaming -o tests/unit/forward_declaration.frag.expected tests/unit/forward_declaration.frag

# Inlining unit tests

--no-renaming --format indented -o tests/unit/inline.expected tests/unit/inline.frag
--no-renaming --format indented --aggressive-inlining -o tests/unit/inline.aggro.expected tests/unit/inline.frag
--no-renaming --format indented --no-inlining -o tests/unit/inline.no.expected tests/unit/inline.frag
--no-renaming --format indented -o tests/unit/inline-aggro.expected tests/unit/inline-aggro.frag
--no-renaming --format indented --aggressive-inlining -o tests/unit/inline-aggro.aggro.expected tests/unit/inline-aggro.frag
--no-renaming --format indented -o tests/unit/inline-fn.expected tests/unit/inline-fn.frag
--no-renaming --format indented --aggressive-inlining -o tests/unit/inline-fn.aggro.expected tests/unit/inline-fn.frag
--no-remove-unused --no-renaming --format indented -o tests/unit/inline.expected tests/unit/inline.frag
--no-remove-unused --no-renaming --format indented --aggressive-inlining -o tests/unit/inline.aggro.expected tests/unit/inline.frag
--no-remove-unused --no-renaming --format indented --no-inlining -o tests/unit/inline.no.expected tests/unit/inline.frag
--no-remove-unused --no-renaming --format indented -o tests/unit/inline-aggro.expected tests/unit/inline-aggro.frag
--no-remove-unused --no-renaming --format indented --aggressive-inlining -o tests/unit/inline-aggro.aggro.expected tests/unit/inline-aggro.frag
--no-remove-unused --no-renaming --format indented -o tests/unit/inline-fn.expected tests/unit/inline-fn.frag
--no-remove-unused --no-renaming --format indented --aggressive-inlining -o tests/unit/inline-fn.aggro.expected tests/unit/inline-fn.frag

# Partial renaming tests

--no-renaming --format c-variables -o tests/unit/function_comma.expected tests/unit/function_comma.frag
--no-remove-unused --no-renaming --format c-variables -o tests/unit/function_comma.expected tests/unit/function_comma.frag
--preserve-externals --format c-variables -o tests/real/mandelbulb.expected tests/real/mandelbulb.frag
--preserve-all-globals --format c-variables -o tests/real/to_the_road_of_ribbon.expected tests/real/to_the_road_of_ribbon.frag
--no-renaming-list rotatey --format c-variables -o tests/real/sult.expected tests/real/sult.frag
--preserve-externals -o tests/unit/externals.preserved.expected tests/unit/externals.frag
--no-remove-unused --preserve-externals -o tests/unit/externals.preserved.expected tests/unit/externals.frag

# Multifile tests

--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/inout.expected tests/unit/inout.frag tests/unit/inout2.frag

# Tests with full renaming

--format c-array --no-inlining -o tests/unit/many_variables.expected tests/unit/many_variables.frag
--no-remove-unused --format c-array --no-inlining -o tests/unit/many_variables.expected tests/unit/many_variables.frag
--hlsl -o tests/real/elevated.hlsl.expected tests/real/elevated.hlsl
-o tests/real/lunaquatic.frag.expected tests/real/lunaquatic.frag
-o tests/real/yx_long_way_from_home.frag.expected tests/real/yx_long_way_from_home.frag
-o tests/real/oscars_chair.frag.expected tests/real/oscars_chair.frag
-o tests/real/the_real_party_is_in_your_pocket.frag.expected tests/real/the_real_party_is_in_your_pocket.frag
-o tests/unit/function_overload.expected tests/unit/function_overload.frag
-o tests/unit/externals.expected tests/unit/externals.frag
-o tests/unit/qualifiers.expected tests/unit/qualifiers.frag
-o tests/unit/macros.expected --no-inlining tests/unit/macros.frag
--format indented -o tests/unit/switch.expected tests/unit/switch.frag
--format indented -o tests/unit/forbidden.expected tests/unit/forbidden.frag
--no-remove-unused -o tests/unit/function_overload.expected tests/unit/function_overload.frag
--no-remove-unused -o tests/unit/externals.expected tests/unit/externals.frag
--no-remove-unused -o tests/unit/qualifiers.expected tests/unit/qualifiers.frag
--no-remove-unused -o tests/unit/macros.expected --no-inlining tests/unit/macros.frag
--no-remove-unused --format indented -o tests/unit/switch.expected tests/unit/switch.frag
--no-remove-unused --format indented -o tests/unit/forbidden.expected tests/unit/forbidden.frag
--format c-variables -o tests/real/heart.frag.expected tests/real/heart.frag

# Optimization tests
Expand Down
62 changes: 20 additions & 42 deletions tests/real/sult.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,34 @@
#ifndef SULT_EXPECTED_
# define SULT_EXPECTED_
# define VAR_resolution "m"
# define VAR_time "c"
# define VAR_time "l"

const char *sult_frag =
"float v=5.,z=.9,y=0.,a=90.,x=0.;"
"vec3 r=vec3(1,1,1),n=vec3(0,0,1),s=vec3(0,0,1.5);"
"float v=5.,y=.9,a=0.,f=90.,e=0.;"
"vec3 r=vec3(1,1,1),c=vec3(0,0,1),t=vec3(0,0,1.5);"
"uniform vec2 m;"
"uniform float c;"
"vec3 rotatey(vec3 v,float r)"
"uniform float l;"
"vec3 rotatey(vec3 v,float m)"
"{"
"return vec3(v.x*cos(r)+v.z*sin(r),v.y,v.z*cos(r)-v.x*sin(r));"
"return vec3(v.x*cos(m)+v.z*sin(m),v.y,v.z*cos(m)-v.x*sin(m));"
"}"
"vec3 e(vec3 v,float r)"
"float u=0.,n=10.;"
"float s(vec3 m)"
"{"
"return vec3(v.y*cos(r)+v.z*sin(r),v.x,v.z*cos(r)-v.y*sin(r));"
"}"
"float f=0.,w=10.;"
"float e(vec3 r)"
"{"
"float y=c,w,z=0.,g,x,a;"
"vec3 m;"
"r+=(sin(r.zxy*1.7+y)+sin(r.yzx+y*3.))*.2;"
"float z=l,y,a=0.,f,e,c;"
"vec3 r;"
"m+=(sin(m.zxy*1.7+z)+sin(m.yzx+z*3.))*.2;"
"if(v<6.)"
"z=length(r.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34;"
"a=length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,z*.15-.3))-.34;"
"else"
" z=length(r.xy+vec2(0.,.7))-.3+(sin(r.z*17.+y*.6)+sin(r.z*2.)*6.)*.01;"
"r.xy=vec2(atan(r.x,r.y)*1.113,1.6-length(r.xy)-sin(y*2.)*.3);"
"m=fract(r.xzz+.5).xyz-.5;"
"m.y=(r.y-.35)*1.3;"
"w=max(abs(r.y-.3)-.05,abs(length(fract(r.xz)-.5)-.4)-.03);"
"f=step(z,w);"
"return min(min(w,z),r.y-.2);"
" a=length(m.xy+vec2(0.,.7))-.3+(sin(m.z*17.+z*.6)+sin(m.z*2.)*6.)*.01;"
"m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(z*2.)*.3);"
"r=fract(m.xzz+.5).xyz-.5;"
"r.y=(m.y-.35)*1.3;"
"y=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);"
"u=step(a,y);"
"return min(min(y,a),m.y-.2);"
"}"
"vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);"
"void e()"
"{"
"vec2 l=-1.+2.*gl_FragCoord.xy/m.xy;"
"vec3 i=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-y*.035).yxz,(a+x*c)*.035)),p=n+s*c;"
"float u=1.,h=0.,F,C,b=0.,Z,Y,X,W;"
"vec3 V=vec3(.01,0,0),U=V.yyy,T;"
"while(u>.1)"
"{"
"for(F=b,C=1.;F<w&&C>.005;F+=C)"
"C=e(p+i*F);"
"if(F<w)"
"p+=i*F,Z=e(p),X=f,T=normalize(-vec3(Z-e(p+V.xyy),Z-e(p+V.yxy),Z-e(p+V.yyx))),Y=clamp(e(p+T*.05)*4.+e(p+T*.1)*2.+.5,.1,1.),h=X*.3,T=normalize(T+step(4.,v)*f*sin(p.yzx*40.)*.05),i=reflect(i,T),W=clamp(dot(normalize(r),T),0.,1.),T=mix(mix(d,o,W),t*(W+.2),X)+vec3(.7*pow(clamp(dot(normalize(r),i),0.,1.),12.)),U+=u*mix(T*Y,g,F/w),u*=h*(1.-F/w),b=.1;"
"else"
" U+=u*g,u=0.;"
"}"
"gl_FragColor.xyz=U;"
"gl_FragColor.w=1.;"
"}";
"vec3 x=vec3(.19,.2,.24),i=vec3(1),z=vec3(.45,.01,0),o=vec3(.17,0,0);";

#endif // SULT_EXPECTED_
Loading

0 comments on commit d3cfc0e

Please sign in to comment.