[clang] [llvm] [Clang] Add __builtin_assume_dereferenceable to encode deref assumption. (PR #121789)
Florian Hahn via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 13 12:04:44 PST 2025
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/121789
>From b7b0a7a8a04e579c512c13bf114613ced56b8fe5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 6 Jan 2025 13:39:55 +0000
Subject: [PATCH 1/5] [Clang] Add __builtin_assume_dereferenceable to encode
deref assumption.
This patch adds a new __builtin_assume_dereferenceable to encode
dereferenceability of a pointer using llvm.assume with an operand
bundle.
For now the builtin only accepts constant sizes, I am planning to drop
this restriction in a follow-up change.
This can be used to better optimize cases where a pointer is known to be
dereferenceable, e.g. unconditionally loading from p2 when vectorizing the loop.
int *get_ptr();
void foo(int* src, int x) {
int *p2 = get_ptr();
__builtin_assume_aligned(p2, 4);
__builtin_assume_dereferenceable(p2, 4000);
for (unsigned I = 0; I != 1000; ++I) {
int x = src[I];
if (x == 0)
x = p2[I];
src[I] = x;
}
}
---
clang/docs/LanguageExtensions.rst | 35 ++++++++++++++++
clang/include/clang/Basic/Builtins.td | 6 +++
clang/lib/CodeGen/CGBuiltin.cpp | 10 +++++
.../CodeGen/builtin-assume-dereferenceable.c | 34 +++++++++++++++
.../Sema/builtin-assume-dereferenceable.c | 41 +++++++++++++++++++
llvm/include/llvm/IR/IRBuilder.h | 5 +++
llvm/lib/IR/IRBuilder.cpp | 10 +++++
7 files changed, 141 insertions(+)
create mode 100644 clang/test/CodeGen/builtin-assume-dereferenceable.c
create mode 100644 clang/test/Sema/builtin-assume-dereferenceable.c
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 973cf8f9d091c..3e9b9a0a3483a 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2866,6 +2866,41 @@ etc.).
Query for this feature with ``__has_builtin(__builtin_assume_separate_storage)``.
+``__builtin_assume_dereferenceable``
+-------------------------------------
+
+``__builtin_assume_derefernceable`` is used to provide the optimizer with the
+knowledge that the pointer argument P is dereferenceable up to the specified
+number of bytes.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_assume_dereferenceable(const void *, size_t)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ int foo(int *x, int y) {
+ __builtin_assume_dereferenceable(x, 4);
+ int z = 0;
+ if (y == 1) {
+ // The optimizer may execute the load of x unconditionally.
+ z = *x;
+ }
+ return z;
+ }
+
+**Description**:
+
+The arguments to this function provide a start pointer ``P`` and a size ``S``.
+``P`` must be non-null and ``S`` at least 1. The optimizer may assume that
+``S`` bytes are dereferenceable starting at ``P``.
+
+Query for this feature with ``__has_builtin(__builtin_assume_dereferenceable)``.
+
``__builtin_offsetof``
----------------------
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 29939242596ba..398cd3094802f 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -839,6 +839,12 @@ def BuiltinAssumeAligned : Builtin {
let Prototype = "void*(void const*, size_t, ...)";
}
+def BuiltinAssumeDereferenceable : Builtin {
+ let Spellings = ["__builtin_assume_dereferenceable"];
+ let Attributes = [NoThrow, Const, Constexpr];
+ let Prototype = "void(void const*, _Constant size_t)";
+}
+
def BuiltinFree : Builtin {
let Spellings = ["__builtin_free"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 361e4c4bf2e2e..f04c252d10282 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3839,6 +3839,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
AlignmentCI, OffsetValue);
return RValue::get(PtrValue);
}
+ case Builtin::BI__builtin_assume_dereferenceable: {
+ const Expr *Ptr = E->getArg(0);
+ Value *PtrValue = EmitScalarExpr(Ptr);
+ Value *SizeValue = EmitScalarExpr(E->getArg(1));
+ if (SizeValue->getType() != IntPtrTy)
+ SizeValue =
+ Builder.CreateIntCast(SizeValue, IntPtrTy, false, "casted.size");
+ Builder.CreateDereferenceableAssumption(PtrValue, SizeValue);
+ return RValue::get(nullptr);
+ }
case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (E->getArg(0)->HasSideEffects(getContext()))
diff --git a/clang/test/CodeGen/builtin-assume-dereferenceable.c b/clang/test/CodeGen/builtin-assume-dereferenceable.c
new file mode 100644
index 0000000000000..cadffd4a84c26
--- /dev/null
+++ b/clang/test/CodeGen/builtin-assume-dereferenceable.c
@@ -0,0 +1,34 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: @test1(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 10) ]
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test1(int *a) {
+ __builtin_assume_dereferenceable(a, 10);
+ return a[0];
+}
+
+// CHECK-LABEL: @test2(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 32) ]
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test2(int *a) {
+ __builtin_assume_dereferenceable(a, 32ull);
+ return a[0];
+}
diff --git a/clang/test/Sema/builtin-assume-dereferenceable.c b/clang/test/Sema/builtin-assume-dereferenceable.c
new file mode 100644
index 0000000000000..07b23022043cd
--- /dev/null
+++ b/clang/test/Sema/builtin-assume-dereferenceable.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s
+
+int test1(int *a) {
+ __builtin_assume_dereferenceable(a, 32);
+ return a[0];
+}
+
+int test2(int *a) {
+ __builtin_assume_dereferenceable(a, 32ull);
+ return a[0];
+}
+
+int test3(int *a) {
+ __builtin_assume_dereferenceable(a, 32u);
+ return a[0];
+}
+
+int test4(int *a, unsigned size) {
+ a = __builtin_assume_dereferenceable(a, size); // expected-error {{argument to '__builtin_assume_dereferenceable' must be a constant integer}}
+ 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}}
+ return a[0];
+}
+
+int test6(float a) {
+ __builtin_assume_dereferenceable(a, 2); // expected-error {{passing 'float' to parameter of incompatible type 'const void *'}}
+ return 0;;
+}
+
+int test7(int *a) {
+ __builtin_assume_dereferenceable(a, 32, 1); // expected-error {{too many arguments to function call, expected 2, have 3}}
+ return a[0];
+}
+
+int test8(int *a) {
+ __builtin_assume_dereferenceable(a); // expected-error {{too few arguments to function call, expected 2, have 1}}
+ return a[0];
+}
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 1692f7dfb7fa7..7e51a16d51632 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2684,6 +2684,11 @@ class IRBuilderBase {
CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue,
Value *Alignment,
Value *OffsetValue = nullptr);
+
+ /// Create an assume intrinsic call that represents an dereferencable
+ /// assumption on the provided pointer.
+ ///
+ CallInst *CreateDereferenceableAssumption(Value *PtrValue, Value *SizeValue);
};
/// This provides a uniform API for creating instructions and inserting
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index d46ae206890e8..134459265cecb 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -1284,6 +1284,16 @@ CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL,
return CreateAlignmentAssumptionHelper(DL, PtrValue, Alignment, OffsetValue);
}
+CallInst *IRBuilderBase::CreateDereferenceableAssumption(Value *PtrValue,
+ Value *SizeValue) {
+ assert(isa<PointerType>(PtrValue->getType()) &&
+ "trying to create an deferenceable assumption on a non-pointer?");
+ SmallVector<Value *, 4> Vals({PtrValue, SizeValue});
+ OperandBundleDefT<Value *> DereferenceableOpB("dereferenceable", Vals);
+ return CreateAssumption(ConstantInt::getTrue(getContext()),
+ {DereferenceableOpB});
+}
+
IRBuilderDefaultInserter::~IRBuilderDefaultInserter() = default;
IRBuilderCallbackInserter::~IRBuilderCallbackInserter() = default;
IRBuilderFolder::~IRBuilderFolder() = default;
>From 2d2dbab427b5badfa94d8c140d389b2403ac3495 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 8 Jan 2025 12:13:27 +0000
Subject: [PATCH 2/5] !fixup address latest comments, thanks!
---
clang/include/clang/Basic/Builtins.td | 2 +-
clang/lib/CodeGen/CGBuiltin.cpp | 4 +++-
.../CodeGen/builtin-assume-dereferenceable.c | 2 ++
.../builtin-assume-dereferenceable.cpp} | 18 ++++++++++++++++--
llvm/include/llvm/IR/IRBuilder.h | 5 ++++-
llvm/lib/IR/IRBuilder.cpp | 8 ++++++++
6 files changed, 34 insertions(+), 5 deletions(-)
rename clang/test/{Sema/builtin-assume-dereferenceable.c => SemaCXX/builtin-assume-dereferenceable.cpp} (57%)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 398cd3094802f..0e5df338dd2e5 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -841,7 +841,7 @@ def BuiltinAssumeAligned : Builtin {
def BuiltinAssumeDereferenceable : Builtin {
let Spellings = ["__builtin_assume_dereferenceable"];
- let Attributes = [NoThrow, Const, Constexpr];
+ let Attributes = [NoThrow, Const];
let Prototype = "void(void const*, _Constant size_t)";
}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f04c252d10282..4ba1c4fb824a5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3841,12 +3841,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_assume_dereferenceable: {
const Expr *Ptr = E->getArg(0);
+ const Expr *Size= E->getArg(1);
Value *PtrValue = EmitScalarExpr(Ptr);
- Value *SizeValue = EmitScalarExpr(E->getArg(1));
+ Value *SizeValue = EmitScalarExpr(Size);
if (SizeValue->getType() != IntPtrTy)
SizeValue =
Builder.CreateIntCast(SizeValue, IntPtrTy, false, "casted.size");
Builder.CreateDereferenceableAssumption(PtrValue, SizeValue);
+ Builder.CreateNonNullAssumption(PtrValue);
return RValue::get(nullptr);
}
case Builtin::BI__assume:
diff --git a/clang/test/CodeGen/builtin-assume-dereferenceable.c b/clang/test/CodeGen/builtin-assume-dereferenceable.c
index cadffd4a84c26..bf632f6e10182 100644
--- a/clang/test/CodeGen/builtin-assume-dereferenceable.c
+++ b/clang/test/CodeGen/builtin-assume-dereferenceable.c
@@ -7,6 +7,7 @@
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 10) ]
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
@@ -23,6 +24,7 @@ int test1(int *a) {
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 32) ]
+// CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
diff --git a/clang/test/Sema/builtin-assume-dereferenceable.c b/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
similarity index 57%
rename from clang/test/Sema/builtin-assume-dereferenceable.c
rename to clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
index 07b23022043cd..b79b7c059567e 100644
--- a/clang/test/Sema/builtin-assume-dereferenceable.c
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s
+// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s
+// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s -fexperimental-new-constant-interpreter
+
int test1(int *a) {
__builtin_assume_dereferenceable(a, 32);
@@ -26,7 +28,7 @@ int test5(int *a, unsigned long long size) {
}
int test6(float a) {
- __builtin_assume_dereferenceable(a, 2); // expected-error {{passing 'float' to parameter of incompatible type 'const void *'}}
+ __builtin_assume_dereferenceable(a, 2); // expected-error {{cannot initialize a parameter of type 'const void *' with an lvalue of type 'float'}}
return 0;;
}
@@ -39,3 +41,15 @@ int test8(int *a) {
__builtin_assume_dereferenceable(a); // expected-error {{too few arguments to function call, expected 2, have 1}}
return a[0];
}
+
+int test9(int *a) {
+ a[0] = __builtin_assume_dereferenceable(a, 32); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ return a[0];
+}
+
+constexpr int *p = 0;
+constexpr void *l = __builtin_assume_dereferenceable(p, 4); // expected-error {{cannot initialize a variable of type 'void *const' with an rvalue of type 'void'}}
+
+void *foo() {
+ return l;
+}
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 7e51a16d51632..742c16edc1c8a 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2687,8 +2687,11 @@ class IRBuilderBase {
/// Create an assume intrinsic call that represents an dereferencable
/// assumption on the provided pointer.
- ///
CallInst *CreateDereferenceableAssumption(Value *PtrValue, Value *SizeValue);
+
+ /// Create an assume intrinsic call that represents a nonnull assumption
+ /// on the provided pointer.
+ CallInst *CreateNonNullAssumption(Value *PtrValue);
};
/// This provides a uniform API for creating instructions and inserting
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index 134459265cecb..d291c351eb4f7 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -1294,6 +1294,14 @@ CallInst *IRBuilderBase::CreateDereferenceableAssumption(Value *PtrValue,
{DereferenceableOpB});
}
+CallInst *IRBuilderBase::CreateNonNullAssumption(Value *PtrValue) {
+ assert(isa<PointerType>(PtrValue->getType()) &&
+ "trying to create an nonnull assumption on a non-pointer?");
+ SmallVector<Value *, 4> Vals({PtrValue});
+ OperandBundleDefT<Value *> NonNullOpB("nonnull", Vals);
+ return CreateAssumption(ConstantInt::getTrue(getContext()), {NonNullOpB});
+}
+
IRBuilderDefaultInserter::~IRBuilderDefaultInserter() = default;
IRBuilderCallbackInserter::~IRBuilderCallbackInserter() = default;
IRBuilderFolder::~IRBuilderFolder() = default;
>From 6604a4470b9e292bea29d188ae19a20a136240aa Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 8 Jan 2025 13:15:07 +0000
Subject: [PATCH 3/5] !fixup fix formatting
---
clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4ba1c4fb824a5..f2c7027b510e8 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3841,7 +3841,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_assume_dereferenceable: {
const Expr *Ptr = E->getArg(0);
- const Expr *Size= E->getArg(1);
+ const Expr *Size = E->getArg(1);
Value *PtrValue = EmitScalarExpr(Ptr);
Value *SizeValue = EmitScalarExpr(Size);
if (SizeValue->getType() != IntPtrTy)
>From b2e443c8c74346cb11885db6ae6686ad92b0b111 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 9 Jan 2025 21:59:07 +0000
Subject: [PATCH 4/5] !fixup undo nonnull assumption, clarify docs
---
clang/docs/LanguageExtensions.rst | 18 ++++++++++++------
clang/lib/CodeGen/CGBuiltin.cpp | 1 -
.../CodeGen/builtin-assume-dereferenceable.c | 2 --
llvm/include/llvm/IR/IRBuilder.h | 4 ----
4 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 3e9b9a0a3483a..7d27da2386296 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2869,7 +2869,7 @@ Query for this feature with ``__has_builtin(__builtin_assume_separate_storage)``
``__builtin_assume_dereferenceable``
-------------------------------------
-``__builtin_assume_derefernceable`` is used to provide the optimizer with the
+``__builtin_assume_dereferenceable`` is used to provide the optimizer with the
knowledge that the pointer argument P is dereferenceable up to the specified
number of bytes.
@@ -2884,20 +2884,26 @@ number of bytes.
.. code-block:: c++
int foo(int *x, int y) {
- __builtin_assume_dereferenceable(x, 4);
+ __builtin_assume_dereferenceable(x, sizeof(int));
int z = 0;
if (y == 1) {
- // The optimizer may execute the load of x unconditionally.
+ // The optimizer may execute the load of x unconditionally due to
+ // __builtin_assume_dereferenceable guaranteeing sizeof(int) bytes can
+ // be loaded speculatively without trapping.
z = *x;
- }
+ }
return z;
}
**Description**:
The arguments to this function provide a start pointer ``P`` and a size ``S``.
-``P`` must be non-null and ``S`` at least 1. The optimizer may assume that
-``S`` bytes are dereferenceable starting at ``P``.
+``S`` must be at least 1 and a constant. The optimizer may assume that ``S``
+bytes are dereferenceable starting at ``P``. Note that this does not necessarily
+imply that ``P`` is non-null as ``nullptr`` can be dereferenced in some cases.
+The assumption also does not imply that ``P`` is not dereferenceable past ``S``
+bytes.
+
Query for this feature with ``__has_builtin(__builtin_assume_dereferenceable)``.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f2c7027b510e8..61939d1f75ed0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3848,7 +3848,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
SizeValue =
Builder.CreateIntCast(SizeValue, IntPtrTy, false, "casted.size");
Builder.CreateDereferenceableAssumption(PtrValue, SizeValue);
- Builder.CreateNonNullAssumption(PtrValue);
return RValue::get(nullptr);
}
case Builtin::BI__assume:
diff --git a/clang/test/CodeGen/builtin-assume-dereferenceable.c b/clang/test/CodeGen/builtin-assume-dereferenceable.c
index bf632f6e10182..cadffd4a84c26 100644
--- a/clang/test/CodeGen/builtin-assume-dereferenceable.c
+++ b/clang/test/CodeGen/builtin-assume-dereferenceable.c
@@ -7,7 +7,6 @@
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 10) ]
-// CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
@@ -24,7 +23,6 @@ int test1(int *a) {
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 32) ]
-// CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[TMP0]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 0
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 742c16edc1c8a..933dbb306d1fc 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2688,10 +2688,6 @@ class IRBuilderBase {
/// Create an assume intrinsic call that represents an dereferencable
/// assumption on the provided pointer.
CallInst *CreateDereferenceableAssumption(Value *PtrValue, Value *SizeValue);
-
- /// Create an assume intrinsic call that represents a nonnull assumption
- /// on the provided pointer.
- CallInst *CreateNonNullAssumption(Value *PtrValue);
};
/// This provides a uniform API for creating instructions and inserting
>From 2835b3ca2bc80867ab582993c489497c2e69108f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 10 Jan 2025 14:50:05 +0000
Subject: [PATCH 5/5] !fixup address comments, fix builds
---
clang/docs/LanguageExtensions.rst | 4 ++--
llvm/lib/IR/IRBuilder.cpp | 8 --------
2 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 7d27da2386296..2a956ad5b2909 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2870,8 +2870,8 @@ Query for this feature with ``__has_builtin(__builtin_assume_separate_storage)``
-------------------------------------
``__builtin_assume_dereferenceable`` is used to provide the optimizer with the
-knowledge that the pointer argument P is dereferenceable up to the specified
-number of bytes.
+knowledge that the pointer argument P is dereferenceable up to at least the
+specified number of bytes.
**Syntax**:
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index d291c351eb4f7..134459265cecb 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -1294,14 +1294,6 @@ CallInst *IRBuilderBase::CreateDereferenceableAssumption(Value *PtrValue,
{DereferenceableOpB});
}
-CallInst *IRBuilderBase::CreateNonNullAssumption(Value *PtrValue) {
- assert(isa<PointerType>(PtrValue->getType()) &&
- "trying to create an nonnull assumption on a non-pointer?");
- SmallVector<Value *, 4> Vals({PtrValue});
- OperandBundleDefT<Value *> NonNullOpB("nonnull", Vals);
- return CreateAssumption(ConstantInt::getTrue(getContext()), {NonNullOpB});
-}
-
IRBuilderDefaultInserter::~IRBuilderDefaultInserter() = default;
IRBuilderCallbackInserter::~IRBuilderCallbackInserter() = default;
IRBuilderFolder::~IRBuilderFolder() = default;
More information about the cfe-commits
mailing list