Skip to content

Commit 26fca54

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

File tree

8 files changed

+118
-8
lines changed

8 files changed

+118
-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 (Attribute A = Attrs.getFnAttr("alloc-variant-zeroed"); A.isValid()) {
2381+
StringRef S = A.getValueAsString();
2382+
Check(!S.empty(), "'alloc-variant-zeroed' must not be empty");
2383+
auto *GV = dyn_cast<GlobalValue>(V);
2384+
Function *Variant = GV ? GV->getParent()->getFunction(S) : nullptr;
2385+
if (Variant) {
2386+
Attribute Family = Attrs.getFnAttr("alloc-family");
2387+
Attribute VariantFamily = Variant->getFnAttribute("alloc-family");
2388+
if (Family.isValid())
2389+
Check(VariantFamily.isValid() &&
2390+
VariantFamily.getValueAsString() == Family.getValueAsString(),
2391+
"'alloc-variant-zeroed' must name a function belonging to the "
2392+
"same 'alloc-family'");
2393+
2394+
Check(Variant->hasFnAttribute(Attribute::AllocKind) &&
2395+
(Variant->getFnAttribute(Attribute::AllocKind).getAllocKind() &
2396+
AllocFnKind::Zeroed) != AllocFnKind::Unknown,
2397+
"'alloc-variant-zeroed' must name a function with "
2398+
"'allockind(\"zeroed\")'");
2399+
2400+
Check(FT == Variant->getFunctionType(),
2401+
"'alloc-variant-zeroed' must name a function with the same "
2402+
"signature");
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,17 @@ struct DSEState {
20282028
if (!InnerCallee)
20292029
return false;
20302030
LibFunc Func;
2031+
StringRef ZeroedVariantName;
20312032
if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) ||
2032-
Func != LibFunc_malloc)
2033-
return false;
2033+
Func != LibFunc_malloc) {
2034+
Attribute Attr = Malloc->getFnAttr("alloc-variant-zeroed");
2035+
if (!Attr.isValid())
2036+
return false;
2037+
ZeroedVariantName = Attr.getValueAsString();
2038+
if (ZeroedVariantName->empty())
2039+
return false;
2040+
}
2041+
20342042
// Gracefully handle malloc with unexpected memory attributes.
20352043
auto *MallocDef = dyn_cast_or_null<MemoryDef>(MSSA.getMemoryAccess(Malloc));
20362044
if (!MallocDef)
@@ -2057,15 +2065,32 @@ struct DSEState {
20572065

20582066
if (Malloc->getOperand(0) != MemSet->getLength())
20592067
return false;
2060-
if (!shouldCreateCalloc(Malloc, MemSet) ||
2061-
!DT.dominates(Malloc, MemSet) ||
2068+
if (!shouldCreateCalloc(Malloc, MemSet) || !DT.dominates(Malloc, MemSet) ||
20622069
!memoryIsNotModifiedBetween(Malloc, MemSet, BatchAA, DL, &DT))
20632070
return false;
20642071
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());
2072+
assert(Func == LibFunc_malloc || !ZeroedVariantName.empty());
2073+
Value *Calloc = nullptr;
2074+
if (!ZeroedVariantName.empty()) {
2075+
LLVMContext &Ctx = Malloc->getContext();
2076+
AttributeList Attrs = InnerCallee->getAttributes();
2077+
AllocFnKind AllocKind =
2078+
Attrs.getFnAttr(Attribute::AllocKind).getAllocKind() |
2079+
AllocFnKind::Zeroed;
2080+
Attrs =
2081+
Attrs.addFnAttribute(Ctx, Attribute::getWithAllocKind(Ctx, AllocKind))
2082+
.removeFnAttribute(Ctx, "alloc-variant-zeroed");
2083+
FunctionCallee ZeroedVariant = Malloc->getModule()->getOrInsertFunction(
2084+
ZeroedVariantName, InnerCallee->getFunctionType(), Attrs);
2085+
SmallVector<Value *, 3> Args;
2086+
Args.append(Malloc->arg_begin(), Malloc->arg_end());
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 call and eliminate the memset
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(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: opt < %s -aa-pipeline=basic-aa -passes='dse,verify<memoryssa>' -S | FileCheck %s
2+
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"
3+
4+
declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
5+
6+
; This should create a declaration for the named variant
7+
define ptr @undeclared_customalloc(i64 %size, i64 %align) {
8+
; CHECK-LABEL: @undeclared_customalloc
9+
; CHECK-NEXT: [[CALL:%.*]] = call ptr @customalloc2_zeroed(i64 [[SIZE:%.*]], i64 [[ALIGN:%.*]])
10+
; CHECK-NEXT: ret ptr [[CALL]]
11+
%call = call ptr @customalloc2(i64 %size, i64 %align)
12+
call void @llvm.memset.p0.i64(ptr %call, i8 0, i64 %size, i1 false)
13+
ret ptr %call
14+
}
15+
16+
declare ptr @customalloc2(i64, i64) allockind("alloc") "alloc-family"="customalloc2" "alloc-variant-zeroed"="customalloc2_zeroed"
17+
; CHECK-DAG: declare ptr @customalloc2_zeroed(i64, i64) #[[CA2ATTR:[0-9]+]]
18+
; CHECK-DAG: attributes #[[CA2ATTR]] = { allockind("alloc,zeroed") "alloc-family"="customalloc2" }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
2+
3+
; CHECK: 'alloc-variant-zeroed' must not be empty
4+
declare ptr @a(i64) "alloc-variant-zeroed"=""
5+
6+
; CHECK: 'alloc-variant-zeroed' must not be empty
7+
declare ptr @b(i64) "alloc-variant-zeroed"=""
8+
9+
; CHECK: 'alloc-variant-zeroed' must name a function belonging to the same 'alloc-family'
10+
declare ptr @c(i64) "alloc-variant-zeroed"="c_zeroed" "alloc-family"="C"
11+
declare ptr @c_zeroed(i64)
12+
13+
; CHECK: 'alloc-variant-zeroed' must name a function with 'allockind("zeroed")'
14+
declare ptr @d(i64) "alloc-variant-zeroed"="d_zeroed" "alloc-family"="D"
15+
declare ptr @d_zeroed(i64) "alloc-family"="D"
16+
17+
; CHECK: 'alloc-variant-zeroed' must name a function with the same signature
18+
declare ptr @e(i64) "alloc-variant-zeroed"="e_zeroed" "alloc-family"="E"
19+
declare ptr @e_zeroed(i64, i64) "alloc-family"="E" allockind("zeroed")

0 commit comments

Comments
 (0)