From 1752faa8eb0a75b6c2d2121f8de2420fc95bd121 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 22 Jun 2026 19:19:41 +0900 Subject: [PATCH] Add noalias/allocsize attributes to GC allocation runtime functions Mark the returned pointer of _d_allocmemory, _d_allocmemoryT and _d_newclass/_d_allocclass with noalias, and give _d_allocmemory an allocsize(0). This helps alias analysis and enables llvm's objectsize-based optimizations. --- gen/runtime.cpp | 29 +++++++++++++++++++++++++---- tests/codegen/gc_alloc_attrs.d | 24 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 tests/codegen/gc_alloc_attrs.d diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 70f9db81771..c752e17b17f 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -492,7 +492,7 @@ static void buildRuntimeModule() { AttrSet NoAttrs, Attr_NoUnwind, Attr_ReadOnly, Attr_ReadOnly_NoUnwind, Attr_Cold, Attr_Cold_NoReturn, Attr_Cold_NoReturn_NoUnwind, Attr_ReadOnly_1_NoCapture, Attr_ReadOnly_1_3_NoCapture, Attr_ReadOnly_NoUnwind_1_NoCapture, Attr_ReadOnly_NoUnwind_1_2_NoCapture, Attr_1_NoCapture, Attr_1_2_NoCapture, Attr_1_3_NoCapture, - Attr_1_4_NoCapture; + Attr_1_4_NoCapture, Attr_NoAlias_Return, Attr_NoAlias_Return_AllocSize0; // `nounwind` { auto addNoUnwind = [&](AttrSet& a) { @@ -541,6 +541,25 @@ static void buildRuntimeModule() { addNoReturn(Attr_Cold_NoReturn); addNoReturn(Attr_Cold_NoReturn_NoUnwind); } + // `noalias` on the returned pointer of GC allocation functions: each call + // hands back freshly allocated memory that does not alias any pre-existing + // pointer (malloc-like semantics). + { + auto addNoAliasReturn = [&](AttrSet& a) { + llvm::AttrBuilder ab(context); + ab.addAttribute(llvm::Attribute::NoAlias); + a.addToReturn(ab); + }; + addNoAliasReturn(Attr_NoAlias_Return); + addNoAliasReturn(Attr_NoAlias_Return_AllocSize0); + } + // `allocsize`: `_d_allocmemory(size_t sz)` returns a block of `sz` bytes + // (size given by parameter 0), enabling llvm.objectsize-based optimizations. + { + llvm::AttrBuilder ab(context); + ab.addAllocSizeAttr(0, std::nullopt); + Attr_NoAlias_Return_AllocSize0.addToFunction(ab); + } // `nocapture`/ `captures(none)` { auto addCapturesNone = [&](int extra, AttrSet& a) { @@ -608,10 +627,12 @@ static void buildRuntimeModule() { ////////////////////////////////////////////////////////////////////////////// // void* _d_allocmemory(size_t sz) - createFwdDecl(LINK::c, voidPtrTy, {"_d_allocmemory"}, {sizeTy}); + createFwdDecl(LINK::c, voidPtrTy, {"_d_allocmemory"}, {sizeTy}, {}, + Attr_NoAlias_Return_AllocSize0); // void* _d_allocmemoryT(TypeInfo ti) - createFwdDecl(LINK::c, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}); + createFwdDecl(LINK::c, voidPtrTy, {"_d_allocmemoryT"}, {typeInfoTy}, {}, + Attr_NoAlias_Return); // void[] _d_newarrayT (const TypeInfo ti, size_t length) // void[] _d_newarrayiT(const TypeInfo ti, size_t length) @@ -628,7 +649,7 @@ static void buildRuntimeModule() { // Object _d_newclass(const ClassInfo ci) // Object _d_allocclass(const ClassInfo ci) createFwdDecl(LINK::c, objectTy, {"_d_newclass", "_d_allocclass"}, - {classInfoTy}, {STCconst}); + {classInfoTy}, {STCconst}, Attr_NoAlias_Return); // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) createFwdDecl(LINK::c, voidTy, {"_d_delarray_t"}, diff --git a/tests/codegen/gc_alloc_attrs.d b/tests/codegen/gc_alloc_attrs.d new file mode 100644 index 00000000000..5354968e689 --- /dev/null +++ b/tests/codegen/gc_alloc_attrs.d @@ -0,0 +1,24 @@ +// RUN: %ldc -O0 -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +// CHECK-DAG: declare noalias ptr @_d_allocclass( +// CHECK-DAG: declare noalias ptr @_d_allocmemoryT( +// CHECK-DAG: declare noalias ptr @_d_allocmemory({{i32|i64}}){{.*}} #[[ALLOC:[0-9]+]] + +// CHECK-DAG: attributes #[[ALLOC]] = {{.*}}allocsize(0) + +class C { int x; } + +C makeClass() +{ + return new C(); +} + +int* makeInt() +{ + return new int; +} + +int delegate() makeClosure(int x) +{ + return () => x; +}