Skip to content

Commit c346cf7

Browse files
jamie-osecclubby789
authored andcommitted
Support non-malloc functions in malloc+memset->calloc fold
1 parent ee3610e commit c346cf7

File tree

6 files changed

+81
-8
lines changed

6 files changed

+81
-8
lines changed

llvm/docs/LangRef.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,10 @@ For example:
19541954
The first three options are mutually exclusive, and the remaining options
19551955
describe more details of how the function behaves. The remaining options
19561956
are invalid for "free"-type functions.
1957+
``"alloc-variant-zeroed"="FUNCTION"``
1958+
This attribute indicates that another function is equivalent to an allocator function,
1959+
but returns zeroed memory. The function must have "zeroed" allocation behavior,
1960+
the same ``alloc-family``, and take exactly the same arguments.
19571961
``allocsize(<EltSizeParam>[, <NumEltsParam>])``
19581962
This attribute indicates that the annotated function will always return at
19591963
least a given number of bytes (or null). Its arguments are zero-indexed

llvm/include/llvm/IR/Attributes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class Attribute {
156156
static Attribute getWithAllocSizeArgs(
157157
LLVMContext &Context, unsigned ElemSizeArg,
158158
const std::optional<unsigned> &NumElemsArg);
159+
static Attribute getWithAllocKind(LLVMContext &Context, AllocFnKind Kind);
159160
static Attribute getWithVScaleRangeArgs(LLVMContext &Context,
160161
unsigned MinValue, unsigned MaxValue);
161162
static Attribute getWithByValType(LLVMContext &Context, Type *Ty);

llvm/lib/IR/Attributes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
300300
return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));
301301
}
302302

303+
Attribute Attribute::getWithAllocKind(LLVMContext &Context, AllocFnKind Kind) {
304+
return get(Context, AllocKind, static_cast<uint64_t>(Kind));
305+
}
306+
303307
Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context,
304308
unsigned MinValue,
305309
unsigned MaxValue) {

llvm/lib/IR/Verifier.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,6 +2377,32 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
23772377
CheckFailed("'allockind()' can't be both zeroed and uninitialized");
23782378
}
23792379

2380+
if (Attrs.hasFnAttr("alloc-variant-zeroed")) {
2381+
if (auto A = Attrs.getFnAttr("alloc-variant-zeroed"); A.isValid()) {
2382+
StringRef s = A.getValueAsString();
2383+
Check(!s.empty(), "\"alloc-variant-zeroed\" must not be empty");
2384+
if (auto *F = dyn_cast<Function>(V)) {
2385+
if (auto Variant = F->getParent()->getFunction(s)) {
2386+
auto Family = Attrs.getFnAttr("alloc-family");
2387+
if (Family.isValid())
2388+
Check(Variant->getFnAttribute("alloc-family").isValid() &&
2389+
Variant->getFnAttribute("alloc-family")
2390+
.getValueAsString() == Family.getValueAsString(),
2391+
"\"alloc-variant-zeroed\" must name a function belonging to "
2392+
"the "
2393+
"same alloc-family");
2394+
2395+
Check(Variant->hasFnAttribute(Attribute::AllocKind) &&
2396+
(Variant->getFnAttribute(Attribute::AllocKind)
2397+
.getAllocKind() &
2398+
AllocFnKind::Zeroed) != AllocFnKind::Unknown,
2399+
"\"alloc-variant-zeroed\" must name a function with "
2400+
"`allockind(\"zeroed\")`");
2401+
}
2402+
}
2403+
}
2404+
}
2405+
23802406
if (Attrs.hasFnAttr(Attribute::VScaleRange)) {
23812407
unsigned VScaleMin = Attrs.getFnAttrs().getVScaleRangeMin();
23822408
if (VScaleMin == 0)

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,9 +2028,18 @@ struct DSEState {
20282028
if (!InnerCallee)
20292029
return false;
20302030
LibFunc Func;
2031+
std::optional<StringRef> ZeroedVariantName = std::nullopt;
20312032
if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) ||
2032-
Func != LibFunc_malloc)
2033-
return false;
2033+
Func != LibFunc_malloc) {
2034+
if (!Malloc->getFnAttr("alloc-variant-zeroed").isValid()) {
2035+
return false;
2036+
}
2037+
ZeroedVariantName =
2038+
Malloc->getFnAttr("alloc-variant-zeroed").getValueAsString();
2039+
if (ZeroedVariantName->empty())
2040+
return false;
2041+
}
2042+
20342043
// Gracefully handle malloc with unexpected memory attributes.
20352044
auto *MallocDef = dyn_cast_or_null<MemoryDef>(MSSA.getMemoryAccess(Malloc));
20362045
if (!MallocDef)
@@ -2057,15 +2066,31 @@ struct DSEState {
20572066

20582067
if (Malloc->getOperand(0) != MemSet->getLength())
20592068
return false;
2060-
if (!shouldCreateCalloc(Malloc, MemSet) ||
2061-
!DT.dominates(Malloc, MemSet) ||
2069+
if (!shouldCreateCalloc(Malloc, MemSet) || !DT.dominates(Malloc, MemSet) ||
20622070
!memoryIsNotModifiedBetween(Malloc, MemSet, BatchAA, DL, &DT))
20632071
return false;
20642072
IRBuilder<> IRB(Malloc);
2065-
Type *SizeTTy = Malloc->getArgOperand(0)->getType();
2066-
auto *Calloc =
2067-
emitCalloc(ConstantInt::get(SizeTTy, 1), Malloc->getArgOperand(0), IRB,
2068-
TLI, Malloc->getType()->getPointerAddressSpace());
2073+
assert(Func == LibFunc_malloc || ZeroedVariantName.has_value());
2074+
Value *Calloc = nullptr;
2075+
if (ZeroedVariantName.has_value()) {
2076+
auto &Ctx = Malloc->getContext();
2077+
auto Attr = InnerCallee->getAttributes();
2078+
auto AllocKind = Attr.getFnAttr(Attribute::AllocKind).getAllocKind() |
2079+
AllocFnKind::Zeroed;
2080+
Attr =
2081+
Attr.addFnAttribute(Ctx, Attribute::getWithAllocKind(Ctx, AllocKind));
2082+
auto ZeroedVariant = Malloc->getModule()->getOrInsertFunction(
2083+
*ZeroedVariantName, InnerCallee->getFunctionType(), Attr);
2084+
SmallVector<Value *, 3> Args;
2085+
for (unsigned I = 0; I < Malloc->arg_size(); I++)
2086+
Args.push_back(Malloc->getArgOperand(I));
2087+
Calloc = IRB.CreateCall(ZeroedVariant, Args, *ZeroedVariantName);
2088+
} else {
2089+
Type *SizeTTy = Malloc->getArgOperand(0)->getType();
2090+
Calloc =
2091+
emitCalloc(ConstantInt::get(SizeTTy, 1), Malloc->getArgOperand(0),
2092+
IRB, TLI, Malloc->getType()->getPointerAddressSpace());
2093+
}
20692094
if (!Calloc)
20702095
return false;
20712096

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,19 @@ define ptr @notmalloc_memset(i64 %size, ptr %notmalloc) {
374374
ret ptr %call1
375375
}
376376

377+
; This should create a customalloc_zeroed
378+
define ptr @customalloc_memset(i64 %size, i64 %align) {
379+
; CHECK-LABEL: @customalloc_memset
380+
; CHECK-NEXT: [[CALL:%.*]] = call ptr @customalloc_zeroed(i64 [[SIZE:%.*]], i64 [[ALIGN:%.*]])
381+
; CHECK-NEXT: ret ptr [[CALL]]
382+
%call = call ptr @customalloc(i64 %size, i64 %align)
383+
call void @llvm.memset.p0.i64(ptr %call, i8 0, i64 %size, i1 false)
384+
ret ptr %call
385+
}
386+
387+
declare ptr @customalloc(i64, i64) allockind("alloc") "alloc-family"="customalloc" "alloc-variant-zeroed"="customalloc_zeroed"
388+
declare ptr @customalloc_zeroed(i64, i64) allockind("alloc,zeroed") "alloc-family"="customalloc"
389+
377390
; This should not create recursive call to calloc.
378391
define ptr @calloc(i64 %nmemb, i64 %size) inaccessiblememonly {
379392
; CHECK-LABEL: @calloc(

0 commit comments

Comments
 (0)