[llvm-dev] load instruction erroneously removed by GVN

Mikael Holmén via llvm-dev llvm-dev at lists.llvm.org
Fri Aug 7 04:15:54 PDT 2015


Hi,

I'm having a problem with GVN removing a load instruction that I think 
is needed.

Dump before GVN:

*** IR Dump Before Global Value Numbering ***
; Function Attrs: minsize optsize
define i16 @TEST__MAIN(i16 %argc.13.par, i16** %argv.14.par) #0 {
   %buf.17 = alloca [10 x i16], align 1
   %_tmp30 = getelementptr inbounds [10 x i16], [10 x i16]* %buf.17, i16 
0, i16 0, !dbg !22
   call fastcc void @format_long(i16* %_tmp30, i16 10, i32 10), !dbg !22
   %_tmp32 = getelementptr [10 x i16], [10 x i16]* %buf.17, i16 0, i16 
0, !dbg !24
   %_tmp33 = load i16, i16* %_tmp32, align 1, !dbg !24
   call fastcc void @check_i(i16 2, i16 %_tmp33, i16 48), !dbg !24
   ret i16 0, !dbg !25
}


GVN debug printouts:

GVN iteration: 0
GVN removed:   %_tmp32 = getelementptr [10 x i16], [10 x i16]* %buf.17, 
i16 0, i16 0, !dbg !16
GVN removed:   %_tmp33 = load i16, i16* %_tmp30, align 1, !dbg !16
GVN iteration: 1

And then the code aftern GVN:

*** IR Dump After Global Value Numbering ***
; Function Attrs: minsize optsize
define i16 @TEST__MAIN(i16 %argc.13.par, i16** %argv.14.par) #0 {
   %buf.17 = alloca [10 x i16], align 1
   %_tmp30 = getelementptr inbounds [10 x i16], [10 x i16]* %buf.17, i16 
0, i16 0, !dbg !22
   call fastcc void @format_long(i16* %_tmp30, i16 10, i32 10), !dbg !22
   call fastcc void @check_i(i16 2, i16 undef, i16 48), !dbg !24
   ret i16 0, !dbg !25
}

So GVN has deemed

   %_tmp33 = load i16, i16* %_tmp32, align 1, !dbg !24

useless, and removed it, replacing %_tmp33 with undef.

While examining the load, processLoad does

   MemDepResult Dep = MD->getDependency(L);
   [...]
   Instruction *DepInst = Dep.getInst();
   [...]
   // If this load really doesn't depend on anything, then we must be 
loading an
   // undef value.  This can happen when loading for a fresh allocation 
with no
   // intervening stores, for example.
   if (isa<AllocaInst>(DepInst) || isMallocLikeFn(DepInst, TLI)) {
     L->replaceAllUsesWith(UndefValue::get(L->getType()));
     markInstructionForDeletion(L);
     ++NumGVNLoad;
     return true;
   }

The Dep points to the

   %buf.17 = alloca [10 x i16], align 1

instruction, so of course GVN thinks the load is reading uninitialized 
memory and thus can be replaced with undef.

But between the load and the alloca there is also

   call fastcc void @format_long(i16* %_tmp30, i16 10, i32 10), !dbg !22

which will use %_tmp30 to write in the alloca'd buffer.

Shoulnd't MemoryDependenceAnalysis::getDependency rather return the call?

MemoryDependenceAnalysis::getDependency uses 
MemoryDependenceAnalysis::getPointerDependencyFrom, which does the 
following analysis at the end:

     // See if this instruction (e.g. a call or vaarg) mod/ref's the 
pointer.
     AliasAnalysis::ModRefResult MR = AA->getModRefInfo(Inst, MemLoc);
     // If necessary, perform additional analysis.
     if (MR == AliasAnalysis::ModRef)
       MR = AA->callCapturesBefore(Inst, MemLoc, DT);
     switch (MR) {
     case AliasAnalysis::NoModRef:
       // If the call has no effect on the queried pointer, just ignore it.
       continue;
     case AliasAnalysis::Mod:
       return MemDepResult::getClobber(Inst);
     case AliasAnalysis::Ref:
       // If the call is known to never store to the pointer, and if 
this is a
       // load query, we can safely ignore it (scan past it).
       if (isLoad)
         continue;
     default:
       // Otherwise, there is a potential dependence.  Return a clobber.
       return MemDepResult::getClobber(Inst);
     }

In my case, when analysing the call instruction, MR is first set to 
ModRef by AA->getModRefInfo(Inst, MemLoc);, but then it is reset to 
NoModRef by MR = AA->callCapturesBefore(Inst, MemLoc, DT); and thus it 
fails to recognize the dependency towards the call.

Note that the function format_long does not capture the pointer, but it 
does use it to write at the pointed address.

Anyone here knows how this should work?

Thanks in advance,
Mikael


More information about the llvm-dev mailing list