Open tomsmeding opened 4 years ago
Another example of similar behaviour, except now there is no dead code, but there is a more complicated scalar expression to reason about.
let a = use (fromList (Z :. (1 :: Int)) [(1::Float,2::Float)])
b = map fst a
in generate (I1 (let I1 n1 = shape b ; I1 n2 = shape a in min n1 n2))
(\(I1 i) -> b ! I1 i)
This show
s as:
let
a0 = use (Vector (Z :. 1) [(((), 1.0), 2.0)])
a1 = map (\(T2 x0 _) -> x0) a0
in
generate (min (let T1 x0 = shape a1 in x0) (let T1 x0 = shape a0 in x0)) (\(T1 x0) -> a1 ! x0)
whereas an optimal fusion result would have been map fst (use (Vector ...))
.
Notable is that if fst
is replaced by (*2)
(and the type of a
with Vector Float
), then the map
does fuse. Is this an instance of the thing I ran into earlier, where nodes like map fst
in the fused AST are not actually compiled as manifest arrays but rather reduce to manipulation of SoA-form arrays?
Two more programs that produce (somewhat) unexpected results:
zipWith (+)
(zipWith (\x y -> x * 2 * y) a a)
(map (\x -> x * x) a)
which show
s as:
\a0 ->
transform
(let T1 x0 = shape a0 ; T1 x1 = shape a0 ; T1 x2 = shape a0 in (min (min x1 x0) x2))
(\(T1 x0) -> x0)
(\x0 -> 2.0 * x0 * x0 + x0 * x0)
a0
which could have been \a -> map (\x -> 2 * x * x + x * x) a
.
Program 2:
zipWith (+) a (map (\x -> x) a)
which show
s as:
\a0 ->
let a1 = map (\x0 -> x0) a0
in
generate
(let T1 x0 = shape a1 ; T1 x1 = shape a0 in (min x1 x0))
(\(T1 x0) -> a0 ! x0 + a1 ! x0)
which could have been \a -> map (\x -> x * x) a
, or indeed \a -> generate (shape a) (\(T1 x) -> a ! x + a ! x)
.
I'm just collecting these for future reference at this point.
Description The fusion pipeline tries to express array shape queries in expressions (with the
shape
primitive) in terms of shapes of argument arrays if not doing so would prevent fusion. However, the algorithm seems to miss certain cases; the case I ran into involves a shape query of an array that is not used anywhere outside of that shape query (and is thus dead code).Steps to reproduce Consider the following code:
The only difference between these two programs is the argument to
shape
. Note thata8
anda9
have the same shape by definition ofmap
.The first program
show
s to:The second program
show
s to:The first program exhibits suboptimal fusion, even though it is equivalent to the second.
Expected behaviour Both programs should fuse to the same result, eliminating all
map
calls.Your environment
accelerate-1.3.0.0
on Hackage, or commit162a779f
.