diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -514,6 +514,8 @@ NewCI->setAttributes(CI->getAttributes()); NewCI->removeAttributes(AttributeList::ReturnIndex, AttributeFuncs::typeIncompatible(NewCI->getType())); + if (CI->isTailCall()) + NewCI->setTailCall(); return Dst; } @@ -543,6 +545,8 @@ NewCI->setAttributes(CI->getAttributes()); NewCI->removeAttributes(AttributeList::ReturnIndex, AttributeFuncs::typeIncompatible(NewCI->getType())); + if (CI->isTailCall()) + NewCI->setTailCall(); return DstEnd; } @@ -3220,6 +3224,8 @@ NewCI->setAttributes(CI->getAttributes()); NewCI->removeAttributes(AttributeList::ReturnIndex, AttributeFuncs::typeIncompatible(NewCI->getType())); + if (CI->isTailCall()) + NewCI->setTailCall(); return CI->getArgOperand(0); } return nullptr; @@ -3248,6 +3254,8 @@ NewCI->setAttributes(CI->getAttributes()); NewCI->removeAttributes(AttributeList::ReturnIndex, AttributeFuncs::typeIncompatible(NewCI->getType())); + if (CI->isTailCall()) + NewCI->setTailCall(); return CI->getArgOperand(0); } return nullptr; @@ -3288,10 +3296,15 @@ // TODO: It might be nice to get a maximum length out of the possible // string lengths for varying. if (isFortifiedCallFoldable(CI, 2, None, 1)) { + Value *Ret; if (Func == LibFunc_strcpy_chk) - return emitStrCpy(Dst, Src, B, TLI); + Ret = emitStrCpy(Dst, Src, B, TLI); else - return emitStpCpy(Dst, Src, B, TLI); + Ret = emitStpCpy(Dst, Src, B, TLI); + if (CI->isTailCall()) + if (auto *NewCI = cast_or_null(Ret)) + NewCI->setTailCall(); + return Ret; } if (OnlyLowerUnknownSize) @@ -3307,6 +3320,9 @@ Type *SizeTTy = DL.getIntPtrType(CI->getContext()); Value *LenV = ConstantInt::get(SizeTTy, Len); Value *Ret = emitMemCpyChk(Dst, Src, LenV, ObjSize, B, DL, TLI); + if (CI->isTailCall()) + if (auto *NewCI = cast_or_null(Ret)) + NewCI->setTailCall(); // If the function was an __stpcpy_chk, and we were able to fold it into // a __memcpy_chk, we still need to return the correct end pointer. if (Ret && Func == LibFunc_stpcpy_chk) @@ -3455,45 +3471,67 @@ if (!ignoreCallingConv(Func) && !IsCallingConvC) return nullptr; + Value *New; switch (Func) { case LibFunc_memcpy_chk: - return optimizeMemCpyChk(CI, Builder); + New = optimizeMemCpyChk(CI, Builder); + break; case LibFunc_mempcpy_chk: - return optimizeMemPCpyChk(CI, Builder); + New = optimizeMemPCpyChk(CI, Builder); + break; case LibFunc_memmove_chk: - return optimizeMemMoveChk(CI, Builder); + New = optimizeMemMoveChk(CI, Builder); + break; case LibFunc_memset_chk: - return optimizeMemSetChk(CI, Builder); + New = optimizeMemSetChk(CI, Builder); + break; case LibFunc_stpcpy_chk: case LibFunc_strcpy_chk: - return optimizeStrpCpyChk(CI, Builder, Func); + New = optimizeStrpCpyChk(CI, Builder, Func); + break; case LibFunc_strlen_chk: - return optimizeStrLenChk(CI, Builder); + New = optimizeStrLenChk(CI, Builder); + break; case LibFunc_stpncpy_chk: case LibFunc_strncpy_chk: - return optimizeStrpNCpyChk(CI, Builder, Func); + New = optimizeStrpNCpyChk(CI, Builder, Func); + break; case LibFunc_memccpy_chk: - return optimizeMemCCpyChk(CI, Builder); + New = optimizeMemCCpyChk(CI, Builder); + break; case LibFunc_snprintf_chk: - return optimizeSNPrintfChk(CI, Builder); + New = optimizeSNPrintfChk(CI, Builder); + break; case LibFunc_sprintf_chk: - return optimizeSPrintfChk(CI, Builder); + New = optimizeSPrintfChk(CI, Builder); + break; case LibFunc_strcat_chk: - return optimizeStrCatChk(CI, Builder); + New = optimizeStrCatChk(CI, Builder); + break; case LibFunc_strlcat_chk: - return optimizeStrLCat(CI, Builder); + New = optimizeStrLCat(CI, Builder); + break; case LibFunc_strncat_chk: - return optimizeStrNCatChk(CI, Builder); + New = optimizeStrNCatChk(CI, Builder); + break; case LibFunc_strlcpy_chk: - return optimizeStrLCpyChk(CI, Builder); + New = optimizeStrLCpyChk(CI, Builder); + break; case LibFunc_vsnprintf_chk: - return optimizeVSNPrintfChk(CI, Builder); + New = optimizeVSNPrintfChk(CI, Builder); + break; case LibFunc_vsprintf_chk: - return optimizeVSPrintfChk(CI, Builder); - default: + New = optimizeVSPrintfChk(CI, Builder); break; + default: + return nullptr; } - return nullptr; + + if (auto *SimplifiedCI = dyn_cast_or_null(New)) + if (CI->isTailCall() && !SimplifiedCI->isTailCall()) + SimplifiedCI->setTailCall(); + + return New; } FortifiedLibCallSimplifier::FortifiedLibCallSimplifier( diff --git a/llvm/test/CodeGen/X86/memset-nonzero.ll b/llvm/test/CodeGen/X86/memset-nonzero.ll --- a/llvm/test/CodeGen/X86/memset-nonzero.ll +++ b/llvm/test/CodeGen/X86/memset-nonzero.ll @@ -196,14 +196,9 @@ define void @memset_256_nonzero_bytes(i8* %x) { ; SSE-LABEL: memset_256_nonzero_bytes: ; SSE: # %bb.0: -; SSE-NEXT: pushq %rax -; SSE-NEXT: .cfi_def_cfa_offset 16 ; SSE-NEXT: movl $256, %edx # imm = 0x100 ; SSE-NEXT: movl $42, %esi -; SSE-NEXT: callq memset@PLT -; SSE-NEXT: popq %rax -; SSE-NEXT: .cfi_def_cfa_offset 8 -; SSE-NEXT: retq +; SSE-NEXT: jmp memset@PLT # TAILCALL ; ; SSE2FAST-LABEL: memset_256_nonzero_bytes: ; SSE2FAST: # %bb.0: diff --git a/llvm/test/Transforms/InstCombine/fortify-folding.ll b/llvm/test/Transforms/InstCombine/fortify-folding.ll --- a/llvm/test/Transforms/InstCombine/fortify-folding.ll +++ b/llvm/test/Transforms/InstCombine/fortify-folding.ll @@ -31,6 +31,18 @@ ret i8* %ret } +define i8* @test_memccpy_tail() { +; CHECK-LABEL: @test_memccpy_tail( +; CHECK-NEXT: [[MEMCCPY:%.*]] = tail call i8* @memccpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i32 0, i64 60) +; CHECK-NEXT: ret i8* [[MEMCCPY]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i8* @__memccpy_chk(i8* %dst, i8* %src, i32 0, i64 60, i64 -1) + ret i8* %ret +} + +; TODO: test tail call define i8* @test_mempcpy() { ; CHECK-LABEL: @test_mempcpy( ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(15) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* noundef nonnull align 1 dereferenceable(15) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 15, i1 false) @@ -77,6 +89,17 @@ ret i32 %ret } +define i32 @test_snprintf_tail() { +; CHECK-LABEL: @test_snprintf_tail( +; CHECK-NEXT: [[SNPRINTF:%.*]] = tail call i32 (i8*, i64, i8*, ...) @snprintf(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 60, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) +; CHECK-NEXT: ret i32 [[SNPRINTF]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk(i8* %dst, i64 60, i32 0, i64 -1, i8* %fmt) + ret i32 %ret +} + define i32 @test_sprintf() { ; CHECK-LABEL: @test_sprintf( ; CHECK-NEXT: [[SPRINTF:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) @@ -101,6 +124,17 @@ ret i32 %ret } +define i32 @test_sprintf_tail() { +; CHECK-LABEL: @test_sprintf_tail( +; CHECK-NEXT: [[SPRINTF:%.*]] = tail call i32 (i8*, i8*, ...) @sprintf(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) +; CHECK-NEXT: ret i32 [[SPRINTF]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* %dst, i32 0, i64 -1, i8* %fmt) + ret i32 %ret +} + define i8* @test_strcat() { ; CHECK-LABEL: @test_strcat( ; CHECK-NEXT: [[STRCAT:%.*]] = call i8* @strcat(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) @@ -123,6 +157,17 @@ ret i8* %ret } +define i8* @test_strcat_tail() { +; CHECK-LABEL: @test_strcat_tail( +; CHECK-NEXT: [[STRCAT:%.*]] = tail call i8* @strcat(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i8* @__strcat_chk(i8* %dst, i8* %src, i64 -1) + ret i8* %ret +} + define i64 @test_strlcat() { ; CHECK-LABEL: @test_strlcat( ; CHECK-NEXT: [[STRLCAT:%.*]] = call i64 @strlcat(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) @@ -145,6 +190,17 @@ ret i64 %ret } +define i64 @test_strlcat_tail() { +; CHECK-LABEL: @test_strlcat_tail( +; CHECK-NEXT: [[STRLCAT:%.*]] = tail call i64 @strlcat(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) +; CHECK-NEXT: ret i64 [[STRLCAT]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i64 @__strlcat_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i64 %ret +} + define i8* @test_strncat() { ; CHECK-LABEL: @test_strncat( ; CHECK-NEXT: [[STRNCAT:%.*]] = call i8* @strncat(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) @@ -167,6 +223,17 @@ ret i8* %ret } +define i8* @test_strncat_tail() { +; CHECK-LABEL: @test_strncat_tail( +; CHECK-NEXT: [[STRNCAT:%.*]] = tail call i8* @strncat(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i8* @__strncat_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i8* %ret +} + define i64 @test_strlcpy() { ; CHECK-LABEL: @test_strlcpy( ; CHECK-NEXT: [[STRLCPY:%.*]] = call i64 @strlcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) @@ -189,6 +256,17 @@ ret i64 %ret } +define i64 @test_strlcpy_tail() { +; CHECK-LABEL: @test_strlcpy_tail( +; CHECK-NEXT: [[STRLCPY:%.*]] = tail call i64 @strlcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) +; CHECK-NEXT: ret i64 [[STRLCPY]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i64 @__strlcpy_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i64 %ret +} + define i32 @test_vsnprintf() { ; CHECK-LABEL: @test_vsnprintf( ; CHECK-NEXT: [[VSNPRINTF:%.*]] = call i32 @vsnprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 4, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) @@ -215,6 +293,18 @@ ret i32 %ret } +define i32 @test_vsnprintf_tail() { +; CHECK-LABEL: @test_vsnprintf_tail( +; CHECK-NEXT: [[VSNPRINTF:%.*]] = tail call i32 @vsnprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 4, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) +; CHECK-NEXT: ret i32 [[VSNPRINTF]] +; + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i32 @__vsnprintf_chk(i8* %dst, i64 4, i32 0, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + define i32 @test_vsprintf() { ; CHECK-LABEL: @test_vsprintf( ; CHECK-NEXT: [[VSPRINTF:%.*]] = call i32 @vsprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) @@ -241,6 +331,18 @@ ret i32 %ret } +define i32 @test_vsprintf_tail() { +; CHECK-LABEL: @test_vsprintf_tail( +; CHECK-NEXT: [[VSPRINTF:%.*]] = tail call i32 @vsprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) +; CHECK-NEXT: ret i32 [[VSPRINTF]] +; + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = tail call i32 @__vsprintf_chk(i8* %dst, i32 0, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + declare i8* @__mempcpy_chk(i8*, i8*, i64, i64) declare i8* @__memccpy_chk(i8*, i8*, i32, i64, i64) declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...) diff --git a/llvm/test/Transforms/InstCombine/memcpy_chk-1.ll b/llvm/test/Transforms/InstCombine/memcpy_chk-1.ll --- a/llvm/test/Transforms/InstCombine/memcpy_chk-1.ll +++ b/llvm/test/Transforms/InstCombine/memcpy_chk-1.ll @@ -38,6 +38,18 @@ ret i8* %ret } +; Same as test_simplify1 but with a tail call rather than vanilla call. +define i8* @test_simplify3() { +; CHECK-LABEL: @test_simplify3( +; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(1824) bitcast (%struct.T1* @t1 to i8*), i8* noundef nonnull align 4 dereferenceable(1824) bitcast (%struct.T2* @t2 to i8*), i64 1824, i1 false) +; CHECK-NEXT: ret i8* bitcast (%struct.T1* @t1 to i8*) +; + %dst = bitcast %struct.T1* @t1 to i8* + %src = bitcast %struct.T2* @t2 to i8* + %ret = tail call i8* @__memcpy_chk(i8* %dst, i8* %src, i64 1824, i64 1824) + ret i8* %ret +} + ; Check cases where dstlen < len. define i8* @test_no_simplify1() { diff --git a/llvm/test/Transforms/InstCombine/memset_chk-1.ll b/llvm/test/Transforms/InstCombine/memset_chk-1.ll --- a/llvm/test/Transforms/InstCombine/memset_chk-1.ll +++ b/llvm/test/Transforms/InstCombine/memset_chk-1.ll @@ -45,6 +45,18 @@ ret i8* %ret } +; Same as @test_simplify1 with tail call. +define i8* @test_simplify4() { +; CHECK-LABEL: @test_simplify4( +; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(1824) bitcast (%struct.T* @t to i8*), i8 0, i64 1824, i1 false) +; CHECK-NEXT: ret i8* bitcast (%struct.T* @t to i8*) +; + %dst = bitcast %struct.T* @t to i8* + + %ret = tail call i8* @__memset_chk(i8* %dst, i32 0, i64 1824, i64 1824) + ret i8* %ret +} + ; Check cases where dstlen < len. define i8* @test_no_simplify1() { diff --git a/llvm/test/Transforms/InstCombine/stpcpy_chk-1.ll b/llvm/test/Transforms/InstCombine/stpcpy_chk-1.ll --- a/llvm/test/Transforms/InstCombine/stpcpy_chk-1.ll +++ b/llvm/test/Transforms/InstCombine/stpcpy_chk-1.ll @@ -48,6 +48,18 @@ ret i8* %ret } +define i8* @test_simplify1_tail() { +; CHECK-LABEL: @test_simplify1_tail( +; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 11) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0 + + %ret = tail call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 60) + ret i8* %ret +} + ; Check cases where there are no string constants. define i8* @test_simplify4() { @@ -62,6 +74,18 @@ ret i8* %ret } +define i8* @test_simplify4_tail() { +; CHECK-LABEL: @test_simplify4_tail( +; CHECK-NEXT: [[STPCPY:%.*]] = tail call i8* @stpcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0)) +; CHECK-NEXT: ret i8* [[STPCPY]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + + %ret = tail call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 -1) + ret i8* %ret +} + ; Check case where the string length is not constant. define i8* @test_simplify5() { @@ -93,6 +117,20 @@ ret i8* %ret } +; Check cases where there are no string constants, and is a tail call. + +define i8* @test_simplify7() { +; CHECK-LABEL: @test_simplify7( +; CHECK-NEXT: [[STPCPY:%.*]] = tail call i8* @stpcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0)) +; CHECK-NEXT: ret i8* [[STPCPY]] +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + + %ret = tail call i8* @__stpcpy_chk(i8* %dst, i8* %src, i32 -1) + ret i8* %ret +} + ; Check case where slen < strlen (src). define i8* @test_no_simplify1() { diff --git a/llvm/test/Transforms/InstCombine/strcpy_chk-1.ll b/llvm/test/Transforms/InstCombine/strcpy_chk-1.ll --- a/llvm/test/Transforms/InstCombine/strcpy_chk-1.ll +++ b/llvm/test/Transforms/InstCombine/strcpy_chk-1.ll @@ -24,6 +24,18 @@ ret i8* %ret } +define i8* @test_simplify1_tail() { +; CHECK-LABEL: @test_simplify1_tail( +; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [12 x i8], [12 x i8]* @.str, i32 0, i32 0 + + %ret = tail call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 60) + ret i8* %ret +} + define i8* @test_simplify2() { ; CHECK-LABEL: @test_simplify2( ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* noundef nonnull align 1 dereferenceable(12) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 12, i1 false) @@ -62,6 +74,18 @@ ret i8* %ret } +define i8* @test_simplify4_tail() { +; CHECK-LABEL: @test_simplify4_tail( +; CHECK-NEXT: [[STRCPY:%.*]] = tail call i8* @strcpy(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0)) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + + %ret = tail call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1) + ret i8* %ret +} + ; Check case where the string length is not constant. define i8* @test_simplify5() { @@ -93,6 +117,20 @@ ret i8* %ret } +; Check cases where there are no string constants, and is a tail call. + +define i8* @test_simplify7() { +; CHECK-LABEL: @test_simplify7( +; CHECK-NEXT: [[STRCPY:%.*]] = tail call i8* @strcpy(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0)) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + + %ret = tail call i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1) + ret i8* %ret +} + ; Check case where slen < strlen (src). define i8* @test_no_simplify1() {