8000 Peephole optims, var scoping (fixes #153) by eldritchconundrum · Pull Request #349 · laurentlb/shader-minifier · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Peephole optims, var scoping (fixes #153) #349

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

Merged
merged 10 commits into from
Apr 18, 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
4 changes: 2 additions & 2 deletions src/analyzer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ module private VariableInlining =
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 ->
debug $"inlining local variable '{Printer.debugIdent ident}' because it's safe to inline and used only once"
debug $"inlining local variable '{Printer.debugIdent ident}' because it's safe to inline (const) and used only once"
ident.ToBeInlined <- true
| (_, 0), (_, 0) ->
debug $"inlining local variable '{Printer.debugIdent ident}' because it's safe to inline and unused"
debug $"inlining (removing) local variable '{Printer.debugIdent ident}' because it's safe to inline and unused"
ident.ToBeInlined <- true
| _ -> ()

Expand Down
63 changes: 46 additions & 17 deletions src/rewriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ let renameField field =
field |> String.map (fun c -> options.canonicalFieldNames.[swizzleIndex c])
else field

let rec private isPure = function
| Var v when v.Name = "true" || v.Name = "false" -> true
| Int _
| Float _ -> true
| FunCall(Var fct, args) ->
Builtin.pureBuiltinFunctions.Contains fct.Name && List.forall isPure args
| FunCall(Op op, args) -> not (Builtin.assignOps.Contains op) && List.forall isPure args
| _ -> false

module private RewriterImpl =

// Remove useless spaces in macros
Expand Down Expand Up @@ -410,35 +419,62 @@ module private RewriterImpl =
| Decl (_, []) -> false
| _ -> true)

let exprUsesIdentName expr identName =
let mutable idents = []
let collectLocalUses _ = function
| Var v as e -> idents <- v :: idents; e
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider replacing idents with a boolean, if you just want to know if we've found identName

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be more useful to return the names, in case we want to search multiple names without visiting the tree multiple times.

| e -> e
mapExpr (mapEnv collectLocalUses id) expr |> ignore<Expr>
idents |> List.exists (fun i -> i.Name = identName)

// Merge two consecutive items into one, everywhere possible in a list.
let rec squeeze (f : 'a * 'a -> 'a option) = function
let rec squeeze (f : 'a * 'a -> 'a list option) = function
| h1 :: h2 :: t ->
match f (h1, h2) with
| Some x -> squeeze f (x :: t)
| Some xs -> squeeze f (xs @ t)
| None -> h1 :: (squeeze f (h2 :: t))
| h :: t -> h :: t
| [] -> []

// Merge preceding expression into a for's init.
let b = b |> squeeze (function
// Merge preceding expression into a for's init.
| (Expr e, ForE (None, cond, inc, body)) -> // a=0;for(;i<5;++i); -> for(a=0;i<5;++i);
Some (ForE (Some e, cond, inc, body))
Some [ForE (Some e, cond, inc, body)]
| (Expr e, While (cond, body)) -> // a=0;while(i<5); -> for(a=0;i<5;);
Some (ForE(Some e, Some cond, None, body))
Some [ForE(Some e, Some cond, None, body)]
| Decl (_, [declElt]), Jump(JumpKeyword.Return, Some (Var v)) // int x=f();return x; -> return f();
when v.Name = declElt.name.Name && declElt.init.IsSome ->
Some (Jump(JumpKeyword.Return, declElt.init))
Some [Jump(JumpKeyword.Return, declElt.init)]
| Expr (FunCall(Op "=", [Var v1; e])), Jump(JumpKeyword.Return, Some (Var v2)) // x=f();return x; -> return f();
when v1.Name = v2.Name ->
match v1.VarDecl with
| Some d ->
if d.scope <> VarScope.Global && not (d.ty.isOutOrInout) then
Some (Jump(JumpKeyword.Return, Some e))
Some [Jump(JumpKeyword.Return, Some e)]
else
None
| _ -> None
// Remove unused assignment immediately followed by re-assignment: m=14.;m=58.; -> 14.;m=58.;
| Expr (FunCall (Op "=", [Var name; init1])), (Expr (FunCall (Op "=", [Var name2; init2])) as assign2)
when name.Name = name2.Name && not (exprUsesIdentName init2 name.Name) ->
match name.Declaration with
| Declaration.Variable decl when decl.scope = VarScope.Global ->
// The assignment should not be removed if init2 calls a function that reads the global variable.
None // Safely assume it could happen.
| Declaration.Variable _ -> Some [Expr init1; assign2] // Transform is safe even if the var is an out parameter.
| _ -> None
// Compact a pure declaration immediately followed by re-assignment: float m=14.;m=58.; -> float m=58.;
| Decl (ty, [declElt]), (Expr (FunCall (Op "=", [Var name2; init2])) as assign2)
when declElt.name.Name = name2.Name
&& not (exprUsesIdentName init2 declElt.name.Name)
&& declElt.init |> Option.map isPure |> Option.defaultValue true ->
Some [Decl (ty, [{declElt with init = Some init2}])]
| _ -> None)

// Remove pure expression statements.
let b = b |> List.filter (function
| Expr e when isPure e -> false
| _ -> true)

// Inline inner decl-less blocks. (Presence of decl could lead to redefinitions.) a();{b();}c(); -> a();b();c();
let b = b |> List.collect (function
| Block b when hasNoDecl b -> b
Expand Down Expand Up @@ -478,7 +514,7 @@ module private RewriterImpl =
let simplifyStmt = function
| Block [] as e -> e
| Block b -> match simplifyBlock b with
| [stmt] -> stmt
| [stmt] as b when hasNoDecl b -> stmt
| stmts -> Block stmts
| Decl (ty, li) -> Decl (rwType ty, declsNotToInline li)
| ForD ((ty, d), cond, inc, body) -> ForD((rwType ty, declsNotToInline d), cond, inc, squeezeBlockWithComma body)
Expand Down Expand Up @@ -584,14 +620,7 @@ let reorderFunctions code =
// Inline the argument of a function call into the function body.
module private ArgumentInlining =

let rec isInlinableExpr = function
| Var v when v.Name = "true" || v.Name = "false" -> true
| Int _
| Float _ -> true
| FunCall(Var fct, args) ->
Builtin.pureBuiltinFunctions.Contains fct.Name && List.forall isInlinableExpr args
| FunCall(Op op, args) -> not (Builtin.assignOps.Contains op) && List.forall isInlinableExpr args
| _ -> false
let isInlinableExpr e = isPure e

type [<NoComparison>] Inlining = {
func: TopLevel
Expand Down
16 changes: 8 additions & 8 deletions tests/compression_results.log
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
clod.frag... 8897 => 1528.145
mouton/mouton.vert... 17026 => 2457.862
audio-flight-v2.frag 4538 => 891.404
buoy.frag 4097 => 624.156
controllable-machinery.frag 7720 => 1220.140
ed-209.frag 7768 => 1340.423
buoy.frag 4094 => 622.550
controllable-machinery.frag 7708 => 1220.329
ed-209.frag 7766 => 1341.089
elevated.hlsl 3405 => 603.218
endeavour.frag 2605 => 534.116
from-the-seas-to-the-stars.frag 14292 => 2328.094
frozen-wasteland.frag 4583 => 806.518
kinder_painter.frag 2867 => 447.669
frozen-wasteland.frag 4578 => 806.452
kinder_painter.frag 2865 => 445.014
leizex.frag 2298 => 510.191
lunaquatic.frag 5247 => 1049.030
mandelbulb.frag 2370 => 538.322
ohanami.frag 3256 => 722.517
orchard.frag 5537 => 1022.773
oscars_chair.frag 4651 => 986.364
robin.frag 6297 => 1053.367
robin.frag 6295 => 1052.336
slisesix.frag 4573 => 931.855
terrarium.frag 3626 => 746.585
terrarium.frag 3624 => 745.827
the_real_party_is_in_your_pocket.frag 12111 => 1794.687
valley_ball.glsl 4386 => 888.496
yx_long_way_from_home.frag 2947 => 606.406
Total: 135097 => 23632.338
Total: 135069 => 23627.076
3 changes: 1 addition & 2 deletions tests/real/buoy.frag.expected
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ void mainImage(out vec4 fragColor,vec2 fragCoord)
vec3 pos,ray;
CamPolar(pos,ray,camRot,fragCoord);
float to=TraceOcean(pos,ray),tb=TraceBoat(pos,ray);
vec3 result;
result=to>0.&&(to<tb||tb==0.)?
vec3 result=to>0.&&(to<tb||tb==0.)?
ShadeOcean(pos+ray*to,ray,fragCoord):
tb>0.?
ShadeBoat(pos+ray*tb,ray):
Expand Down
18 changes: 6 additions & 12 deletions tests/real/controllable-machinery.frag.expected
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ vec4 BPos(float t)
}
float PrBoxDf(vec3 p,vec3 b)
{
vec3 d;
d=abs(p)-b;
vec3 d=abs(p)-b;
return min(max(d.x,max(d.y,d.z)),0.)+length(max(d,0.));
}
float PrRoundBoxDf(vec3 p,vec3 b)
Expand Down Expand Up @@ -78,8 +77,7 @@ float Maxv2(vec2 p)
}
float SmoothMin(float a,float b,float r)
{
float h;
h=clamp(.5+.5*(b-a)/r,0.,1.);
float h=clamp(.5+.5*(b-a)/r,0.,1.);
return mix(b-h*r,a,h);
}
float SmoothMax(float a,float b,float r)
Expand All @@ -100,8 +98,7 @@ mat3 StdVuMat(float el,float az)
}
vec2 Rot2D(vec2 q,float a)
{
vec2 cs;
cs=sin(a+vec2(1.57079635,0));
vec2 cs=sin(a+vec2(1.57079635,0));
return vec2(dot(q,vec2(cs.x,-cs.y)),dot(q.yx,cs));
}
float GearWlDf(vec3 p,float rad,float wlThk,float tWid,float nt,float aRot,bool bev,float dMin)
Expand Down Expand Up @@ -241,8 +238,7 @@ float GearRay(vec3 ro,vec3 rd)
vec3 GearNf(vec3 p)
{
vec4 v;
vec2 e;
e=vec2(5e-4,-5e-4);
vec2 e=vec2(5e-4,-5e-4);
for(int j=VAR_ZERO;j<4;j++)
v[j]=GearDf(p+(j<2?
j==0?
Expand All @@ -257,8 +253,7 @@ vec3 GearNf(vec3 p)
vec3 ObjNf(vec3 p)
{
vec4 v;
vec2 e;
e=vec2(5e-4,-5e-4);
vec2 e=vec2(5e-4,-5e-4);
for(int j=VAR_ZERO;j<4;j++)
v[j]=ObjDf(p+(j<2?
j==0?
Expand Down Expand Up @@ -447,8 +442,7 @@ vec3 ShowScene(vec3 ro,vec3 rd)
}
vec4 Loadv4(int idVar)
{
float fi;
fi=float(idVar);
float fi=float(idVar);
return texture(txBuf,(vec2(mod(fi,128.),floor(fi/128.))+.5)/txSize);
}
void mainImage(out vec4 fragColor,vec2 fragCoord)
Expand Down
3 changes: 1 addition & 2 deletions tests/real/ed-209.frag.expected
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,7 @@ MarchData room(vec3 p)
r.d=min(backWall,max(length(p.z),-doorHole+.1));
if(r.d==backWall)
{
float ocp;
ocp=min(abs(sdOctogon(xy,2.6)),abs(sdOctogon(xy,1.9)));
float ocp=min(abs(sdOctogon(xy,2.6)),abs(sdOctogon(xy,1.9)));
ocp=max(ocp,min(.7-abs(xy.x+1.2),-xy.y));
ocp=min(ocp,max(abs(sdOctogon(xy,1.2)),min(xy.x,.7-abs(xy.y))));
if(ocp<.3)
Expand Down
3 changes: 1 addition & 2 deletions tests/real/frozen-wasteland.frag.expected
6377
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ vec3 Sky(vec3 rd,vec3 ligt)
}
float Occ(vec3 p)
{
float h=0.;
h=clamp(map(p),.5,1.);
float h=clamp(map(p),.5,1.);
return sqrt(h);
}
void mainImage(out vec4 fragColor,vec2 fragCoord)
Expand Down
3 changes: 1 addition & 2 deletions tests/real/kinder_painter.expected
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
"float t(vec4 z,vec3 m,vec3 v)"
"{"
"vec3 r=m-z.xyz;"
"float w=dot(v.xz,v.xz),d=dot(v.xz,r.xz),b;"
"b=d*d-w*(dot(r.xz,r.xz)-z.w*z.w);"
"float w=dot(v.xz,v.xz),d=dot(v.xz,r.xz),b=d*d-w*(dot(r.xz,r.xz)-z.w*z.w);"
"if(b>0.)"
"b=(-d-sqrt(b))/w;"
"return b-.001;"
Expand Down
3 changes: 1 addition & 2 deletions tests/real/robin.frag.expected
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ float noise(vec3 x)
}
float fbm(vec3 p)
{
float f;
f=1.6*noise(p);
float f=1.6*noise(p);
p*=2.02;
f+=.35*noise(p);
p*=2.33;
Expand Down
2 changes: 1 addition & 1 deletion tests/real/terrarium.frag.expected
F438
Original file line numberDiff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void main()
else if(r<1.07)
col=mix(col,0.,.2),p.xy=p.xy+vec2(-.5,-.866025),p=S(p);
else
col=mix(col,0.,.2),col=1.,p.xy=p.xy+vec2(-.5,.866025),p=S(p),p.z+=.1;
mix(col,0.,.2),col=1.,p.xy=p.xy+vec2(-.5,.866025),p=S(p),p.z+=.1;
if(time>48.)
p.z=mix(p.z,mod(p.z+time/2.+2,4.)-2,smoothstep(48.,49.,time));
}
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/bug321.expected
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
int n;
float n;
float a(float s)
{
s=3.;
n=2.;
return s;
}
float main()
float b()
{
float t=3.;
t-=1.;
return a(1.)+a(5.);
}
}
4 changes: 2 additions & 2 deletions tests/unit/bug321.frag
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
int n;
float n;
const float s = 1.;
float a(float s)
{
s = 3.;
n = 2.;
return s;
}
float main()
float b()
{
float t = 3.;
t -= s;
Expand Down
14 changes: 6 additions & 8 deletions tests/unit/conditionals.frag.expected
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,14 @@ bool and3()
}
float ifStmtToExpr(float f)
{
float r,r2,r3;
r=f>0.?
1.:
2.;
r2=f>1.?
1.:
(1,2.);
float r3;
if(f>1.)
r3=1.;
else
r3=2.,1;
return r+r2+r3;
return(f>0.?
1.:
2.)+(f>1.?
1.:
(1,2.))+r3;
}
5 changes: 1 addition & 4 deletions tests/unit/inline-aggro.aggro.expected
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ float inl6()
return 2.*baz;
}
void notevil()
{
float x=101.;
x=42.;
}
{}
float inl7()
{
notevil();
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/inline-aggro.expected
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ float inl6()
}
void notevil()
{
float x=101.;
x=42.;
float x=42.;
}
float inl7()
{
Expand Down
13 changes: 11 additions & 2 deletions tests/unit/inline.aggro.expected
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ float multiPass2()
}
int dont_inline_lvalue()
{
int a=1;
a=2;
return 3;
}
vec4 fragColor247;
Expand Down Expand Up @@ -79,3 +77,14 @@ float inline_uninitialized()
{
return c;
}
float glo;
float noinline_readsTheGlobal()
{
return glo;
}
float dontCompressAssigments()
{
glo=10.;
glo=50.+noinline_readsTheGlobal();
return glo*glo;
}
Loading
0