Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -840,12 +840,8 @@ if (!FillValue || FillValue->getZExtValue() != 0) return nullptr; - // TODO: We should handle the case where the malloc has more than one use. - // This is necessary to optimize common patterns such as when the result of - // the malloc is checked against null or when a memset intrinsic is used in - // place of a memset library call. auto *Malloc = dyn_cast(Memset->getArgOperand(0)); - if (!Malloc || !Malloc->hasOneUse()) + if (!Malloc) return nullptr; // Is the inner call really malloc()? @@ -2219,7 +2215,8 @@ return optimizeLog(CI, Builder); case Intrinsic::sqrt: return optimizeSqrt(CI, Builder); - // TODO: Use foldMallocMemset() with memset intrinsic. + case Intrinsic::memset: + return foldMallocMemset(CI, Builder, *TLI); default: return nullptr; } @@ -2393,7 +2390,8 @@ Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI, IRBuilder<> &B) { - // TODO: Try foldMallocMemset() here. + if (auto *Calloc = foldMallocMemset(CI, B, *TLI)) + return Calloc; if (isFortifiedCallFoldable(CI, 3, 2, false)) { Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); Index: test/Transforms/InstCombine/memset-1.ll =================================================================== --- test/Transforms/InstCombine/memset-1.ll +++ test/Transforms/InstCombine/memset-1.ll @@ -26,6 +26,17 @@ ; CHECK-NEXT: ret i8* %calloc } + +define i8* @malloc_llvmmemset_fold_calloc(i32 %n) #0 { + %call = call i8* @malloc(i32 %n) + call void @llvm.memset.p0i8.i32(i8* %call, i8 0, i32 %n, i32 1, i1 false) + ret i8* %call + +; CHECK-LABEL: @malloc_llvmmemset_fold_calloc( +; CHECK-NEXT: %calloc = call i8* @calloc(i32 1, i32 %n) +; CHECK-NEXT: ret i8* %calloc +} + ; This should not create a calloc and not crash the compiler. ; CHECK-LABEL: @notmalloc_memset ; CHECK-NOT: @calloc @@ -53,12 +64,11 @@ ; CHECK-LABEL: @pr25892( ; CHECK: entry: -; CHECK-NEXT: %call = tail call i8* @malloc(i32 %size) #1 -; CHECK-NEXT: %cmp = icmp eq i8* %call, null +; CHECK-NEXT: %calloc = call i8* @calloc(i32 1, i32 %size) +; CHECK-NEXT: %cmp = icmp eq i8* %calloc, null ; CHECK-NEXT: br i1 %cmp, label %cleanup, label %if.end ; CHECK: if.end: -; CHECK-NEXT: %bc = bitcast i8* %call to float* -; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* nonnull align 1 %call, i8 0, i32 %size, i1 false) +; CHECK-NEXT: %bc = bitcast i8* %calloc to float* ; CHECK-NEXT: br label %cleanup ; CHECK: cleanup: ; CHECK-NEXT: %retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ] @@ -67,6 +77,8 @@ declare noalias i8* @malloc(i32) #1 declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) #2 +declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i32, i1) #3 +declare i8* @calloc(i32, i32) #4 attributes #0 = { nounwind ssp uwtable } attributes #1 = { nounwind }