Skip to content

Commit

Permalink
Iterate inlining and simplification until we can do no more (#133)
Browse files Browse the repository at this point in the history
Inlining can open up new opportunities for simplification. The rewriter
tries to take advantage of this by doing two passes, but there can be
chains of inlinable variables which can require an arbitrary number of
passes. Instead, we can track whether or not we've inlined a variable
this pass, and continue with further passes until we haven't found such
a variable.
  • Loading branch information
jwatzman committed May 5, 2022
1 parent 342adde commit 50b12fe
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
28 changes: 19 additions & 9 deletions src/rewriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ let collectReferences stmtList =
// - the variable is used only once in the current block
// - the variable is not used in a sub-block (e.g. inside a loop)
// - the init value is trivial (doesn't depend on a variable)
let findInlinable block =
let findInlinable foundInlinable block =
// Variables that are defined in this scope.
// The boolean indicates if the variable initialization has dependencies.
let localDefs = Dictionary<string, (Ident * bool)>()
Expand Down Expand Up @@ -213,8 +213,8 @@ let findInlinable block =
let ident, hasInitDeps = def.Value
if not ident.ToBeInlined then
match localReferences.TryGetValue(def.Key), allReferences.TryGetValue(def.Key) with
| (true, 1), (true, 1) when not hasInitDeps -> ident.Inline()
| (false, _), (false, _) -> ident.Inline()
| (true, 1), (true, 1) when not hasInitDeps -> ident.Inline(); foundInlinable := true
| (false, _), (false, _) -> ident.Inline(); foundInlinable := true
| _ -> ()

let private simplifyStmt = function
Expand All @@ -227,9 +227,6 @@ let private simplifyStmt = function
// Remove inner empty blocks
let b = b |> List.filter (function Block [] | Decl (_, []) -> false | _ -> true)

if not options.noInlining then
findInlinable b

// Try to remove blocks by using the comma operator
let returnExp = b |> Seq.tryPick (function Jump(JumpKeyword.Return, e) -> e | _ -> None)
let canOptimize = b |> List.forall (function
Expand Down Expand Up @@ -267,12 +264,25 @@ let reorderTopLevel t =
else
t

let rec iterateSimplifyAndInline li =
let foundInlinable =
if options.noInlining then
false
else
let foundInlinableRef = ref false
let mapExpr _ e = e
let mapStmt = function
| Block b as e -> findInlinable foundInlinableRef b; e
| e -> e
mapTopLevel (mapEnv mapExpr mapStmt) li |> ignore
!foundInlinableRef
let simplified = mapTopLevel (mapEnv simplifyExpr simplifyStmt) li
if foundInlinable then iterateSimplifyAndInline simplified else simplified

let simplify li =
li
|> reorderTopLevel
|> mapTopLevel (mapEnv simplifyExpr simplifyStmt)
// A second pass, because some variables might now be inlinable.
|> mapTopLevel (mapEnv simplifyExpr simplifyStmt)
|> iterateSimplifyAndInline
|> List.map (function
| TLDecl (ty, li) -> TLDecl (rwType ty, declsNotToInline li)
| TLVerbatim s -> TLVerbatim (stripSpaces s)
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/inline.expected
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ int arithmetic2()
}
int unusedVars()
{
int d=30;
return d;
return 30;
}
int unusedVars2()
{
return 18;
}
int multiPass()
{
return 3;
}
8 changes: 8 additions & 0 deletions tests/unit/inline.frag
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ int unusedVars2() {
int var7 = 7, var8 = 8, var9 = 9, var10 = 10, var11 = 11, var12 = 12;
return var1 + var5 + var12;
}

int multiPass()
{
int one = 1;
int two = one * 2;
int three = two + 1;
return three;
}
5 changes: 5 additions & 0 deletions tests/unit/inline.no.expected
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ int unusedVars2()
int var1=1,var2=2,var3=3,var4=4,var5=5,var6=6,var7=7,var8=8,var9=9,var10=10,var11=11,var12=12;
return var1+var5+var12;
}
int multiPass()
{
int one=1,two=one*2,three=two+1;
return three;
}

0 comments on commit 50b12fe

Please sign in to comment.