[LLVMdev] why gvn does not work for global variables

Nick Lewycky nicholas at mxc.ca
Sun Jul 26 14:46:47 PDT 2015


Xiangyang Guo wrote:
> Hi, All,
>
> Suppose I have a very simple code like this and variable 'a' is a global
> variable:
> ***************************************************************************
> /double ** a;/
> /int main(){/
> /    a[5][10] = 0.1;/
> /    a[5][20] = 0.5;/
> /    return 0;/
> /}/
> ***************************************************************************/
> /
>
> Then I can get the IR without any optimization like this:
> ***************************************************************************
> /@a = global double** null, align 8/
> /
> /
> /; Function Attrs: nounwind uwtable/
> /define i32 @main() #0 {/
> /  %1 = alloca i32, align 4/
> /  store i32 0, i32* %1/
> /  %2 = load double*** @a, align 8/
> /  %3 = getelementptr inbounds double** %2, i64 5/
> /  %4 = load double** %3, align 8/
> /  %5 = getelementptr inbounds double* %4, i64 10/
> /  store double 1.000000e-01, double* %5, align 8/
> /  %6 = load double*** @a, align 8/
> /  %7 = getelementptr inbounds double** %6, i64 5/
> /  %8 = load double** %7, align 8/
> /  %9 = getelementptr inbounds double* %8, i64 20/
> /  store double 5.000000e-01, double* %9, align 8/
> /  ret i32 0/
> /}/
> ***************************************************************************
>
> I hope GVN can get rid of redundant 'load' and 'getelementptr'
> instructions such as '/%2 = load double*** @a, align 8/' and '/%6 = load
> double*** @a, align 8/'. So I use 'opt input.ll -basicaa -gvn -S -o
> output.ll ' , I still get :
> ***************************************************************************
> /  %2 = load double*** @a, align 8/
> /  %3 = getelementptr inbounds double** %2, i64 5/
> /  %4 = load double** %3, align 8/
> /  %5 = getelementptr inbounds double* %4, i64 10/
> /  store double 1.000000e-01, double* %5, align 8/
> /  %6 = load double*** @a, align 8/
> /  %7 = getelementptr inbounds double** %6, i64 5/
> /  %8 = load double** %7, align 8/
> /  %9 = getelementptr inbounds double* %8, i64 20/
> /  store double 5.000000e-01, double* %9, align 8/
> ***************************************************************************/
> /
>
> It seems GVN doesn't work. Then I use '-aa-eval', it seems LLVM thinks
> that is "*may alias*". But '%2' and '%6' are alias, right?
> ***************************************************************************
> /===== Alias Analysis Evaluator Report =====/
> /  45 Total Alias Queries Performed/
> /  13 no alias responses (28.8%)/
> /  32 may alias responses (71.1%)/
> /  0 partial alias responses (0.0%)/
> /  0 must alias responses (0.0%)/
> /  Alias Analysis Evaluator Pointer Alias Summary: 28%/71%/0%/0%/
> /  Alias Analysis Mod/Ref Evaluator Summary: no mod/ref!/
> ***************************************************************************
>
> Can anyone help me to use GVN in this situation? Thanks

There's not much you can do here; nothing tells GVN that %5 != @a, so it 
thinks it needs to reload @a after you store to it.

Because 'a' is an externally visible variable, a global initialize could 
have initializes 'a' in any way before main begins. To be deliberately 
hostile, I could prepare it as such:

   a[5] = (double*)&a[-10];

In the exact case you posted there's two other facts we could optimize 
on. Firstly, there's the fact that you have two accesses. That means the 
cases break down like this:
   a) a[5] = &a[-10] therefore the later run of a[5][20] will be UB
   b) a[5] = &a[-20] therefore the earlier run of a[5][10] was UB
   c) a[5] doesn't alias 'a'
but how sure are we about (a) and (b)? What if I arrange for a linker 
script that puts 'a' here and 10 pointer-sizes later puts another global 
variable there?

The second thing we have is an 'inbounds' qualifier on getelementptr. In 
C/C++ there are rules about not being allowed to even form pointers 
outside the range of an [object begin, object end + 1], but those rules 
don't exist in llvm ir except for the 'inbounds' attribute on 
getelementptr. An inbounds getelementptr means that the base pointer 
must be within the bounds (including a one-off-the-end pointer) of a 
concrete object, which means that (a[5]) can't be pointing to &a[-10], 
given that 'a' is only sizeof(double).

Nick



More information about the llvm-dev mailing list