-
Notifications
You must be signed in to change notification settings - Fork 3
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
Push selects over conditions to eliminate some unecessary tuples. #33
Conversation
Looks good to me. What do you think @emilaxelsson? |
Are we sure that it's better to have two conditions without creating a struct than to have a single condition with a struct? If the answer is "depends on the back end", I think we should make this optimization optional (which we don't have the infrastructure for at the moment). Note that this optimization will be subsumed by the fix of Feldspar/feldspar-compiler#3 (which might take a while). |
We are sure that it's better to have a single condition without creating the struct than to have a single condition with a struct. The code that we start optimizing from is: (\var0 -> (\var1 -> ((sel1 (condition (var0 == var1) (tup2 var0 2) (tup2 var1 3))) + (sel2 (condition (var0 == var1) (tup2 var0 2) (tup2 var1 3)))))) There's apparently some interaction with CSE because the generated code should really be: (\var0 -> (\var1 -> (condition (var0 == var1) (var0 + 2) (var1 + 3)) I don't see how this could be subsumed by the other ticket; this optimization has the possibility to completely eliminate variables from the program whereas the other ticket will remove the struct but not any of its members. |
Agreed.
Right, what I had in mind was your initial example for which the optimization produced two conditionals. For that case I think it would be preferred to have a single conditional assigning two separate variables. |
That would require the following rule
which we don't have at the moment. This rule seems dangerous since it duplicates So, the idea of pushing selects inside conditionals and then merging conditionals seems very good in many cases, but as far as I can see, it's not an optimization we can just apply anywhere. If that's the case, I think we need to investigate this a bit more. |
f (condition x a b) (condition x c d) ==> condition x (f a c) (f b d) which we don't have at the moment. This rule seems dangerous since it duplicates f. That's OK for simple functions, but not in general. That danger is real, but I think we're looking at this problem from the wrong perspective (because it's a really hard problem to solve). By shifting the perspective and look at the outputs of the opitmization we can avoid the problem of trying to predict the outcome of the optimization by looking at the inputs. The implementation of the optimization is something along the following lines: transform context (Cond c t1 f1) (Cond c t2 f2) = do
t' <- opt context (t1 + t2)
f' <- opt context (f1 + f2)
let result | acceptable (t1 + t2) t' && acceptable (f1 + f2) f' = Cond c t' f'
| otherwise = context (transform emptyContext (Cond c t1 f1)) (transform emptyContext (Cond c t2 f2))
return result We had pretty much precisely this idea implemented in our supercompiler and the performance penalty from this was not even visible when profiling the compiler. What infrastructure is required for making optimizations optional--just passing a record of the current options around? |
Ok, cool! But let's make it an optional transformation to begin with.
Yes. Feel free to implement it :) |
I'm closing this issue for now. Feel free to make a new request once there is a transformation that can be applied optionally. |
I only have a rough semantic understanding of how the optimizations work, for all I know we could be traversing the AST a million times. It does work though:
For the program: