[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