[llvm-dev] Bitwise AND blocks re-association

Friedman, Eli via llvm-dev llvm-dev at lists.llvm.org
Wed Nov 16 11:07:22 PST 2016


On 11/16/2016 7:28 AM, Timofeev, Alexander via llvm-dev wrote:
>
> Hi All,
>
> I’m writing to ask for the suggestion.
>
> I’m working on the AMDGPU project. I was recently analyzing our 
> backend performance looking for optimization opportunities and found 
> that LoadStore vectorizer is unable to handle simple case.
>
> The deeper look revealed that the reason was in a i64 to i32 truncation.
>
> The OpenCL code looks like this:
>
> __kernel void read_linear(__global float *input,__global float *output)
>
> {
>
>         float val = 0.0f;
>
>         uint gid = get_global_id(0);
>
>         val = val + input[gid + 0];
>
>         val = val + input[gid + 1];
>
>         val = val + input[gid + 2];
>
>         val = val + input[gid + 3];
>
>         val = val + input[gid + 4];
>
> *** and so on… ***
>
>         output[gid] = val;
>
> }
>
> I’d expect loads to be combined   since they all have same base and 
> offsets are constants and consecutively increasing.
>
> That is exactly what happens if I change ‘uint’ to ‘ulong’ in the 
> assignment: uint gid = get_global_id(0)  => ulong gid = 
> get_global_id(0) – loads are combined as expected.
>
> The reason is simple:
>
> OpenCL get_global_id(uint) returns i64
>
> The result is assigned to i32
>
> Clang generates trunc i64 to i32 as AND with FFFFFFFF:
>
> %call = tail call i64 @_Z13get_global_idj(i32 0) #2
>
>   %idxprom = and i64 %call, 4294967295
>
>   %arrayidx = getelementptr inbounds float, float addrspace(1)* 
> %input, i64 %idxprom
>
>   %0 = load float, float addrspace(1)* %arrayidx, align 4, !tbaa !7
>
> So, LoadStoreVectorizer cannot combine with the next load:
>
>   %add2 = add i64 %call, 1
>
>   %idxprom3 = and i64 %add2, 4294967295
>
>   %arrayidx4 = getelementptr inbounds float, float addrspace(1)* 
> %input, i64 %idxprom3
>
>   %1 = load float, float addrspace(1)* %arrayidx4, align 4, !tbaa !7
>
> Basically we have a case: C1 & ( A + C2 ) => C1 & A + C1 & C2 that is 
> not always legal.
>
> In our case that really is trunc(A+C) => trunc(A) + trunc(C) that is 
> legal.
>
> NaryReassociate cannot handle this because it only considers ADD, MUL, GEP
>
> Reassociate cannot handle this either just because it explicitly looks 
> for “X&~X == 0, X|~X == -1.” or “Y ^ X^X -> Y”
>
> We definitely should be able to optimize 0xFFFFFFFF & ( A + 1 ) to  
> 0xFFFFFFFF & A + 1 given that  bitwise AND with FFFFFFFF  is a special 
> case.
>
> We maybe want be able to enhance bitwise operation processing to 
> handle more common cases.
>

I'm not sure what you're expecting reassociation to do here.  If you can 
prove "gid + 1" doesn't wrap in your example (because of some property 
of the get_global_id() function), the AND is a no-op, so you can just 
kill it.  And if you can't prove "gid + 1" doesn't wrap, your proposed 
transformation is illegal.

-Eli

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161116/6e357aa4/attachment-0001.html>


More information about the llvm-dev mailing list