Author: Florian Hahn
Date: 2025-09-05T14:51:54Z
New Revision: c8d065bf914d7c8feb06aa7978fe43b2a800b17f

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

LOG: [Clang] Allow non-constant sizes for __builtin_assume_dereferenceable. 
(#156929)

Update Clang's __builtin_assume_dereferenceable to support non-constant
lengths. The corresponding assume bundle has been updated to support
non-constant sizes in cad62df49a7.

The current docs for the builtin don't mention the constant requirement
for the size argument, so don't need to be updated:
https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume-dereferenceable

A number of patches landed recently to make the optimizer make better
use of the dereferenceable assumptions, and once
https://github.com/llvm/llvm-project/pull/156730 lands, it can be used
to vectorize some early-exit loops, for example std::find with
std::vector::iterator: https://godbolt.org/z/qo58PKG37
```
  #include <algorithm>
  #include <cstddef>
  #include <vector>

  auto find(std::vector<short>::iterator first, short s, unsigned size) {
    auto Addr = __builtin_assume_aligned(std::to_address(first),  2);
    __builtin_assume_dereferenceable(std::to_address(first), size * 
sizeof(short));
    return std::find(first, first + size, s);
  }
```

PR: https://github.com/llvm/llvm-project/pull/156929

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/Builtins.td
    clang/test/CodeGen/builtin-assume-dereferenceable.c
    clang/test/SemaCXX/builtin-assume-dereferenceable.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8522f4123cd97..8720262c33959 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -206,6 +206,7 @@ Non-comprehensive list of changes in this release
   Currently, the use of ``__builtin_dedup_pack`` is limited to template 
arguments and base
   specifiers, it also must be used within a template context.
 
+- ``__builtin_assume_dereferenceable`` now accepts non-constant size operands.
 
 New Compiler Flags
 ------------------

diff  --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 27fc6f008d743..27639f06529cb 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -854,7 +854,7 @@ def BuiltinAssumeAligned : Builtin {
 def BuiltinAssumeDereferenceable : Builtin {
   let Spellings = ["__builtin_assume_dereferenceable"];
   let Attributes = [NoThrow, Const];
-  let Prototype = "void(void const*, _Constant size_t)";
+  let Prototype = "void(void const*, size_t)";
 }
 
 def BuiltinFree : Builtin {

diff  --git a/clang/test/CodeGen/builtin-assume-dereferenceable.c 
b/clang/test/CodeGen/builtin-assume-dereferenceable.c
index cadffd4a84c26..0dc4ba089ee3a 100644
--- a/clang/test/CodeGen/builtin-assume-dereferenceable.c
+++ b/clang/test/CodeGen/builtin-assume-dereferenceable.c
@@ -32,3 +32,62 @@ int test2(int *a) {
   __builtin_assume_dereferenceable(a, 32ull);
   return a[0];
 }
+
+// CHECK-LABEL: @test3(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[N_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    store i32 [[N:%.*]], ptr [[N_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP1]] to i64
+// CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
[[TMP0]], i64 [[CONV]]) ]
+// CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], 
i64 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT:    ret i32 [[TMP3]]
+//
+int test3(int *a, int n) {
+  __builtin_assume_dereferenceable(a, n);
+  return a[0];
+}
+
+// CHECK-LABEL: @test4(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[N_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    store i64 [[N:%.*]], ptr [[N_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr [[N_ADDR]], align 8
+// CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
[[TMP0]], i64 [[TMP1]]) ]
+// CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], 
i64 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT:    ret i32 [[TMP3]]
+//
+int test4(int *a, unsigned long long n) {
+  __builtin_assume_dereferenceable(a, n);
+  return a[0];
+}
+
+// CHECK-LABEL: @test5(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[N_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    store float [[N:%.*]], ptr [[N_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[N_ADDR]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptoui float [[TMP1]] to i64
+// CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
[[TMP0]], i64 [[CONV]]) ]
+// CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], 
i64 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT:    ret i32 [[TMP3]]
+//
+int test5(int *a, float n) {
+  __builtin_assume_dereferenceable(a, n);
+  return a[0];
+}

diff  --git a/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp 
b/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
index b79b7c059567e..2cbd7ac3507bf 100644
--- a/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
@@ -18,12 +18,12 @@ int test3(int *a) {
 }
 
 int test4(int *a, unsigned size) {
-  a = __builtin_assume_dereferenceable(a, size); // expected-error {{argument 
to '__builtin_assume_dereferenceable' must be a constant integer}}
+  __builtin_assume_dereferenceable(a, size);
   return a[0];
 }
 
 int test5(int *a, unsigned long long size) {
-  a = __builtin_assume_dereferenceable(a, size); // expected-error {{argument 
to '__builtin_assume_dereferenceable' must be a constant integer}}
+  __builtin_assume_dereferenceable(a, size);
   return a[0];
 }
 
@@ -53,3 +53,8 @@ constexpr void *l = __builtin_assume_dereferenceable(p, 4); 
// expected-error {{
 void *foo() {
   return l;
 }
+
+int test10(int *a) {
+  __builtin_assume_dereferenceable(a, a); // expected-error {{cannot 
initialize a parameter of type '__size_t' (aka 'unsigned long') with an lvalue 
of type 'int *'}}
+  return a[0];
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to