Skip to content
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

Closed
wants to merge 3 commits into from
Closed

Conversation

pjonsson
Copy link
Member

@pjonsson pjonsson commented Nov 2, 2012

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:

cexp9 :: Data WordN -> Data WordN -> Data WordN
cexp9 a b = c+d
  where
    (c,d) = (a==b) ? ((a,2), (b,3))
> printExpr cexp9
(\var0 -> (\var1 -> (letBind (var0 == var1) (\var2 -> ((condition var2 var0 var1) + (condition var2 2 3))))))

@emwap
Copy link
Member

emwap commented Nov 4, 2012

Looks good to me. What do you think @emilaxelsson?

@emilaxelsson
Copy link
Member

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).

@pjonsson
Copy link
Member Author

pjonsson commented Nov 5, 2012

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.

@emilaxelsson
Copy link
Member

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.

Agreed.

I don't see how this could be subsumed by the other ticket

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.

@emilaxelsson
Copy link
Member

the generated code should really be:

(\var0 -> (\var1 -> (condition (var0 == var1) (var0 + 2) (var1 + 3))

That would require the following rule

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.

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.

@pjonsson
Copy link
Member Author

pjonsson commented Nov 5, 2012

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?

@emilaxelsson
Copy link
Member

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.

Ok, cool! But let's make it an optional transformation to begin with.

What infrastructure is required for making optimizations optional--just passing a record of the current options around?

Yes. Feel free to implement it :)

@emilaxelsson
Copy link
Member

I'm closing this issue for now. Feel free to make a new request once there is a transformation that can be applied optionally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants