@@ -111,36 +111,89 @@ pub const unsafe fn unreachable_unchecked() -> ! {
111
111
112
112
/// Makes a *soundness* promise to the compiler that `cond` holds.
113
113
///
114
- /// This may allow the optimizer to simplify things,
115
- /// but it might also make the generated code slower.
116
- /// Either way, calling it will most likely make compilation take longer.
114
+ /// This may allow the optimizer to simplify things, but it might also make the generated code
115
+ /// slower. Either way, calling it will most likely make compilation take longer.
117
116
///
118
- /// This is a situational tool for micro-optimization, and is allowed to do nothing.
119
- /// Any use should come with a repeatable benchmark to show the value
120
- /// and allow removing it later should the optimizer get smarter and no longer need it .
117
+ /// You may know this from other places as
118
+ /// [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C,
119
+ /// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume) .
121
120
///
122
- /// The more complicated the condition the less likely this is to be fruitful.
123
- /// For example, `assert_unchecked(foo.is_sorted())` is a complex enough value
124
- /// that the compiler is unlikely to be able to take advantage of it.
121
+ /// This promotes a correctness requirement to a soundness requirement. Don't do that without
122
+ /// very good reason.
125
123
///
126
- /// There's also no need to `assert_unchecked` basic properties of things. For
127
- /// example, the compiler already knows the range of `count_ones`, so there's no
128
- /// benefit to `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`.
124
+ /// # Usage
129
125
///
130
- /// If ever you're tempted to write `assert_unchecked(false)`, then you're
131
- /// actually looking for [`unreachable_unchecked()`].
126
+ /// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use
127
+ /// should come with a repeatable benchmark to show the value, with the expectation to drop it
128
+ /// later should the optimizer get smarter and no longer need it.
132
129
///
133
- /// You may know this from other places
134
- /// as [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic)
135
- /// or [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume) .
130
+ /// The more complicated the condition, the less likely this is to be useful. For example,
131
+ /// `assert_unchecked(foo.is_sorted())` is a complex enough value that the compiler is unlikely
132
+ /// to be able to take advantage of it .
136
133
///
137
- /// This promotes a correctness requirement to a soundness requirement.
138
- /// Don't do that without very good reason.
134
+ /// There's also no need to `assert_unchecked` basic properties of things. For example, the
135
+ /// compiler already knows the range of `count_ones`, so there is no benefit to
136
+ /// `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`.
137
+ ///
138
+ /// `assert_unchecked` is logically equivalent to `if !cond { unreachable_unchecked(); }`. If
139
+ /// ever you are tempted to write `assert_unchecked(false)`, you should instead use
140
+ /// [`unreachable_unchecked()`] directly.
139
141
///
140
142
/// # Safety
141
143
///
142
- /// `cond` must be `true`. It's immediate UB to call this with `false`.
144
+ /// `cond` must be `true`. It is immediate UB to call this with `false`.
145
+ ///
146
+ /// # Example
147
+ ///
148
+ /// ```
149
+ /// #![feature(hint_assert_unchecked)]
150
+ ///
151
+ /// use core::hint;
152
+ ///
153
+ /// /// # Safety
154
+ /// ///
155
+ /// /// `p` must be nonnull and valid
156
+ /// pub unsafe fn next_value(p: *const i32) -> i32 {
157
+ /// // SAFETY: caller invariants guarantee that `p` is not null
158
+ /// unsafe { hint::assert_unchecked(!p.is_null()) }
159
+ ///
160
+ /// if p.is_null() {
161
+ /// return -1;
162
+ /// } else {
163
+ /// // SAFETY: caller invariants guarantee that `p` is valid
164
+ /// unsafe { *p + 1 }
165
+ /// }
166
+ /// }
167
+ /// ```
168
+ ///
169
+ /// Without the `assert_unchecked`, the above function produces the following with optimizations
170
+ /// enabled:
171
+ ///
172
+ /// ```asm
173
+ /// next_value:
174
+ /// test rdi, rdi
175
+ /// je .LBB0_1
176
+ /// mov eax, dword ptr [rdi]
177
+ /// inc eax
178
+ /// ret
179
+ /// .LBB0_1:
180
+ /// mov eax, -1
181
+ /// ret
182
+ /// ```
183
+ ///
184
+ /// Adding the assertion allows the optimizer to remove the extra check:
185
+ ///
186
+ /// ```asm
187
+ /// next_value:
188
+ /// mov eax, dword ptr [rdi]
189
+ /// inc eax
190
+ /// ret
191
+ /// ```
143
192
///
193
+ /// This example is quite unlike anything that would be used in the real world: it is redundant
194
+ /// to put an an assertion right next to code that checks the same thing, and dereferencing a
195
+ /// pointer already has the builtin assumption that it is nonnull. However, it illustrates the
196
+ /// kind of changes the optimizer can make even when the behavior is less obviously related.
144
197
#[ inline( always) ]
145
198
#[ doc( alias = "assume" ) ]
146
199
#[ track_caller]
0 commit comments