Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -22,6 +22,7 @@ #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/Loads.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -150,6 +151,17 @@ return true; } +static bool canTransformToMemCmp(CallInst *CI, Value *Str, uint64_t Len, + const DataLayout &DL) { + if (!isOnlyUsedInZeroEqualityComparison(CI)) + return false; + + if (!isDereferenceableAndAlignedPointer(Str, 1, APInt(64, Len), DL)) + return false; + + return true; +} + //===----------------------------------------------------------------------===// // String and Memory Library Call Optimizations //===----------------------------------------------------------------------===// @@ -322,6 +334,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, DL)) + return emitMemCmp(Str1P, Str2P, + ConstantInt::get(DL.getIntPtrType(CI->getContext()), Len), + B, DL, TLI); + return nullptr; } @@ -361,6 +389,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, DL)) + 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,550 @@ +; 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" + +@key = constant [4 x i8] c"key\00", align 1 + +declare void @use(i32) + +define i32 @strcmp_memcmp([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp( +; 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]* @key, 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 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %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]* @key, i64 0, i64 0)) + %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 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([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp2( +; 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]* @key, i64 0, i64 0), i8* nonnull [[STRING]]) +; 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]] +; + %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]* @key, i64 0, i64 0), i8* nonnull %string) + %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 +} + +define i32 @strcmp_memcmp3([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp3( +; 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]* @key, i64 0, i64 0)) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne 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]] +; + %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]* @key, i64 0, i64 0)) + %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 @strcmp_memcmp4([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp4( +; 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]* @key, i64 0, i64 0), i8* nonnull [[STRING]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne 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]] +; + %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]* @key, i64 0, i64 0), i8* nonnull %string) + %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 @strcmp_memcmp5([5 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp5( +; 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: [[CALL:%.*]] = call i32 @strcmp(i8* nonnull align 1 [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, 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 5, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CONV]] +; + %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) + %call = call i32 @strcmp(i8* nonnull align 1 %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0)) + %cmp = icmp eq i32 %call, 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([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp( +; 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* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2) +; 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]] +; + %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]* @key, 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) + +define i32 @strncmp_memcmp2([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp2( +; 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* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 11) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne 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]] +; + %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]* @key, i64 0, i64 0), i64 11) + %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([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp3( +; 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]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 11) +; 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]] +; + %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]* @key, i64 0, i64 0), i8* nonnull %string, i64 11) + %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 +} + +define i32 @strncmp_memcmp4([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp4( +; 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* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 5) +; 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]] +; + %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]* @key, i64 0, i64 0), i64 5) + %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 +} + +define i32 @strncmp_memcmp5([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp5( +; 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]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 5) +; 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]] +; + %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]* @key, i64 0, i64 0), i8* nonnull %string, i64 5) + %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 +} + + +define i32 @strncmp_memcmp6([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp6( +; 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]* @key, i64 0, i64 0), i8* nonnull [[STRING]], i64 5) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne 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]] +; + %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]* @key, i64 0, i64 0), i8* nonnull %string, i64 5) + %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_memcmp7([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp7( +; 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* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 4) +; 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]] +; + %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]* @key, i64 0, i64 0), i64 4) + %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 +} + +define i32 @strncmp_memcmp8([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp8( +; 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* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 3) +; 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]] +; + %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]* @key, i64 0, i64 0), i64 3) + %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 +} + +; Negative tests +define i32 @strcmp_memcmp_bad([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad( +; 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]* @key, 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]] +; + %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]* @key, 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([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad2( +; 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]* @key, 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]] +; + %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]* @key, 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([12 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad3( +; 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]* @key, i64 0, i64 0)) +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 [[CALL]] +; + %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]* @key, 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]* @key, 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]* @key, 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([3 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad5( +; 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]* @key, 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]] +; + %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]* @key, 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([4 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad6( +; 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]* @key, 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]] +; + %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]* @key, 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([4 x i8]* %buf, i8* nocapture readonly %k) { +; CHECK-LABEL: @strcmp_memcmp_bad7( +; 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]] +; + %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]* @key, 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]* @key, i64 0, i64 0), i8* %k) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +define i32 @strcmp_memcmp_bad9([4 x i8]* %buf) { +; CHECK-LABEL: @strcmp_memcmp_bad9( +; 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]* @key, i64 0, i64 0)) +; CHECK-NEXT: tail call void @use(i32 [[CALL]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 0 +; + %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]* @key, i64 0, i64 0)) + tail call void @use(i32 %call) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %string) + ret i32 0 +} + +define i32 @strncmp_memcmp_bad([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp_bad( +; 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]* @key, 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]] +; + %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]* @key, 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([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp_bad1( +; 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]* @key, 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]] +; + %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]* @key, 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([12 x i8]* %buf, i64 %n) { +; CHECK-LABEL: @strncmp_memcmp_bad2( +; 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]* @key, 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]] +; + %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]* @key, 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([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp_bad3( +; 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]* @key, 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]] +; + %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]* @key, 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 +} + +define i32 @strncmp_memcmp_bad4([12 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp_bad4( +; 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]* @key, 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]] +; + %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]* @key, 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 +} + +define i32 @strncmp_memcmp_bad5(i8* nocapture readonly %k) { +; CHECK-LABEL: @strncmp_memcmp_bad5( +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* [[K:%.*]], i64 2) +; 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 @strncmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i8* %k, i64 2) + %cmp = icmp eq i32 %call, 0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +define i32 @strncmp_memcmp_bad6([4 x i8]* %buf) { +; CHECK-LABEL: @strncmp_memcmp_bad6( +; 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 @strncmp(i8* nonnull [[STRING]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2) +; CHECK-NEXT: tail call void @use(i32 [[CALL]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[STRING]]) +; CHECK-NEXT: ret i32 0 +; + %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 @strncmp(i8* nonnull %string, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @key, i64 0, i64 0), i64 2) + tail call void @use(i32 %call) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %string) + ret i32 0 +} + +declare i32 @memcmp(i8* nocapture, i8* nocapture, i64)