LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 32124 - memchr("", 0, 1) optimized incorrectly
Summary: memchr("", 0, 1) optimized incorrectly
Status: RESOLVED FIXED
Alias: None
Product: libraries
Classification: Unclassified
Component: Scalar Optimizations (show other bugs)
Version: 4.0
Hardware: PC Windows NT
: P enhancement
Assignee: Matthias Braun
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-02 16:34 PST by Alex Crichton
Modified: 2017-05-19 15:48 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Crichton 2017-03-02 16:34:27 PST
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)
Comment 1 Alex Crichton 2017-03-02 16:35:56 PST
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?
Comment 2 edy.burt 2017-03-02 16:43:40 PST
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.
Comment 3 edy.burt 2017-03-02 16:50:59 PST
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.
Comment 4 Davide Italiano 2017-03-02 16:52:10 PST
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)
Comment 5 Davide Italiano 2017-03-03 18:58:03 PST
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.
Comment 6 edy.burt 2017-03-04 01:16:45 PST
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.
Comment 7 Matthias Braun 2017-05-05 13:02:25 PDT
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.
Comment 8 Matthias Braun 2017-05-19 15:48:41 PDT
Fixed by r303461