Skip to content

Commit 1953629

Browse files
committed
[MemoryBuiltins] Handle allocator attributes on call-site
We should handle allocator attributes not only on function declarations, but also on the call-site. That way we can e.g. also optimize cases where the allocator function is a virtual function call. This was already supported in some of the MemoryBuiltins helpers, but not all of them. This adds support for allocsize, alloc-family and allockind("free").
1 parent fff78a5 commit 1953629

File tree

3 files changed

+51
-31
lines changed

3 files changed

+51
-31
lines changed

llvm/lib/Analysis/MemoryBuiltins.cpp

+28-31
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,18 @@ getAllocationData(const Value *V, AllocType AllocTy,
240240
}
241241

242242
static std::optional<AllocFnsTy>
243-
getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) {
243+
getAllocationSize(const CallBase *CB, const TargetLibraryInfo *TLI) {
244244
bool IsNoBuiltinCall;
245-
const Function *Callee =
246-
getCalledFunction(V, IsNoBuiltinCall);
247-
if (!Callee)
248-
return std::nullopt;
249-
250-
// Prefer to use existing information over allocsize. This will give us an
251-
// accurate AllocTy.
252-
if (!IsNoBuiltinCall)
245+
const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall);
246+
if (Callee && !IsNoBuiltinCall) {
247+
// Prefer to use existing information over allocsize. This will give us an
248+
// accurate AllocTy.
253249
if (std::optional<AllocFnsTy> Data =
254250
getAllocationDataForFunction(Callee, AnyAlloc, TLI))
255251
return Data;
252+
}
256253

257-
Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
254+
Attribute Attr = CB->getFnAttr(Attribute::AllocSize);
258255
if (Attr == Attribute())
259256
return std::nullopt;
260257

@@ -264,7 +261,7 @@ getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) {
264261
// Because allocsize only tells us how many bytes are allocated, we're not
265262
// really allowed to assume anything, so we use MallocLike.
266263
Result.AllocTy = MallocLike;
267-
Result.NumParams = Callee->getNumOperands();
264+
Result.NumParams = CB->arg_size();
268265
Result.FstParam = Args.first;
269266
Result.SndParam = Args.second.value_or(-1);
270267
// Allocsize has no way to specify an alignment argument
@@ -512,19 +509,20 @@ std::optional<StringRef>
512509
llvm::getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI) {
513510
bool IsNoBuiltin;
514511
const Function *Callee = getCalledFunction(I, IsNoBuiltin);
515-
if (Callee == nullptr || IsNoBuiltin)
516-
return std::nullopt;
517-
LibFunc TLIFn;
518-
519-
if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
520-
// Callee is some known library function.
521-
const auto AllocData = getAllocationDataForFunction(Callee, AnyAlloc, TLI);
522-
if (AllocData)
523-
return mangledNameForMallocFamily(AllocData->Family);
524-
const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
525-
if (FreeData)
526-
return mangledNameForMallocFamily(FreeData->Family);
512+
if (Callee && !IsNoBuiltin) {
513+
LibFunc TLIFn;
514+
if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
515+
// Callee is some known library function.
516+
const auto AllocData =
517+
getAllocationDataForFunction(Callee, AnyAlloc, TLI);
518+
if (AllocData)
519+
return mangledNameForMallocFamily(AllocData->Family);
520+
const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
521+
if (FreeData)
522+
return mangledNameForMallocFamily(FreeData->Family);
523+
}
527524
}
525+
528526
// Callee isn't a known library function, still check attributes.
529527
if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc |
530528
AllocFnKind::Realloc)) {
@@ -558,14 +556,13 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
558556
Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
559557
bool IsNoBuiltinCall;
560558
const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall);
561-
if (Callee == nullptr || IsNoBuiltinCall)
562-
return nullptr;
563-
564-
LibFunc TLIFn;
565-
if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
566-
isLibFreeFunction(Callee, TLIFn)) {
567-
// All currently supported free functions free the first argument.
568-
return CB->getArgOperand(0);
559+
if (Callee && !IsNoBuiltinCall) {
560+
LibFunc TLIFn;
561+
if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
562+
isLibFreeFunction(Callee, TLIFn)) {
563+
// All currently supported free functions free the first argument.
564+
return CB->getArgOperand(0);
565+
}
569566
}
570567

571568
if (checkFnAllocKind(CB, AllocFnKind::Free))

llvm/test/Transforms/InstCombine/deref-alloc-fns.ll

+9
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,12 @@ define ptr @my_calloc_constant_size() {
372372
%call = call ptr @my_calloc(i64 32, i64 4)
373373
ret ptr %call
374374
}
375+
376+
define ptr @virtual_constant_size(ptr %alloc) {
377+
; CHECK-LABEL: @virtual_constant_size(
378+
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(16) ptr [[ALLOC:%.*]](i64 16) #[[ATTR5:[0-9]+]]
379+
; CHECK-NEXT: ret ptr [[CALL]]
380+
;
381+
%call = call ptr %alloc(i64 16) allocsize(0)
382+
ret ptr %call
383+
}

llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ start:
1515
ret void
1616
}
1717

18+
define void @alloc_elides_test_virtual(i32 %data, ptr %alloc, ptr %realloc, ptr %dealloc) {
19+
; CHECK-LABEL: @alloc_elides_test_virtual(
20+
; CHECK-NEXT: start:
21+
; CHECK-NEXT: ret void
22+
;
23+
start:
24+
%a = call noalias ptr %alloc(i64 4, i64 allocalign 32) nounwind allocsize(0) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"
25+
store i32 0, ptr %a
26+
%a2 = call noalias ptr %realloc(ptr allocptr %a, i64 4, i64 allocalign 32, i64 8) nounwind allocsize(3) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"
27+
store i32 1, ptr %a2
28+
call void %dealloc(ptr allocptr %a2, i64 4, i64 32) nounwind allockind("free") "alloc-family"="__rust_alloc"
29+
ret void
30+
}
31+
1832
declare noalias ptr @__rust_alloc(i64, i64 allocalign) nounwind allocsize(0) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"
1933

2034
declare noalias ptr @__rust_realloc(ptr allocptr, i64, i64 allocalign, i64) nounwind allocsize(3) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"

0 commit comments

Comments
 (0)