Skip to content

Commit

Permalink
Make LValue detection more precise and more reusable
Browse files Browse the repository at this point in the history
- In `arr[idx] = 1`, we now detect that arr a lvalue, while idx is not.
- LValue detection is now part of the generic map function
  • Loading branch information
laurentlb committed Dec 11, 2022
1 parent b54ca90 commit 247b787
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 27 deletions.
30 changes: 8 additions & 22 deletions src/analyzer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,34 +100,20 @@ let inlineAllConsts li =
|> mapTopLevel (mapEnv mapExpr mapStmt)
|> List.map mapTLDecl

let assignOps = Set.ofList [
"="; "+="; "-="; "*="; "/="; "%="
"<<="; ">>="; "&="; "^="; "|="
"++"; "--"; "$++"; "$--"
]

let markLValues li =
// Helpers for the bodies of functions: find any expression of the form
// "foo = ..." or "foo += ..." etc, then scan through all of "foo" marking
// any variable seen there as potentially in an lvalue position. This will
// over-mark things, e.g., "x[i]" both "x" and "i" will get marked even
// though the latter does not need to be, but it is simple.
let markVars env = function
| Var v as e ->

let findWrites (env: MapEnv) = function
| Var v as e when env.isLValue ->
match env.vars.TryFind v.Name with
| Some (_, {name = vv}) -> vv.IsLValue <- true; e
| _ -> e
| e -> e

let findWrites env = function
| FunCall(Op o, e::args) when assignOps.Contains o ->
let newEnv = {env with fExpr = markVars}
FunCall(Op o, (mapExpr newEnv e)::args)
| FunCall(Var v, _) as e ->
| FunCall(Var v, args) as e ->
match env.fns.TryFind v.Name with
| Some (fct, _) when fct.fName.IsLValue ->
let newEnv = {env with fExpr = markVars}
mapExpr newEnv e
let newEnv = {env with isLValue = true}
for arg in args do
(mapExpr newEnv arg: Expr) |> ignore
e
| _ -> e
| e -> e

Expand Down
16 changes: 14 additions & 2 deletions src/ast.fs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,16 @@ type MapEnv = {
fStmt: Stmt -> Stmt
vars: Map<string, Type * DeclElt>
fns: Map<string, FunctionType * Stmt>
isLValue: bool
}

let mapEnv fe fi = {fExpr = fe; fStmt = fi; vars = Map.empty; fns = Map.empty}
let mapEnv fe fi = {fExpr = fe; fStmt = fi; vars = Map.empty; fns = Map.empty; isLValue = false}

let assignOps = Set.ofList [
"="; "+="; "-="; "*="; "/="; "%="
"<<="; ">>="; "&="; "^="; "|="
"++"; "--"; "$++"; "$--"
]

let foldList env fct li =
let mutable env = env
Expand All @@ -146,10 +153,15 @@ let foldList env fct li =

// Applies env.fExpr recursively on all nodes of an expression.
let rec mapExpr env = function
| FunCall(Op o as fct, first::args) when assignOps.Contains o ->
let first = mapExpr {env with isLValue = true} first
env.fExpr env (FunCall(mapExpr env fct, first :: List.map (mapExpr env) args))
| FunCall(fct, args) ->
let env = {env with isLValue = false}
env.fExpr env (FunCall(mapExpr env fct, List.map (mapExpr env) args))
| Subscript(arr, ind) ->
env.fExpr env (Subscript(mapExpr env arr, Option.map (mapExpr env) ind))
let indexEnv = {env with isLValue = false}
env.fExpr env (Subscript(mapExpr env arr, Option.map (mapExpr indexEnv) ind))
| Dot(e, field) -> env.fExpr env (Dot(mapExpr env e, field))
| Cast(id, e) -> env.fExpr env (Cast(id, mapExpr env e))
| VectorExp(li) ->
Expand Down
4 changes: 1 addition & 3 deletions tests/unit/inline-aggro.aggro.expected
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ float inl7()
}
int inl8(ivec3 x)
{
int i=1;
x[i]+=1;
return x[i]+i;
return x[1]+=1,x[1]+1;
}
float noinl1()
{
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/inline.aggro.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#version 120

float result;
void main()
{
Expand Down Expand Up @@ -37,6 +39,11 @@ int dont_inline_lvalue()
a=2;
return 3;
}
float arr[]=float[](3.4,4.2);
void lvalues()
{
arr[1]=2.;
}
uniform int time;
in int sync;
int dependOnConst()
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/inline.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#version 120

float result;
void main()
{
Expand Down Expand Up @@ -39,6 +41,11 @@ int dont_inline_lvalue()
a=2;
return 3;
}
float arr[]=float[](3.4,4.2);
void lvalues()
{
arr[1]=2.;
}
uniform int time;
in int sync;
int dependOnConst()
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/inline.frag
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#version 120

float result;

void main()
Expand Down Expand Up @@ -67,6 +69,12 @@ int dont_inline_lvalue() {
return 3;
}

float arr[] = float[](3.4, 4.2);
void lvalues() {
int a = 1;
arr[a] = 2.;
}

uniform int time;
in int sync;

Expand Down
8 changes: 8 additions & 0 deletions tests/unit/inline.no.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#version 120

float result;
void main()
{
Expand Down Expand Up @@ -43,6 +45,12 @@ int dont_inline_lvalue()
a=2;
return 3;
}
float arr[]=float[](3.4,4.2);
void lvalues()
{
int a=1;
arr[a]=2.;
}
uniform int time;
in int sync;
int dependOnConst()
Expand Down

0 comments on commit 247b787

Please sign in to comment.