Eliminating unused code (Compiler/language design)
Posted: Tue Jun 17, 2014 10:52 am
I've been thinking about single static assignment form in preparation for writing a JIT compiler in my virtual machine. One of the very nice things about SSA form is the ability to detect unused variables.
For example - in psuedo code:
In SSA form this could be written as:
Now, because we can see a1 is not used, we can eliminate it, reducing the function to:
(We could take this one step further and detect a2 is a constant and just "return 5".)
In the following code:
We can detect that the result of our function call to randomNumber() is assigned to a (a1 in SSA form) but because that value is never used, we can eliminate it the call to randomNumber().
But how do we now if it is safe to eliminate a function call? Another example with objects would be this:
In SSA form:
Working backwards, we can see that the value of a1 is never referenced, so we eliminate it:
Now, random1 is never referenced, so we can eliminate it:
In that example, we were able to remove the construction of an object and a function call, because we knew we weren't going to use the result.
However - what if the function has side effects? For example:
In SSA form:
Since a1 is never used, we'd eliminate it:
Now that file1 is not used, we'd eliminate it too:
However, file.write has side-effects. It has to perform something, even if we do not use the value it returned.
Imagine this example:
in SSA form:
We see that error1 and error2 have the same value, so rather than call it twice, one can reference the other:
This also opens a whole can of worms on figuring out if functions can be rearranged, if duplicate code can be reused, etc.
I'm thinking either:
https://github.com/MessiahAndrw/Percept ... ntation.md
Being SSA, the destination is literally the instruction itself, e.g.:
For example - in psuedo code:
Code: Select all
var a = 10;
a = 5;
return a;
Code: Select all
a1 = 10
a2 = 5
return a2
Code: Select all
a2 = 5
return a2
In the following code:
Code: Select all
var a = randomNumber();
a = 5;
return a;
But how do we now if it is safe to eliminate a function call? Another example with objects would be this:
Code: Select all
var random = new RandomNumberGenerator();
a = random.randomNumber();
a = 5;
return a;
Code: Select all
random1 = new RandomNumberGenerator()
a1 = random1.randomNumber()
a2 = 5
return a2
Code: Select all
random1 = new object
a2 = 5
return a2
Code: Select all
a2 = 5
return a2
However - what if the function has side effects? For example:
Code: Select all
var file = new File("abc.txt");
var a = file.write("hello");
a = 5;
return a;
Code: Select all
file1 = new File("abc.txt")
a1 = file.write("hello")
a2 = 5
return a2
Code: Select all
file1 = new File("abc.txt")
a2 = 5
return a2
Code: Select all
a2 = 5
return a2
Imagine this example:
Code: Select all
var file = new File("abc.txt");
var error = file1.write("hello");
// check here
error = file1.write("hello");
// check here
Code: Select all
file1 = new File("abc.txt")
error1 = file1.write("hello")
error2 = file1.write("hello")
Code: Select all
file1 = new File("abc.txt")
error1 = file1.write("hello")
error2 = error1
I'm thinking either:
- Assume all function calls have side-effects, and never eliminate them. At best we may remove the assignment but never the function call:
May be reduced to:Code: Select all
file1 = new File("abc.txt") a1 = file.write("hello") a2 = 5 return a2
The assignment "a1 =" was eliminated, but the function call is still there.Code: Select all
file1 = new File("abc.txt") file.write("hello") a2 = 5 return a2
- Have some language feature to distinguish between functions with side-effects and functional functions without side-effects. In a static language it may be possible for the compiler to automatically detect this, but this would be much harder in a dynamic language - as functions are first class types and we don't exactly know the function we are calling at compile time. However, a programmer usually may have a good idea if a function has side-effects and if it may be removed or called out of order, so we could add syntax to tell the compiler that the function call is functional.
For example:Code: Select all
var a = cos#(b); // the # tells the compiler this is a functional function that may be eliminated var c = sqrt#(d); var e = file.write("abc"); // no #, cannot be eliminated
https://github.com/MessiahAndrw/Percept ... ntation.md
Being SSA, the destination is literally the instruction itself, e.g.:
Code: Select all
0x000 Float 5.0
0x001 Float 8.0
0x002 Add 0x000 0x001 ; 5 + 8 = 13
0x003 Float 7.1
0x004 Add 0x002 0x003 ; 13 + 7.1 = 20.1
0x005 Return 0x004 ; returns 20.1