Skip to content

Commit c8d065b

Browse files
authored
[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 cad62df. 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 #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: #156929
1 parent ef1539c commit c8d065b

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ Non-comprehensive list of changes in this release
206206
Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base
207207
specifiers, it also must be used within a template context.
208208

209+
- ``__builtin_assume_dereferenceable`` now accepts non-constant size operands.
209210

210211
New Compiler Flags
211212
------------------

clang/include/clang/Basic/Builtins.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ def BuiltinAssumeAligned : Builtin {
854854
def BuiltinAssumeDereferenceable : Builtin {
855855
let Spellings = ["__builtin_assume_dereferenceable"];
856856
let Attributes = [NoThrow, Const];
857-
let Prototype = "void(void const*, _Constant size_t)";
857+
let Prototype = "void(void const*, size_t)";
858858
}
859859

860860
def BuiltinFree : Builtin {

clang/test/CodeGen/builtin-assume-dereferenceable.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,62 @@ int test2(int *a) {
3232
__builtin_assume_dereferenceable(a, 32ull);
3333
return a[0];
3434
}
35+
36+
// CHECK-LABEL: @test3(
37+
// CHECK-NEXT: entry:
38+
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
39+
// CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
40+
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
41+
// CHECK-NEXT: store i32 [[N:%.*]], ptr [[N_ADDR]], align 4
42+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
43+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[N_ADDR]], align 4
44+
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP1]] to i64
45+
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 [[CONV]]) ]
46+
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
47+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 0
48+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
49+
// CHECK-NEXT: ret i32 [[TMP3]]
50+
//
51+
int test3(int *a, int n) {
52+
__builtin_assume_dereferenceable(a, n);
53+
return a[0];
54+
}
55+
56+
// CHECK-LABEL: @test4(
57+
// CHECK-NEXT: entry:
58+
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
59+
// CHECK-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
60+
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
61+
// CHECK-NEXT: store i64 [[N:%.*]], ptr [[N_ADDR]], align 8
62+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
63+
// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[N_ADDR]], align 8
64+
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 [[TMP1]]) ]
65+
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
66+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 0
67+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
68+
// CHECK-NEXT: ret i32 [[TMP3]]
69+
//
70+
int test4(int *a, unsigned long long n) {
71+
__builtin_assume_dereferenceable(a, n);
72+
return a[0];
73+
}
74+
75+
// CHECK-LABEL: @test5(
76+
// CHECK-NEXT: entry:
77+
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
78+
// CHECK-NEXT: [[N_ADDR:%.*]] = alloca float, align 4
79+
// CHECK-NEXT: store ptr [[A:%.*]], ptr [[A_ADDR]], align 8
80+
// CHECK-NEXT: store float [[N:%.*]], ptr [[N_ADDR]], align 4
81+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
82+
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[N_ADDR]], align 4
83+
// CHECK-NEXT: [[CONV:%.*]] = fptoui float [[TMP1]] to i64
84+
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP0]], i64 [[CONV]]) ]
85+
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
86+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 0
87+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
88+
// CHECK-NEXT: ret i32 [[TMP3]]
89+
//
90+
int test5(int *a, float n) {
91+
__builtin_assume_dereferenceable(a, n);
92+
return a[0];
93+
}

clang/test/SemaCXX/builtin-assume-dereferenceable.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ int test3(int *a) {
1818
}
1919

2020
int test4(int *a, unsigned size) {
21-
a = __builtin_assume_dereferenceable(a, size); // expected-error {{argument to '__builtin_assume_dereferenceable' must be a constant integer}}
21+
__builtin_assume_dereferenceable(a, size);
2222
return a[0];
2323
}
2424

2525
int test5(int *a, unsigned long long size) {
26-
a = __builtin_assume_dereferenceable(a, size); // expected-error {{argument to '__builtin_assume_dereferenceable' must be a constant integer}}
26+
__builtin_assume_dereferenceable(a, size);
2727
return a[0];
2828
}
2929

@@ -53,3 +53,8 @@ constexpr void *l = __builtin_assume_dereferenceable(p, 4); // expected-error {{
5353
void *foo() {
5454
return l;
5555
}
56+
57+
int test10(int *a) {
58+
__builtin_assume_dereferenceable(a, a); // expected-error {{cannot initialize a parameter of type '__size_t' (aka 'unsigned long') with an lvalue of type 'int *'}}
59+
return a[0];
60+
}

0 commit comments

Comments
 (0)