We've got an upstream rust-lang/rust bug at https://github.com/rust-lang/rust/issues/40165 which is exhibiting some odd behavior! I've managed to reduce it to a small snippet of IR which optimizes oddly: @s = internal constant [1 x i8] [i8 0], align 1 define i8* @foo() { entry-block: %0 = tail call i8* @memchr(i8* getelementptr ([1 x i8], [1 x i8]* @s, i64 0, i64 0), i32 0, i64 1) ret i8* %0 } declare i8* @memchr(i8*, i32, i64) When optimized,that entire function optimizes to returning null, but I'd expect it to return @s itself (as the first byte is zero)
Some local discussion on IRC points out that https://github.com/llvm-mirror/llvm/blob/003f1a56c5e496c7c195122de24b1272d32866a0/lib/Analysis/ValueTracking.cpp#L3098-L3099 may be related here?
I believe the minimal diff for fixing this to be: - if (GV->getInitializer()->isNullValue()) { + if (GV->getInitializer()->isNullValue() && TrimAtNul) { This will remove the ability to optimize certain libcalls on all-zero static buffers, but at least it won't be incorrect. The ideal fix would probably be to allocate an all-zero string buffer if TrimAtNul is false.
Checking https://godbolt.org/g/QroaoK against various versions of clang suggests this bug has been around since LLVM 3.7, and is not present in other compilers.
I haven't stepped throught with a debugger, but you may want to confirm that SimplifyLibCall doesn't do anything hazy with memchr() Value *LibCallSimplifier::optimizeMemChr(CallInst *CI, IRBuilder<> &B)
You may want to try this patch (at least as stopgap solution). diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index ec33679..5553d5c 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -666,6 +666,10 @@ Value *LibCallSimplifier::optimizeMemChr(CallInst *CI, IRBuilder<> &B) { // return null if we don't find the char. Str = Str.substr(0, LenC->getZExtValue()); + // memchr("", 0, y) -> "" + if (Str.empty() && CharC->isNullValue()) + return CI->getArgOperand(0); + // If the char is variable but the input str and length are not we can turn // this memchr call into a simple bit field test. Of course this only works // when the return value is only checked against null.
IMO this should be fixed (even as an workaround) in getConstantStringInfo (see my mini-diff above), because memchr is unlikely to be the only affected function.
For the record: Looks like Eli found the (existing) bug while reading my review at https://reviews.llvm.org/D32839#inline-284908 The latest version of that patch fixes this issue as a side effect of some refactoring.
Fixed by r303461