Skip to content

Commit 07058aa

Browse files
committed
Revert "[SimplifyLibCalls][NFC] Clean up LibCallSimplifier from 'memset + malloc into calloc' transformation"
This reverts commit 01cf1dc.
1 parent 01cf1dc commit 07058aa

File tree

3 files changed

+56
-8
lines changed

3 files changed

+56
-8
lines changed

llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class LibCallSimplifier {
132132
eraseFromParent(I);
133133
}
134134

135+
Value *foldMallocMemset(CallInst *Memset, IRBuilderBase &B);
136+
135137
public:
136138
LibCallSimplifier(
137139
const DataLayout &DL, const TargetLibraryInfo *TLI,

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,12 +1156,59 @@ Value *LibCallSimplifier::optimizeMemMove(CallInst *CI, IRBuilderBase &B) {
11561156
return CI->getArgOperand(0);
11571157
}
11581158

1159+
/// Fold memset[_chk](malloc(n), 0, n) --> calloc(1, n).
1160+
Value *LibCallSimplifier::foldMallocMemset(CallInst *Memset, IRBuilderBase &B) {
1161+
// This has to be a memset of zeros (bzero).
1162+
auto *FillValue = dyn_cast<ConstantInt>(Memset->getArgOperand(1));
1163+
if (!FillValue || FillValue->getZExtValue() != 0)
1164+
return nullptr;
1165+
1166+
// TODO: We should handle the case where the malloc has more than one use.
1167+
// This is necessary to optimize common patterns such as when the result of
1168+
// the malloc is checked against null or when a memset intrinsic is used in
1169+
// place of a memset library call.
1170+
auto *Malloc = dyn_cast<CallInst>(Memset->getArgOperand(0));
1171+
if (!Malloc || !Malloc->hasOneUse())
1172+
return nullptr;
1173+
1174+
// Is the inner call really malloc()?
1175+
Function *InnerCallee = Malloc->getCalledFunction();
1176+
if (!InnerCallee)
1177+
return nullptr;
1178+
1179+
LibFunc Func;
1180+
if (!TLI->getLibFunc(*InnerCallee, Func) || !TLI->has(Func) ||
1181+
Func != LibFunc_malloc)
1182+
return nullptr;
1183+
1184+
// The memset must cover the same number of bytes that are malloc'd.
1185+
if (Memset->getArgOperand(2) != Malloc->getArgOperand(0))
1186+
return nullptr;
1187+
1188+
// Replace the malloc with a calloc. We need the data layout to know what the
1189+
// actual size of a 'size_t' parameter is.
1190+
B.SetInsertPoint(Malloc->getParent(), ++Malloc->getIterator());
1191+
const DataLayout &DL = Malloc->getModule()->getDataLayout();
1192+
IntegerType *SizeType = DL.getIntPtrType(B.GetInsertBlock()->getContext());
1193+
if (Value *Calloc = emitCalloc(ConstantInt::get(SizeType, 1),
1194+
Malloc->getArgOperand(0),
1195+
Malloc->getAttributes(), B, *TLI)) {
1196+
substituteInParent(Malloc, Calloc);
1197+
return Calloc;
1198+
}
1199+
1200+
return nullptr;
1201+
}
1202+
11591203
Value *LibCallSimplifier::optimizeMemSet(CallInst *CI, IRBuilderBase &B) {
11601204
Value *Size = CI->getArgOperand(2);
11611205
annotateNonNullAndDereferenceable(CI, 0, Size, DL);
11621206
if (isa<IntrinsicInst>(CI))
11631207
return nullptr;
11641208

1209+
if (auto *Calloc = foldMallocMemset(CI, B))
1210+
return Calloc;
1211+
11651212
// memset(p, v, n) -> llvm.memset(align 1 p, v, n)
11661213
Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false);
11671214
CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val, Size, Align(1));
@@ -3019,6 +3066,7 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {
30193066
return optimizeLog(CI, Builder);
30203067
case Intrinsic::sqrt:
30213068
return optimizeSqrt(CI, Builder);
3069+
// TODO: Use foldMallocMemset() with memset intrinsic.
30223070
case Intrinsic::memset:
30233071
return optimizeMemSet(CI, Builder);
30243072
case Intrinsic::memcpy:
@@ -3241,6 +3289,8 @@ Value *FortifiedLibCallSimplifier::optimizeMemMoveChk(CallInst *CI,
32413289

32423290
Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI,
32433291
IRBuilderBase &B) {
3292+
// TODO: Try foldMallocMemset() here.
3293+
32443294
if (isFortifiedCallFoldable(CI, 3, 2)) {
32453295
Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false);
32463296
CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val,

llvm/test/Transforms/InstCombine/memset-1.ll

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,17 @@ define i8* @test_simplify1(i8* %mem, i32 %val, i32 %size) {
2121
ret i8* %ret
2222
}
2323

24-
; Malloc + memset pattern is now handled by DSE in a more general way.
25-
2624
define i8* @pr25892_lite(i32 %size) #0 {
2725
; CHECK-LABEL: @pr25892_lite(
28-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i32 [[SIZE:%.*]])
29-
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 [[CALL]], i8 0, i32 [[SIZE]], i1 false)
26+
; CHECK-NEXT: [[CALLOC:%.*]] = call i8* @calloc(i32 1, i32 [[SIZE:%.*]])
27+
; CHECK-NEXT: ret i8* [[CALLOC]]
3028
;
3129
%call1 = call i8* @malloc(i32 %size) #1
3230
%call2 = call i8* @memset(i8* %call1, i32 0, i32 %size) #1
3331
ret i8* %call2
3432
}
3533

36-
; A memset intrinsic should be handled similarly to a memset() libcall.
37-
; Notice that malloc + memset pattern is now handled by DSE in a more general way.
34+
; FIXME: A memset intrinsic should be handled similarly to a memset() libcall.
3835

3936
define i8* @malloc_and_memset_intrinsic(i32 %n) #0 {
4037
; CHECK-LABEL: @malloc_and_memset_intrinsic(
@@ -48,7 +45,6 @@ define i8* @malloc_and_memset_intrinsic(i32 %n) #0 {
4845
}
4946

5047
; This should not create a calloc and should not crash the compiler.
51-
; Notice that malloc + memset pattern is now handled by DSE in a more general way.
5248

5349
define i8* @notmalloc_memset(i32 %size, i8*(i32)* %notmalloc) {
5450
; CHECK-LABEL: @notmalloc_memset(
@@ -61,8 +57,8 @@ define i8* @notmalloc_memset(i32 %size, i8*(i32)* %notmalloc) {
6157
ret i8* %call2
6258
}
6359

60+
; FIXME: memset(malloc(x), 0, x) -> calloc(1, x)
6461
; This doesn't fire currently because the malloc has more than one use.
65-
; Notice that malloc + memset pattern is now handled by DSE in a more general way.
6662

6763
define float* @pr25892(i32 %size) #0 {
6864
; CHECK-LABEL: @pr25892(

0 commit comments

Comments
 (0)