[llvm] 1953629 - [MemoryBuiltins] Handle allocator attributes on call-site

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 9 06:23:02 PDT 2024


Author: Nikita Popov
Date: 2024-08-09T15:22:54+02:00
New Revision: 195362929cd79c0202f73bcbab9a09b8a1a3beaa

URL: https://github.com/llvm/llvm-project/commit/195362929cd79c0202f73bcbab9a09b8a1a3beaa
DIFF: https://github.com/llvm/llvm-project/commit/195362929cd79c0202f73bcbab9a09b8a1a3beaa.diff

LOG: [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").

Added: 
    

Modified: 
    llvm/lib/Analysis/MemoryBuiltins.cpp
    llvm/test/Transforms/InstCombine/deref-alloc-fns.ll
    llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 1edc51e9ce5da..6fbdda1843c21 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -240,21 +240,18 @@ getAllocationData(const Value *V, AllocType AllocTy,
 }
 
 static std::optional<AllocFnsTy>
-getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) {
+getAllocationSize(const CallBase *CB, const TargetLibraryInfo *TLI) {
   bool IsNoBuiltinCall;
-  const Function *Callee =
-      getCalledFunction(V, IsNoBuiltinCall);
-  if (!Callee)
-    return std::nullopt;
-
-  // Prefer to use existing information over allocsize. This will give us an
-  // accurate AllocTy.
-  if (!IsNoBuiltinCall)
+  const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall);
+  if (Callee && !IsNoBuiltinCall) {
+    // Prefer to use existing information over allocsize. This will give us an
+    // accurate AllocTy.
     if (std::optional<AllocFnsTy> Data =
             getAllocationDataForFunction(Callee, AnyAlloc, TLI))
       return Data;
+  }
 
-  Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
+  Attribute Attr = CB->getFnAttr(Attribute::AllocSize);
   if (Attr == Attribute())
     return std::nullopt;
 
@@ -264,7 +261,7 @@ getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) {
   // Because allocsize only tells us how many bytes are allocated, we're not
   // really allowed to assume anything, so we use MallocLike.
   Result.AllocTy = MallocLike;
-  Result.NumParams = Callee->getNumOperands();
+  Result.NumParams = CB->arg_size();
   Result.FstParam = Args.first;
   Result.SndParam = Args.second.value_or(-1);
   // Allocsize has no way to specify an alignment argument
@@ -512,19 +509,20 @@ std::optional<StringRef>
 llvm::getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI) {
   bool IsNoBuiltin;
   const Function *Callee = getCalledFunction(I, IsNoBuiltin);
-  if (Callee == nullptr || IsNoBuiltin)
-    return std::nullopt;
-  LibFunc TLIFn;
-
-  if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
-    // Callee is some known library function.
-    const auto AllocData = getAllocationDataForFunction(Callee, AnyAlloc, TLI);
-    if (AllocData)
-      return mangledNameForMallocFamily(AllocData->Family);
-    const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
-    if (FreeData)
-      return mangledNameForMallocFamily(FreeData->Family);
+  if (Callee && !IsNoBuiltin) {
+    LibFunc TLIFn;
+    if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
+      // Callee is some known library function.
+      const auto AllocData =
+          getAllocationDataForFunction(Callee, AnyAlloc, TLI);
+      if (AllocData)
+        return mangledNameForMallocFamily(AllocData->Family);
+      const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
+      if (FreeData)
+        return mangledNameForMallocFamily(FreeData->Family);
+    }
   }
+
   // Callee isn't a known library function, still check attributes.
   if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc |
                               AllocFnKind::Realloc)) {
@@ -558,14 +556,13 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
 Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
   bool IsNoBuiltinCall;
   const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall);
-  if (Callee == nullptr || IsNoBuiltinCall)
-    return nullptr;
-
-  LibFunc TLIFn;
-  if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
-      isLibFreeFunction(Callee, TLIFn)) {
-    // All currently supported free functions free the first argument.
-    return CB->getArgOperand(0);
+  if (Callee && !IsNoBuiltinCall) {
+    LibFunc TLIFn;
+    if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
+        isLibFreeFunction(Callee, TLIFn)) {
+      // All currently supported free functions free the first argument.
+      return CB->getArgOperand(0);
+    }
   }
 
   if (checkFnAllocKind(CB, AllocFnKind::Free))

diff  --git a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll
index bb46ce02313ac..00dbf7e180c4c 100644
--- a/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll
+++ b/llvm/test/Transforms/InstCombine/deref-alloc-fns.ll
@@ -372,3 +372,12 @@ define ptr @my_calloc_constant_size() {
   %call = call ptr @my_calloc(i64 32, i64 4)
   ret ptr %call
 }
+
+define ptr @virtual_constant_size(ptr %alloc) {
+; CHECK-LABEL: @virtual_constant_size(
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(16) ptr [[ALLOC:%.*]](i64 16) #[[ATTR5:[0-9]+]]
+; CHECK-NEXT:    ret ptr [[CALL]]
+;
+  %call = call ptr %alloc(i64 16) allocsize(0)
+  ret ptr %call
+}

diff  --git a/llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll b/llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll
index f505eb103d11a..4dd4c00bfc352 100644
--- a/llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll
+++ b/llvm/test/Transforms/InstCombine/out-of-tree-allocator-optimizes-away.ll
@@ -15,6 +15,20 @@ start:
   ret void
 }
 
+define void @alloc_elides_test_virtual(i32 %data, ptr %alloc, ptr %realloc, ptr %dealloc) {
+; CHECK-LABEL: @alloc_elides_test_virtual(
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    ret void
+;
+start:
+  %a = call noalias ptr %alloc(i64 4, i64 allocalign 32) nounwind allocsize(0) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"
+  store i32 0, ptr %a
+  %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"
+  store i32 1, ptr %a2
+  call void %dealloc(ptr allocptr %a2, i64 4, i64 32) nounwind allockind("free") "alloc-family"="__rust_alloc"
+  ret void
+}
+
 declare noalias ptr @__rust_alloc(i64, i64 allocalign) nounwind allocsize(0) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"
 
 declare noalias ptr @__rust_realloc(ptr allocptr, i64, i64 allocalign, i64) nounwind allocsize(3) allockind("alloc,uninitialized,aligned") "alloc-family"="__rust_alloc"


        


More information about the llvm-commits mailing list