From e2d4a45c6eb54e5e8c806c2d8ff55d19dadfbbcc Mon Sep 17 00:00:00 2001 From: David Bolvansky Date: Mon, 23 Sep 2019 18:20:01 +0000 Subject: [PATCH] [SLC] Convert some strndup calls to strdup calls Summary: Motivation: - If we can fold it to strdup, we should (strndup does more things than strdup). - Annotation mechanism. (Works for strdup well). strdup and strndup are part of C 20 (currently posix fns), so we should optimize them. Reviewers: efriedma, jdoerfert Reviewed By: jdoerfert Subscribers: lebedev.ri, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67679 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@372636 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Transforms/Utils/BuildLibCalls.h | 5 ++ .../llvm/Transforms/Utils/SimplifyLibCalls.h | 1 + .../InstCombine/InstCombineCalls.cpp | 6 +- lib/Transforms/Utils/BuildLibCalls.cpp | 6 ++ lib/Transforms/Utils/SimplifyLibCalls.cpp | 15 +++++ test/Transforms/InstCombine/objsize.ll | 14 ++-- test/Transforms/InstCombine/strndup.ll | 67 +++++++++++++++++++ 7 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 test/Transforms/InstCombine/strndup.ll diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index 726723ae23b..3d15b2a7bf2 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -50,6 +50,11 @@ namespace llvm { Value *emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); + /// Emit a call to the strdup function to the builder, for the specified + /// pointer. Ptr is required to be some pointer type, and the return value has + /// 'i8*' type. + Value *emitStrDup(Value *Ptr, IRBuilder<> &B, const TargetLibraryInfo *TLI); + /// Emit a call to the strnlen function to the builder, for the specified /// pointer. Ptr is required to be some pointer type, MaxLen must be of size_t /// type, and the return value has 'intptr_t' type. diff --git a/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/include/llvm/Transforms/Utils/SimplifyLibCalls.h index d03bf1405b7..b722c47c1ca 100644 --- a/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -160,6 +160,7 @@ private: Value *optimizeStrRChr(CallInst *CI, IRBuilder<> &B); Value *optimizeStrCmp(CallInst *CI, IRBuilder<> &B); Value *optimizeStrNCmp(CallInst *CI, IRBuilder<> &B); + Value *optimizeStrNDup(CallInst *CI, IRBuilder<> &B); Value *optimizeStrCpy(CallInst *CI, IRBuilder<> &B); Value *optimizeStpCpy(CallInst *CI, IRBuilder<> &B); Value *optimizeStrNCpy(CallInst *CI, IRBuilder<> &B); diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 90438189f89..bf9917dbab0 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4222,9 +4222,6 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) { if (isAllocationFn(&Call, &TLI)) annotateAnyAllocSite(Call, &TLI); - if (isAllocLikeFn(&Call, &TLI)) - return visitAllocSite(Call); - bool Changed = false; // Mark any parameters that are known to be non-null with the nonnull @@ -4355,6 +4352,9 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) { if (I) return eraseInstFromFunction(*I); } + if (isAllocLikeFn(&Call, &TLI)) + return visitAllocSite(Call); + return Changed ? &Call : nullptr; } diff --git a/lib/Transforms/Utils/BuildLibCalls.cpp b/lib/Transforms/Utils/BuildLibCalls.cpp index ea1fbc9e73b..e8ce3f92749 100644 --- a/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/lib/Transforms/Utils/BuildLibCalls.cpp @@ -842,6 +842,12 @@ Value *llvm::emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, B.getInt8PtrTy(), castToCStr(Ptr, B), B, TLI); } +Value *llvm::emitStrDup(Value *Ptr, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strdup, B.getInt8PtrTy(), B.getInt8PtrTy(), + castToCStr(Ptr, B), B, TLI); +} + Value *llvm::emitStrChr(Value *Ptr, char C, IRBuilder<> &B, const TargetLibraryInfo *TLI) { Type *I8Ptr = B.getInt8PtrTy(); diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index b003a720fbd..813816e82d2 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -531,6 +531,19 @@ Value *LibCallSimplifier::optimizeStrNCmp(CallInst *CI, IRBuilder<> &B) { return nullptr; } +Value *LibCallSimplifier::optimizeStrNDup(CallInst *CI, IRBuilder<> &B) { + Value *Src = CI->getArgOperand(0); + ConstantInt *Size = dyn_cast(CI->getArgOperand(1)); + uint64_t SrcLen = GetStringLength(Src); + if (SrcLen && Size) { + annotateDereferenceableBytes(CI, 0, SrcLen); + if (SrcLen <= Size->getZExtValue() + 1) + return emitStrDup(Src, B, TLI); + } + + return nullptr; +} + Value *LibCallSimplifier::optimizeStrCpy(CallInst *CI, IRBuilder<> &B) { Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1); if (Dst == Src) // strcpy(x,x) -> x @@ -2713,6 +2726,8 @@ Value *LibCallSimplifier::optimizeStringMemoryLibCall(CallInst *CI, return optimizeStrLen(CI, Builder); case LibFunc_strpbrk: return optimizeStrPBrk(CI, Builder); + case LibFunc_strndup: + return optimizeStrNDup(CI, Builder); case LibFunc_strtol: case LibFunc_strtod: case LibFunc_strtof: diff --git a/test/Transforms/InstCombine/objsize.ll b/test/Transforms/InstCombine/objsize.ll index 590fcd60f48..f00f5970af1 100644 --- a/test/Transforms/InstCombine/objsize.ll +++ b/test/Transforms/InstCombine/objsize.ll @@ -239,7 +239,7 @@ define i32 @test9(i8** %esc) { define i32 @test10(i8** %esc) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 3) #0 +; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strndup(i8* dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 3) #0 ; CHECK-NEXT: store i8* [[CALL]], i8** [[ESC:%.*]], align 8 ; CHECK-NEXT: ret i32 4 ; @@ -251,8 +251,8 @@ define i32 @test10(i8** %esc) { define i32 @test11(i8** %esc) { ; CHECK-LABEL: @test11( -; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 7) #0 -; CHECK-NEXT: store i8* [[CALL]], i8** [[ESC:%.*]], align 8 +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(8) i8* @strdup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0)) +; CHECK-NEXT: store i8* [[STRDUP]], i8** [[ESC:%.*]], align 8 ; CHECK-NEXT: ret i32 8 ; %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 7) nounwind @@ -263,8 +263,8 @@ define i32 @test11(i8** %esc) { define i32 @test12(i8** %esc) { ; CHECK-LABEL: @test12( -; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 8) #0 -; CHECK-NEXT: store i8* [[CALL]], i8** [[ESC:%.*]], align 8 +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(8) i8* @strdup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0)) +; CHECK-NEXT: store i8* [[STRDUP]], i8** [[ESC:%.*]], align 8 ; CHECK-NEXT: ret i32 8 ; %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 8) nounwind @@ -275,8 +275,8 @@ define i32 @test12(i8** %esc) { define i32 @test13(i8** %esc) { ; CHECK-LABEL: @test13( -; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 57) #0 -; CHECK-NEXT: store i8* [[CALL]], i8** [[ESC:%.*]], align 8 +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(8) i8* @strdup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0)) +; CHECK-NEXT: store i8* [[STRDUP]], i8** [[ESC:%.*]], align 8 ; CHECK-NEXT: ret i32 8 ; %call = tail call i8* @strndup(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i32 57) nounwind diff --git a/test/Transforms/InstCombine/strndup.ll b/test/Transforms/InstCombine/strndup.ll new file mode 100644 index 00000000000..0861535e9dd --- /dev/null +++ b/test/Transforms/InstCombine/strndup.ll @@ -0,0 +1,67 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +@hello = constant [6 x i8] c"hello\00" +@null = constant [1 x i8] zeroinitializer + +declare i8* @strndup(i8*, i32) + +define i8* @test1() { +; CHECK-LABEL: @test1( +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(1) i8* @strdup(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @null, i64 0, i64 0)) +; CHECK-NEXT: ret i8* [[STRDUP]] +; + %src = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 0) + ret i8* %ret +} + +define i8* @test2() { +; CHECK-LABEL: @test2( +; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 4) +; CHECK-NEXT: ret i8* [[RET]] +; + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 4) + ret i8* %ret +} + +define i8* @test3() { +; CHECK-LABEL: @test3( +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0)) +; CHECK-NEXT: ret i8* [[STRDUP]] +; + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 5) + ret i8* %ret +} + +define i8* @test4() { +; CHECK-LABEL: @test4( +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0)) +; CHECK-NEXT: ret i8* [[STRDUP]] +; + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 6) + ret i8* %ret +} + +define i8* @test5() { +; CHECK-LABEL: @test5( +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(6) i8* @strdup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0)) +; CHECK-NEXT: ret i8* [[STRDUP]] +; + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 7) + ret i8* %ret +} + +define i8* @test6(i32 %n) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 [[N:%.*]]) +; CHECK-NEXT: ret i8* [[RET]] +; + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 + %ret = call i8* @strndup(i8* %src, i32 %n) + ret i8* %ret +} -- 2.50.1