Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -432,9 +432,7 @@ if (Len == 0) return Dst; // strncpy(x, y, 0) -> x - // Let strncpy handle the zero padding - if (Len > SrcLen + 1) - return nullptr; + Len = std::min(Len, SrcLen + 1); Type *PT = Callee->getFunctionType()->getParamType(0); // strncpy(x, s, c) -> memcpy(align 1 x, align 1 s, c) [s and c are constant] Index: test/Transforms/InstCombine/strncpy-1.ll =================================================================== --- test/Transforms/InstCombine/strncpy-1.ll +++ test/Transforms/InstCombine/strncpy-1.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the strncpy library call simplifier works correctly. ; ; RUN: opt < %s -instcombine -S | FileCheck %s @@ -17,8 +18,15 @@ define i32 @test_simplify1() { ; CHECK-LABEL: @test_simplify1( -; CHECK-NOT: call i8* @strncpy -; CHECK: call i32 @puts +; CHECK-NEXT: [[TARGET:%.*]] = alloca [1024 x i8], align 1 +; CHECK-NEXT: [[ARG1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[TARGET]], i32 0, i32 0 +; CHECK-NEXT: store i8 0, i8* [[ARG1]], align 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* nonnull align 1 [[ARG1]], i8* align 1 getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* nonnull align 1 [[ARG1]], i8 0, i32 42, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* nonnull align 1 [[ARG1]], i8 0, i32 42, i1 false) +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @puts(i8* nonnull [[ARG1]]) +; CHECK-NEXT: ret i32 0 +; %target = alloca [1024 x i8] %arg1 = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0 store i8 0, i8* %arg1 @@ -40,11 +48,13 @@ define void @test_simplify2() { ; CHECK-LABEL: @test_simplify2( +; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8 0, i32 32, i1 false) +; CHECK-NEXT: ret void +; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0 call i8* @strncpy(i8* %dst, i8* %src, i32 32) -; CHECK: call void @llvm.memset.p0i8.i32 ret void } @@ -52,44 +62,67 @@ define i8* @test_simplify3() { ; CHECK-LABEL: @test_simplify3( +; CHECK-NEXT: ret i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0) +; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 %ret = call i8* @strncpy(i8* %dst, i8* %src, i32 0) ret i8* %ret -; CHECK: ret i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0) } -; Check strncpy(x, s, c) -> memcpy(x, s, c, 1) [s and c are constant]. +; Check strncpy(x, s, c) -> memcpy(x, s, c, 1) [s and c are constant]. define void @test_simplify4() { ; CHECK-LABEL: @test_simplify4( +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6, i1 false) +; CHECK-NEXT: ret void +; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 call i8* @strncpy(i8* %dst, i8* %src, i32 6) -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i32 ret void } -; Check cases that shouldn't be simplified. - -define void @test_no_simplify1() { -; CHECK-LABEL: @test_no_simplify1( +; Check strncpy(x, s, c) -> memcpy(x, s, min(c, len(s)), 1) [s and c are constant]. +; Length: len(s) +define void @test_simplify5() { +; CHECK-LABEL: @test_simplify5( +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6, i1 false) +; CHECK-NEXT: ret void +; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 - %src = getelementptr [32 x i8], [32 x i8]* @b, i32 0, i32 0 + %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i8* @strncpy(i8* %dst, i8* %src, i32 32) -; CHECK: call i8* @strncpy + call i8* @strncpy(i8* %dst, i8* %src, i32 12) ret void } -define void @test_no_simplify2() { -; CHECK-LABEL: @test_no_simplify2( +; Check strncpy(x, s, c) -> memcpy(x, s, min(c, len(s)), 1) [s and c are constant]. +; Length: c +define void @test_simplify6() { +; CHECK-LABEL: @test_simplify6( +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* align 1 getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 5, i1 false) +; CHECK-NEXT: ret void +; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i8* @strncpy(i8* %dst, i8* %src, i32 8) -; CHECK: call i8* @strncpy + call i8* @strncpy(i8* %dst, i8* %src, i32 5) + ret void +} + +; Check cases that shouldn't be simplified. + +define void @test_no_simplify1() { +; CHECK-LABEL: @test_no_simplify1( +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @strncpy(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8], [32 x i8]* @b, i32 0, i32 0), i32 32) +; CHECK-NEXT: ret void +; + %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 + %src = getelementptr [32 x i8], [32 x i8]* @b, i32 0, i32 0 + + call i8* @strncpy(i8* %dst, i8* %src, i32 32) ret void }