Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -150,6 +150,22 @@ return true; } +static bool canTransformToMemCmp(CallInst *CI, Value *Str, uint64_t Len, + unsigned CharSize = 8) { + if (!isOnlyUsedInZeroEqualityComparison(CI)) + return false; + + auto *GEP = dyn_cast(Str); + if (!GEP) + return false; + + uint64_t ArrSize = + cast(GEP->getSourceElementType())->getNumElements(); + if (ArrSize <= Len) + return false; + return true; +} + //===----------------------------------------------------------------------===// // String and Memory Library Call Optimizations //===----------------------------------------------------------------------===// @@ -322,6 +338,22 @@ B, DL, TLI); } + // strcmp to memcmp + uint64_t Len = 0; + if (!HasStr1 && !HasStr2) { + return nullptr; + } else if (!HasStr1 && HasStr2) { + Len = Len2; + } else if (HasStr1 && !HasStr2) { + std::swap(Str1P, Str2P); + Len = Len1; + } + + if (canTransformToMemCmp(CI, Str1P, Len)) + return emitMemCmp(Str1P, Str2P, + ConstantInt::get(DL.getIntPtrType(CI->getContext()), Len), + B, DL, TLI); + return nullptr; } @@ -361,6 +393,16 @@ if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType()); + // strncmp to memcmp + if (!HasStr1 && !HasStr2) { + return nullptr; + } else if (HasStr1 && !HasStr2) { + std::swap(Str1P, Str2P); + } + + if (canTransformToMemCmp(CI, Str1P, Length)) + return emitMemCmp(Str1P, Str2P, CI->getArgOperand(2), B, DL, TLI); + return nullptr; } Index: test/Transforms/InstCombine/strcmp-memcmp.ll =================================================================== --- test/Transforms/InstCombine/strcmp-memcmp.ll +++ test/Transforms/InstCombine/strcmp-memcmp.ll @@ -0,0 +1,536 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +@strcmp_memcmp_bad8.buf = private unnamed_addr constant [4 x i8] c"key\00", align 1 + +define i32 @strcmp_memcmp() { +; CHECK-LABEL: @strcmp_memcmp( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare i32 @strcmp(i8* nocapture, i8* nocapture) +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +define i32 @strcmp_memcmp2() { +; CHECK-LABEL: @strcmp_memcmp2( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +define i32 @strcmp_memcmp3() { +; CHECK-LABEL: @strcmp_memcmp3( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp ne i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +define i32 @strcmp_memcmp4() { +; CHECK-LABEL: @strcmp_memcmp4( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp ne i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +define i32 @strcmp_memcmp5() { +; CHECK-LABEL: @strcmp_memcmp5( +; CHECK-NEXT: [[BUF:%.*]] = alloca [5 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [5 x i8], [5 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 5, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 5, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [5 x i8], align 1 + %string = getelementptr inbounds [5 x i8], [5 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 5, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 5, i8* nonnull %string) + ret i32 %conv +} + +define i32 @strncmp_memcmp() { +; CHECK-LABEL: @strncmp_memcmp( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 2) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 2) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +declare i32 @strncmp(i8* nocapture, i8* nocapture, i64) local_unnamed_addr + +define i32 @strncmp_memcmp2() { +; CHECK-LABEL: @strncmp_memcmp2( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 2) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 2) + %cmp = icmp ne i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +define i32 @strncmp_memcmp3() { +; CHECK-LABEL: @strncmp_memcmp3( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 11) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 11) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp4() { +; CHECK-LABEL: @strncmp_memcmp4( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp5() { +; CHECK-LABEL: @strncmp_memcmp5( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp6() { +; CHECK-LABEL: @strncmp_memcmp6( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 5) + %cmp = icmp ne i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp7() { +; CHECK-LABEL: @strncmp_memcmp7( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 4) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp8() { +; CHECK-LABEL: @strncmp_memcmp8( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 3) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[MEMCMP]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %memcmp = call i32 @memcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i64 3) + %cmp = icmp eq i32 %memcmp, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +; Negative tests +define i32 @strcmp_memcmp_bad() { +; CHECK-LABEL: @strcmp_memcmp_bad( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) + %cmp = icmp sgt i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad2() { +; CHECK-LABEL: @strcmp_memcmp_bad2( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 1 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull %string) + %cmp = icmp slt i32 %call, 1 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad3() { +; CHECK-LABEL: @strcmp_memcmp_bad3( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CALL]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %call +} + + +define i32 @strcmp_memcmp_bad4(i8* nocapture readonly %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad4( +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* [[BUF:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %call = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* %buf) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad5() { +; CHECK-LABEL: @strcmp_memcmp_bad5( +; CHECK-NEXT: [[BUF:%.*]] = alloca [3 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [3 x i8], [3 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 3, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 3, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [3 x i8], align 1 + %string = getelementptr inbounds [3 x i8], [3 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 3, i8* nonnull %string) + %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 3, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad6() { +; CHECK-LABEL: @strcmp_memcmp_bad6( +; CHECK-NEXT: [[BUF:%.*]] = alloca [4 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [4 x i8], align 1 + %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %string) + %call = call i32 @strcmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0)) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad7(i8* nocapture readonly %k) { +; CHECK-LABEL: @strcmp_memcmp_bad7( +; CHECK-NEXT: [[BUF:%.*]] = alloca [4 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull [[STRING]], i8* [[K:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [4 x i8], align 1 + %string = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %string) + %call = call i32 @strcmp(i8* nonnull %string, i8* %k) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strcmp_memcmp_bad8(i8* nocapture readonly %k) { +; CHECK-LABEL: @strcmp_memcmp_bad8( +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* [[K:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[CONV]] +; + %call = tail call i32 @strcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* %k) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + + +define i32 @strncmp_memcmp_bad() { +; CHECK-LABEL: @strncmp_memcmp_bad( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull [[STRING]], i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull %string, i64 5) + %cmp = icmp sgt i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp_bad1() { +; CHECK-LABEL: @strncmp_memcmp_bad1( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull [[STRING]], i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 1 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull %string, i64 5) + %cmp = icmp slt i32 %call, 1 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp_bad2(i64 %n) { +; CHECK-LABEL: @strncmp_memcmp_bad2( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull [[STRING]], i64 [[N:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 1 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull %string, i64 %n) + %cmp = icmp slt i32 %call, 1 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + + +define i32 @strncmp_memcmp_bad3() { +; CHECK-LABEL: @strncmp_memcmp_bad3( +; CHECK-NEXT: [[BUF:%.*]] = alloca [12 x i8], align 1 +; CHECK-NEXT: [[STRING:%.*]] = getelementptr inbounds [12 x i8], [12 x i8]* [[BUF]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull [[STRING]], i64 12) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %buf = alloca [12 x i8], align 1 + %string = getelementptr inbounds [12 x i8], [12 x i8]* %buf, i64 0, i64 0 + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %string) + %call = call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @strcmp_memcmp_bad8.buf, i64 0, i64 0), i8* nonnull %string, i64 12) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %string) + ret i32 %conv +} + +declare i32 @memcmp(i8* nocapture, i8* nocapture, i64)