Skip to content

Commit bc536c7

Browse files
committed
Revert "[DSE] Transform memset + malloc --> calloc (PR25892)"
This reverts commit 43234b1. Reason: We should detect that we are implementing 'calloc' and bail out.
1 parent fef86a3 commit bc536c7

File tree

2 files changed

+14
-188
lines changed

2 files changed

+14
-188
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
#include "llvm/IR/DataLayout.h"
5757
#include "llvm/IR/Dominators.h"
5858
#include "llvm/IR/Function.h"
59-
#include "llvm/IR/IRBuilder.h"
6059
#include "llvm/IR/InstIterator.h"
6160
#include "llvm/IR/InstrTypes.h"
6261
#include "llvm/IR/Instruction.h"
@@ -79,7 +78,6 @@
7978
#include "llvm/Support/raw_ostream.h"
8079
#include "llvm/Transforms/Scalar.h"
8180
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
82-
#include "llvm/Transforms/Utils/BuildLibCalls.h"
8381
#include "llvm/Transforms/Utils/Local.h"
8482
#include <algorithm>
8583
#include <cassert>
@@ -507,12 +505,7 @@ memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI,
507505
BasicBlock::iterator SecondBBI(SecondI);
508506
BasicBlock *FirstBB = FirstI->getParent();
509507
BasicBlock *SecondBB = SecondI->getParent();
510-
MemoryLocation MemLoc;
511-
if (auto *MemSet = dyn_cast<MemSetInst>(SecondI))
512-
MemLoc = MemoryLocation::getForDest(MemSet);
513-
else
514-
MemLoc = MemoryLocation::get(SecondI);
515-
508+
MemoryLocation MemLoc = MemoryLocation::get(SecondI);
516509
auto *MemLocPtr = const_cast<Value *>(MemLoc.Ptr);
517510

518511
// Start checking the SecondBB.
@@ -826,17 +819,14 @@ bool isNoopIntrinsic(Instruction *I) {
826819
}
827820

828821
// Check if we can ignore \p D for DSE.
829-
bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller,
830-
const TargetLibraryInfo &TLI) {
822+
bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) {
831823
Instruction *DI = D->getMemoryInst();
832824
// Calls that only access inaccessible memory cannot read or write any memory
833825
// locations we consider for elimination.
834826
if (auto *CB = dyn_cast<CallBase>(DI))
835-
if (CB->onlyAccessesInaccessibleMemory()) {
836-
if (isAllocLikeFn(DI, &TLI))
837-
return false;
827+
if (CB->onlyAccessesInaccessibleMemory())
838828
return true;
839-
}
829+
840830
// We can eliminate stores to locations not visible to the caller across
841831
// throwing instructions.
842832
if (DI->mayThrow() && !DefVisibleToCaller)
@@ -851,7 +841,7 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller,
851841
return true;
852842

853843
// Skip intrinsics that do not really read or modify memory.
854-
if (isNoopIntrinsic(DI))
844+
if (isNoopIntrinsic(D->getMemoryInst()))
855845
return true;
856846

857847
return false;
@@ -1399,7 +1389,7 @@ struct DSEState {
13991389
MemoryDef *CurrentDef = cast<MemoryDef>(Current);
14001390
Instruction *CurrentI = CurrentDef->getMemoryInst();
14011391

1402-
if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(DefUO), TLI))
1392+
if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(DefUO)))
14031393
continue;
14041394

14051395
// Before we try to remove anything, check for any extra throwing
@@ -1826,55 +1816,13 @@ struct DSEState {
18261816

18271817
if (StoredConstant && StoredConstant->isNullValue()) {
18281818
auto *DefUOInst = dyn_cast<Instruction>(DefUO);
1829-
if (DefUOInst) {
1830-
if (isCallocLikeFn(DefUOInst, &TLI)) {
1831-
auto *UnderlyingDef =
1832-
cast<MemoryDef>(MSSA.getMemoryAccess(DefUOInst));
1833-
// If UnderlyingDef is the clobbering access of Def, no instructions
1834-
// between them can modify the memory location.
1835-
auto *ClobberDef =
1836-
MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(Def);
1837-
return UnderlyingDef == ClobberDef;
1838-
}
1839-
1840-
if (MemSet) {
1841-
if (F.hasFnAttribute(Attribute::SanitizeMemory))
1842-
return false;
1843-
auto *Malloc = const_cast<CallInst *>(dyn_cast<CallInst>(DefUOInst));
1844-
if (!Malloc)
1845-
return false;
1846-
auto *InnerCallee = Malloc->getCalledFunction();
1847-
if (!InnerCallee)
1848-
return false;
1849-
LibFunc Func;
1850-
if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) ||
1851-
Func != LibFunc_malloc)
1852-
return false;
1853-
if (Malloc->getOperand(0) == MemSet->getLength()) {
1854-
if (DT.dominates(Malloc, MemSet) &&
1855-
memoryIsNotModifiedBetween(Malloc, MemSet, BatchAA, DL, &DT)) {
1856-
IRBuilder<> IRB(Malloc);
1857-
const auto &DL = Malloc->getModule()->getDataLayout();
1858-
AttributeList EmptyList;
1859-
if (auto *Calloc = emitCalloc(
1860-
ConstantInt::get(IRB.getIntPtrTy(DL), 1),
1861-
Malloc->getArgOperand(0), EmptyList, IRB, TLI)) {
1862-
MemorySSAUpdater Updater(&MSSA);
1863-
auto *LastDef = cast<MemoryDef>(
1864-
Updater.getMemorySSA()->getMemoryAccess(Malloc));
1865-
auto *NewAccess = Updater.createMemoryAccessAfter(
1866-
cast<Instruction>(Calloc), LastDef, LastDef);
1867-
auto *NewAccessMD = cast<MemoryDef>(NewAccess);
1868-
Updater.insertDef(NewAccessMD, /*RenameUses=*/true);
1869-
Updater.removeMemoryAccess(Malloc);
1870-
Malloc->replaceAllUsesWith(Calloc);
1871-
Malloc->eraseFromParent();
1872-
return true;
1873-
}
1874-
return false;
1875-
}
1876-
}
1877-
}
1819+
if (DefUOInst && isCallocLikeFn(DefUOInst, &TLI)) {
1820+
auto *UnderlyingDef = cast<MemoryDef>(MSSA.getMemoryAccess(DefUOInst));
1821+
// If UnderlyingDef is the clobbering access of Def, no instructions
1822+
// between them can modify the memory location.
1823+
auto *ClobberDef =
1824+
MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(Def);
1825+
return UnderlyingDef == ClobberDef;
18781826
}
18791827
}
18801828

llvm/test/Transforms/DeadStoreElimination/noop-stores.ll

Lines changed: 1 addition & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt < %s -basic-aa -dse -S | FileCheck %s
3-
; RUN: opt < %s -aa-pipeline=basic-aa -passes='dse,verify<memoryssa>' -S | FileCheck %s
3+
; RUN: opt < %s -aa-pipeline=basic-aa -passes=dse -S | FileCheck %s
44
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
55

66
declare i8* @calloc(i64, i64)
@@ -309,128 +309,6 @@ entry:
309309
ret void
310310
}
311311

312-
declare noalias i8* @malloc(i64)
313-
declare noalias i8* @_Znwm(i64)
314-
declare void @clobber_memory(float*)
315-
316-
; based on pr25892_lite
317-
define i8* @zero_memset_after_malloc(i64 %size) {
318-
; CHECK-LABEL: @zero_memset_after_malloc(
319-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @calloc(i64 1, i64 [[SIZE:%.*]])
320-
; CHECK-NEXT: ret i8* [[CALL]]
321-
;
322-
%call = call i8* @malloc(i64 %size) inaccessiblememonly
323-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size, i1 false)
324-
ret i8* %call
325-
}
326-
327-
; based on pr25892_lite
328-
define i8* @zero_memset_after_malloc_with_intermediate_clobbering(i64 %size) {
329-
; CHECK-LABEL: @zero_memset_after_malloc_with_intermediate_clobbering(
330-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 [[SIZE:%.*]])
331-
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[CALL]] to float*
332-
; CHECK-NEXT: call void @clobber_memory(float* [[BC]])
333-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[CALL]], i8 0, i64 [[SIZE]], i1 false)
334-
; CHECK-NEXT: ret i8* [[CALL]]
335-
;
336-
%call = call i8* @malloc(i64 %size) inaccessiblememonly
337-
%bc = bitcast i8* %call to float*
338-
call void @clobber_memory(float* %bc)
339-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size, i1 false)
340-
ret i8* %call
341-
}
342-
343-
; based on pr25892_lite
344-
define i8* @zero_memset_after_malloc_with_different_sizes(i64 %size) {
345-
; CHECK-LABEL: @zero_memset_after_malloc_with_different_sizes(
346-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 [[SIZE:%.*]])
347-
; CHECK-NEXT: [[SIZE2:%.*]] = add nsw i64 [[SIZE]], -1
348-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[CALL]], i8 0, i64 [[SIZE2]], i1 false)
349-
; CHECK-NEXT: ret i8* [[CALL]]
350-
;
351-
%call = call i8* @malloc(i64 %size) inaccessiblememonly
352-
%size2 = add nsw i64 %size, -1
353-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size2, i1 false)
354-
ret i8* %call
355-
}
356-
357-
; based on pr25892_lite
358-
define i8* @zero_memset_after_new(i64 %size) {
359-
; CHECK-LABEL: @zero_memset_after_new(
360-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @_Znwm(i64 [[SIZE:%.*]])
361-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[CALL]], i8 0, i64 [[SIZE]], i1 false)
362-
; CHECK-NEXT: ret i8* [[CALL]]
363-
;
364-
%call = call i8* @_Znwm(i64 %size)
365-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size, i1 false)
366-
ret i8* %call
367-
}
368-
369-
; This should not create a calloc and should not crash the compiler.
370-
define i8* @notmalloc_memset(i64 %size, i8*(i64)* %notmalloc) {
371-
; CHECK-LABEL: @notmalloc_memset(
372-
; CHECK-NEXT: [[CALL1:%.*]] = call i8* [[NOTMALLOC:%.*]](i64 [[SIZE:%.*]])
373-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[CALL1]], i8 0, i64 [[SIZE]], i1 false)
374-
; CHECK-NEXT: ret i8* [[CALL1]]
375-
;
376-
%call1 = call i8* %notmalloc(i64 %size)
377-
call void @llvm.memset.p0i8.i64(i8* %call1, i8 0, i64 %size, i1 false)
378-
ret i8* %call1
379-
}
380-
381-
define float* @pr25892(i64 %size) {
382-
; CHECK-LABEL: @pr25892(
383-
; CHECK: entry:
384-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @calloc(i64 1, i64 [[SIZE:%.*]])
385-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[CALL]], null
386-
; CHECK-NEXT: br i1 [[CMP]], label [[CLEANUP:%.*]], label [[IF_END:%.*]]
387-
; CHECK: if.end:
388-
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[CALL]] to float*
389-
; CHECK-NEXT: br label [[CLEANUP]]
390-
; CHECK: cleanup:
391-
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi float* [ [[BC]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
392-
; CHECK-NEXT: ret float* [[RETVAL_0]]
393-
;
394-
entry:
395-
%call = call i8* @malloc(i64 %size) inaccessiblememonly
396-
%cmp = icmp eq i8* %call, null
397-
br i1 %cmp, label %cleanup, label %if.end
398-
if.end:
399-
%bc = bitcast i8* %call to float*
400-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size, i1 false)
401-
br label %cleanup
402-
cleanup:
403-
%retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ]
404-
ret float* %retval.0
405-
}
406-
407-
; CHECK-LABEL: @pr25892_with_extra_store(
408-
; CHECK: entry:
409-
; CHECK-NEXT: [[CALL:%.*]] = call i8* @calloc(i64 1, i64 [[SIZE:%.*]])
410-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[CALL]], null
411-
; CHECK-NEXT: br i1 [[CMP]], label [[CLEANUP:%.*]], label [[IF_END:%.*]]
412-
; CHECK: if.end:
413-
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[CALL]] to float*
414-
; CHECK-NEXT: br label [[CLEANUP]]
415-
; CHECK: cleanup:
416-
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi float* [ [[BC]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
417-
; CHECK-NEXT: ret float* [[RETVAL_0]]
418-
;
419-
define float* @pr25892_with_extra_store(i64 %size) {
420-
entry:
421-
%call = call i8* @malloc(i64 %size) inaccessiblememonly
422-
%cmp = icmp eq i8* %call, null
423-
br i1 %cmp, label %cleanup, label %if.end
424-
if.end:
425-
%bc = bitcast i8* %call to float*
426-
call void @llvm.memset.p0i8.i64(i8* %call, i8 0, i64 %size, i1 false)
427-
store i8 0, i8* %call, align 1
428-
br label %cleanup
429-
cleanup:
430-
%retval.0 = phi float* [ %bc, %if.end ], [ null, %entry ]
431-
ret float* %retval.0
432-
}
433-
434312
; PR50143
435313
define i8* @store_zero_after_calloc_inaccessiblememonly() {
436314
; CHECK-LABEL: @store_zero_after_calloc_inaccessiblememonly(

0 commit comments

Comments
 (0)