Skip to main content

core/stdarch/crates/core_arch/src/amdgpu/
mod.rs

1//! amdgpu intrinsics
2//!
3//! The reference is the [LLVM amdgpu guide] and the [LLVM implementation].
4//! The order of intrinsics here follows the order in the [LLVM implementation].
5//!
6//! [LLVM amdgpu guide]: https://llvm.org/docs/AMDGPUUsage.html#llvm-ir-intrinsics
7//! [LLVM implementation]: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
8
9#[allow(improper_ctypes)]
10unsafe extern "unadjusted" {
11    #[link_name = "llvm.amdgcn.workitem.id.x"]
12    safe fn llvm_workitem_id_x() -> u32;
13    #[link_name = "llvm.amdgcn.workitem.id.y"]
14    safe fn llvm_workitem_id_y() -> u32;
15    #[link_name = "llvm.amdgcn.workitem.id.z"]
16    safe fn llvm_workitem_id_z() -> u32;
17
18    #[link_name = "llvm.amdgcn.workgroup.id.x"]
19    safe fn llvm_workgroup_id_x() -> u32;
20    #[link_name = "llvm.amdgcn.workgroup.id.y"]
21    safe fn llvm_workgroup_id_y() -> u32;
22    #[link_name = "llvm.amdgcn.workgroup.id.z"]
23    safe fn llvm_workgroup_id_z() -> u32;
24
25    #[link_name = "llvm.amdgcn.groupstaticsize"]
26    safe fn llvm_groupstaticsize() -> u32;
27    #[link_name = "llvm.amdgcn.dispatch.id"]
28    safe fn llvm_dispatch_id() -> u64;
29
30    #[link_name = "llvm.amdgcn.wavefrontsize"]
31    safe fn llvm_wavefrontsize() -> u32;
32
33    #[link_name = "llvm.amdgcn.s.barrier"]
34    safe fn llvm_s_barrier();
35    #[link_name = "llvm.amdgcn.s.barrier.signal"]
36    fn llvm_s_barrier_signal(barrier_type: i32);
37    #[link_name = "llvm.amdgcn.s.barrier.signal.isfirst"]
38    fn llvm_s_barrier_signal_isfirst(barrier_type: i32) -> bool;
39    #[link_name = "llvm.amdgcn.s.barrier.wait"]
40    fn llvm_s_barrier_wait(barrier_type: i16);
41    #[link_name = "llvm.amdgcn.s.get.barrier.state"]
42    fn llvm_s_get_barrier_state(barrier_type: i32) -> u32;
43    #[link_name = "llvm.amdgcn.wave.barrier"]
44    safe fn llvm_wave_barrier();
45    #[link_name = "llvm.amdgcn.sched.barrier"]
46    fn llvm_sched_barrier(mask: u32);
47    #[link_name = "llvm.amdgcn.sched.group.barrier"]
48    fn llvm_sched_group_barrier(mask: u32, size: u32, sync_id: u32);
49
50    #[link_name = "llvm.amdgcn.s.sleep"]
51    safe fn llvm_s_sleep(count: u32);
52
53    #[link_name = "llvm.amdgcn.s.sethalt"]
54    safe fn llvm_s_sethalt(value: u32) -> !;
55
56    #[link_name = "llvm.amdgcn.s.getpc"]
57    safe fn llvm_s_getpc() -> i64;
58
59    #[link_name = "llvm.amdgcn.mbcnt.lo"]
60    safe fn llvm_mbcnt_lo(value: u32, init: u32) -> u32;
61    #[link_name = "llvm.amdgcn.mbcnt.hi"]
62    safe fn llvm_mbcnt_hi(value: u32, init: u32) -> u32;
63
64    #[link_name = "llvm.amdgcn.ballot"]
65    safe fn llvm_ballot(b: bool) -> u64;
66
67    #[link_name = "llvm.amdgcn.inverse.ballot"]
68    safe fn llvm_inverse_ballot(value: u64) -> bool;
69
70    #[link_name = "llvm.amdgcn.wave.reduce.umin"]
71    safe fn llvm_wave_reduce_umin(value: u32, strategy: u32) -> u32;
72    #[link_name = "llvm.amdgcn.wave.reduce.min"]
73    safe fn llvm_wave_reduce_min(value: i32, strategy: u32) -> i32;
74    #[link_name = "llvm.amdgcn.wave.reduce.umax"]
75    safe fn llvm_wave_reduce_umax(value: u32, strategy: u32) -> u32;
76    #[link_name = "llvm.amdgcn.wave.reduce.max"]
77    safe fn llvm_wave_reduce_max(value: i32, strategy: u32) -> i32;
78    #[link_name = "llvm.amdgcn.wave.reduce.add"]
79    safe fn llvm_wave_reduce_add(value: u32, strategy: u32) -> u32;
80    #[link_name = "llvm.amdgcn.wave.reduce.and"]
81    safe fn llvm_wave_reduce_and(value: u32, strategy: u32) -> u32;
82    #[link_name = "llvm.amdgcn.wave.reduce.or"]
83    safe fn llvm_wave_reduce_or(value: u32, strategy: u32) -> u32;
84    #[link_name = "llvm.amdgcn.wave.reduce.xor"]
85    safe fn llvm_wave_reduce_xor(value: u32, strategy: u32) -> u32;
86
87    // The following intrinsics can have multiple sizes
88
89    #[link_name = "llvm.amdgcn.readfirstlane.i32"]
90    safe fn llvm_readfirstlane_u32(value: u32) -> u32;
91    #[link_name = "llvm.amdgcn.readfirstlane.i64"]
92    safe fn llvm_readfirstlane_u64(value: u64) -> u64;
93    #[link_name = "llvm.amdgcn.readlane.i32"]
94    fn llvm_readlane_u32(value: u32, lane: u32) -> u32;
95    #[link_name = "llvm.amdgcn.readlane.i64"]
96    fn llvm_readlane_u64(value: u64, lane: u32) -> u64;
97    #[link_name = "llvm.amdgcn.writelane.i32"]
98    fn llvm_writelane_u32(value: u32, lane: u32, default: u32) -> u32;
99    #[link_name = "llvm.amdgcn.writelane.i64"]
100    fn llvm_writelane_u64(value: u64, lane: u32, default: u64) -> u64;
101
102    #[link_name = "llvm.amdgcn.endpgm"]
103    safe fn llvm_endpgm() -> !;
104
105    #[link_name = "llvm.amdgcn.update.dpp.i32"]
106    fn llvm_update_dpp(
107        old: u32,
108        src: u32,
109        dpp_ctrl: u32,
110        row_mask: u32,
111        bank_mask: u32,
112        bound_control: bool,
113    ) -> u32;
114
115    #[link_name = "llvm.amdgcn.s.memrealtime"]
116    safe fn llvm_s_memrealtime() -> u64;
117
118    #[link_name = "llvm.amdgcn.ds.permute"]
119    fn llvm_ds_permute(lane: u32, value: u32) -> u32;
120    #[link_name = "llvm.amdgcn.ds.bpermute"]
121    fn llvm_ds_bpermute(lane: u32, value: u32) -> u32;
122    #[link_name = "llvm.amdgcn.perm"]
123    fn llvm_perm(src0: u32, src1: u32, selector: u32) -> u32;
124
125    // gfx10
126    #[link_name = "llvm.amdgcn.permlane16.i32"]
127    fn llvm_permlane16_u32(
128        old: u32,
129        src0: u32,
130        src1: u32,
131        src2: u32,
132        fi: bool,
133        bound_control: bool,
134    ) -> u32;
135
136    // gfx10
137    #[link_name = "llvm.amdgcn.permlanex16.i32"]
138    fn llvm_permlanex16_u32(
139        old: u32,
140        src0: u32,
141        src1: u32,
142        src2: u32,
143        fi: bool,
144        bound_control: bool,
145    ) -> u32;
146
147    #[link_name = "llvm.amdgcn.s.get.waveid.in.workgroup"]
148    safe fn llvm_s_get_waveid_in_workgroup() -> u32;
149
150    // gfx11
151    #[link_name = "llvm.amdgcn.permlane64.i32"]
152    fn llvm_permlane64_u32(value: u32) -> u32;
153
154    // gfx12
155    #[link_name = "llvm.amdgcn.permlane16.var"]
156    fn llvm_permlane16_var(old: u32, src0: u32, src1: u32, fi: bool, bound_control: bool) -> u32;
157
158    // gfx12
159    #[link_name = "llvm.amdgcn.permlanex16.var"]
160    fn llvm_permlanex16_var(old: u32, src0: u32, src1: u32, fi: bool, bound_control: bool) -> u32;
161
162    #[link_name = "llvm.amdgcn.wave.id"]
163    safe fn llvm_wave_id() -> u32;
164
165    // gfx950
166    #[link_name = "llvm.amdgcn.permlane16.swap"]
167    fn llvm_permlane16_swap(
168        vdst_old: u32,
169        vsrc_src0: u32,
170        fi: bool,
171        bound_control: bool,
172    ) -> (u32, u32);
173
174    // gfx950
175    #[link_name = "llvm.amdgcn.permlane32.swap"]
176    fn llvm_permlane32_swap(
177        vdst_old: u32,
178        vsrc_src0: u32,
179        fi: bool,
180        bound_control: bool,
181    ) -> (u32, u32);
182}
183
184/// Returns the x coordinate of the workitem index within the workgroup.
185#[inline]
186#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
187pub fn workitem_id_x() -> u32 {
188    llvm_workitem_id_x()
189}
190/// Returns the y coordinate of the workitem index within the workgroup.
191#[inline]
192#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
193pub fn workitem_id_y() -> u32 {
194    llvm_workitem_id_y()
195}
196/// Returns the z coordinate of the workitem index within the workgroup.
197#[inline]
198#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
199pub fn workitem_id_z() -> u32 {
200    llvm_workitem_id_z()
201}
202
203/// Returns the x coordinate of the workgroup index within the dispatch.
204#[inline]
205#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
206pub fn workgroup_id_x() -> u32 {
207    llvm_workgroup_id_x()
208}
209/// Returns the y coordinate of the workgroup index within the dispatch.
210#[inline]
211#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
212pub fn workgroup_id_y() -> u32 {
213    llvm_workgroup_id_y()
214}
215/// Returns the z coordinate of the workgroup index within the dispatch.
216#[inline]
217#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
218pub fn workgroup_id_z() -> u32 {
219    llvm_workgroup_id_z()
220}
221
222/// Returns the size of statically allocated shared memory for this program in bytes.
223#[inline]
224#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
225pub fn groupstaticsize() -> u32 {
226    llvm_groupstaticsize()
227}
228/// Returns the id of the dispatch that is currently executed.
229#[inline]
230#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
231pub fn dispatch_id() -> u64 {
232    llvm_dispatch_id()
233}
234
235/// Returns the number of threads in a wavefront.
236///
237/// Is always a power of 2.
238#[inline]
239#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
240pub fn wavefrontsize() -> u32 {
241    llvm_wavefrontsize()
242}
243
244/// Synchronize all wavefronts in a workgroup.
245///
246/// Each wavefronts in a workgroup waits at the barrier until all wavefronts in the workgroup arrive at a barrier.
247///
248#[doc = include_str!("intrinsic_is_convergent.md")]
249#[inline]
250#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
251pub fn s_barrier() {
252    llvm_s_barrier()
253}
254
255/// Signal a specific barrier type.
256///
257/// Only for non-named barriers.
258///
259#[doc = include_str!("intrinsic_is_convergent.md")]
260#[inline]
261#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
262pub unsafe fn s_barrier_signal<const BARRIER_TYPE: i32>() {
263    unsafe { llvm_s_barrier_signal(BARRIER_TYPE) }
264}
265
266/// Signal a specific barrier type.
267///
268/// Only for non-named barriers.
269/// Provides access to the s_barrier_signal_first instruction;
270/// additionally ensures that the result value is valid even when
271/// the intrinsic is used from a wavefront that is not running in a workgroup.
272///
273#[doc = include_str!("intrinsic_is_convergent.md")]
274#[inline]
275#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
276pub unsafe fn s_barrier_signal_isfirst<const BARRIER_TYPE: i32>() -> bool {
277    unsafe { llvm_s_barrier_signal_isfirst(BARRIER_TYPE) }
278}
279
280/// Wait for a specific barrier type.
281///
282/// Only for non-named barriers.
283///
284#[doc = include_str!("intrinsic_is_convergent.md")]
285#[inline]
286#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
287pub unsafe fn s_barrier_wait<const BARRIER_TYPE: i16>() {
288    unsafe { llvm_s_barrier_wait(BARRIER_TYPE) }
289}
290
291/// Get the state of a specific barrier type.
292///
293/// The `barrier_type` argument must be uniform, otherwise behavior is undefined.
294///
295#[doc = include_str!("intrinsic_is_convergent.md")]
296#[inline]
297#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
298pub unsafe fn s_get_barrier_state<const BARRIER_TYPE: i32>() -> u32 {
299    unsafe { llvm_s_get_barrier_state(BARRIER_TYPE) }
300}
301
302/// A barrier for only the threads within the current wavefront.
303///
304/// Does not result in an instruction but restricts the compiler.
305///
306#[doc = include_str!("intrinsic_is_convergent.md")]
307#[inline]
308#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
309pub fn wave_barrier() {
310    llvm_wave_barrier()
311}
312
313/// Prevent movement of some instruction types.
314///
315/// Controls the types of instructions that may be allowed to cross the intrinsic during instruction scheduling.
316/// The parameter is a mask for the instruction types that can cross the intrinsic.
317///
318/// - 0x0000: No instructions may be scheduled across `sched_barrier`.
319/// - 0x0001: All, non-memory, non-side-effect producing instructions may be scheduled across `sched_barrier`, i.e. allow ALU instructions to pass.
320/// - 0x0002: VALU instructions may be scheduled across `sched_barrier`.
321/// - 0x0004: SALU instructions may be scheduled across `sched_barrier`.
322/// - 0x0008: MFMA/WMMA instructions may be scheduled across `sched_barrier`.
323/// - 0x0010: All VMEM instructions may be scheduled across `sched_barrier`.
324/// - 0x0020: VMEM read instructions may be scheduled across `sched_barrier`.
325/// - 0x0040: VMEM write instructions may be scheduled across `sched_barrier`.
326/// - 0x0080: All DS instructions may be scheduled across `sched_barrier`.
327/// - 0x0100: All DS read instructions may be scheduled across `sched_barrier`.
328/// - 0x0200: All DS write instructions may be scheduled across `sched_barrier`.
329/// - 0x0400: All Transcendental (e.g. V_EXP) instructions may be scheduled across `sched_barrier`.
330///
331#[doc = include_str!("intrinsic_is_convergent.md")]
332#[inline]
333#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
334pub unsafe fn sched_barrier<const MASK: u32>() {
335    static_assert_uimm_bits!(MASK, 11);
336    unsafe { llvm_sched_barrier(MASK) }
337}
338
339/// Creates schedule groups with specific properties to create custom scheduling pipelines.
340///
341/// The ordering between groups is enforced by the instruction scheduler.
342/// The intrinsic applies to the code that precedes the intrinsic.
343/// The intrinsic takes three values that control the behavior of the schedule groups.
344///
345/// - `mask`: Classify instruction groups using the [`sched_barrier`] mask values.
346/// - `size`: The number of instructions that are in the group.
347/// - `sync_id`: Order is enforced between groups with matching values.
348///
349/// The mask can include multiple instruction types. It is undefined behavior to set values beyond the range of valid masks.
350///
351/// Combining multiple `sched_group_barrier` intrinsics enables an ordering of specific instruction types during instruction scheduling.
352/// For example, the following enforces a sequence of 1 VMEM read, followed by 1 VALU instruction, followed by 5 MFMA instructions.
353///
354/// ```ignore (only available on AMD)
355/// // 1 VMEM read
356/// sched_group_barrier::<32, 1, 0>();
357/// // 1 VALU
358/// sched_group_barrier::<2, 1, 0>();
359/// // 5 MFMA
360/// sched_group_barrier::<8, 5, 0>();
361/// ```
362///
363#[doc(cfg(target_arch = "amdgpu"))]
364#[doc = include_str!("intrinsic_is_convergent.md")]
365#[inline]
366#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
367pub unsafe fn sched_group_barrier<const MASK: u32, const SIZE: u32, const SYNC_ID: u32>() {
368    static_assert_uimm_bits!(MASK, 11);
369    unsafe { llvm_sched_group_barrier(MASK, SIZE, SYNC_ID) }
370}
371
372/// Sleeps for approximately `COUNT * 64` cycles.
373///
374/// `COUNT` must be a constant.
375/// Only the lower 7 bits of `COUNT` are used.
376/// If `COUNT == 0x8000`, sleep forever until woken up, or killed.
377#[inline]
378#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
379pub fn s_sleep<const COUNT: u32>() {
380    llvm_s_sleep(COUNT)
381}
382
383/// Stop execution of the kernel.
384///
385/// This usually signals an error state.
386///
387#[doc = include_str!("intrinsic_is_convergent.md")]
388#[inline]
389#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
390pub fn s_sethalt<const VALUE: u32>() -> ! {
391    static_assert_uimm_bits!(VALUE, 3);
392    llvm_s_sethalt(VALUE)
393}
394
395/// Returns the current process counter.
396///
397/// Provides access to the s_getpc_b64 instruction, but with the return value sign-extended
398/// from the width of the underlying PC hardware register even on processors where the
399/// s_getpc_b64 instruction returns a zero-extended value.
400#[inline]
401#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
402pub fn s_getpc() -> i64 {
403    llvm_s_getpc()
404}
405
406/// Masked bit count, low 32 lanes.
407///
408/// Computes the number of bits set in `value`, masked with a thread mask
409/// which contains 1 for all active threads less than the current thread within a wavefront.
410/// `init` is added to the result.
411#[inline]
412#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
413pub fn mbcnt_lo(value: u32, init: u32) -> u32 {
414    llvm_mbcnt_lo(value, init)
415}
416/// Masked bit count, high 32 lanes.
417///
418/// Computes the number of bits set in `value`, masked with a thread mask
419/// which contains 1 for all active threads less than the current thread within a wavefront.
420/// `init` is added to the result.
421#[inline]
422#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
423pub fn mbcnt_hi(value: u32, init: u32) -> u32 {
424    llvm_mbcnt_hi(value, init)
425}
426
427/// Returns a bitfield (`u32` or `u64`) containing the result of its i1 argument
428/// in all active lanes, and zero in all inactive lanes.
429///
430#[doc = include_str!("intrinsic_is_convergent.md")]
431#[inline]
432#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
433pub fn ballot(b: bool) -> u64 {
434    llvm_ballot(b)
435}
436
437/// Indexes into the `value` with the current lane id and returns for each lane
438/// if the corresponding bit is set.
439///
440/// While [`ballot`] converts a `bool` to a mask, `inverse_ballot` converts a mask back to a `bool`.
441/// This means `inverse_ballot(ballot(b)) == b`.
442/// The inverse of `ballot(inverse_ballot(value)) ~= value` is not always true as inactive lanes are set to zero by `ballot`.
443///
444#[doc = include_str!("intrinsic_is_convergent.md")]
445#[inline]
446#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
447pub fn inverse_ballot(value: u64) -> bool {
448    llvm_inverse_ballot(value)
449}
450
451/// Performs an arithmetic min reduction on the unsigned values provided by each lane in the wavefront.
452///
453/// The `STRATEGY` argument is a hint for the reduction strategy.
454/// - 0: Target default preference
455/// - 1: Iterative strategy
456/// - 2: DPP
457///
458/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
459///
460#[doc = include_str!("intrinsic_is_convergent.md")]
461#[inline]
462#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
463pub fn wave_reduce_umin<const STRATEGY: u32>(value: u32) -> u32 {
464    static_assert!(STRATEGY <= 2);
465    llvm_wave_reduce_umin(value, STRATEGY)
466}
467/// Performs an arithmetic min reduction on the signed values provided by each lane in the wavefront.
468///
469/// The `STRATEGY` argument is a hint for the reduction strategy.
470/// - 0: Target default preference
471/// - 1: Iterative strategy
472/// - 2: DPP
473///
474/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
475///
476#[doc = include_str!("intrinsic_is_convergent.md")]
477#[inline]
478#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
479pub fn wave_reduce_min<const STRATEGY: u32>(value: i32) -> i32 {
480    static_assert!(STRATEGY <= 2);
481    llvm_wave_reduce_min(value, STRATEGY)
482}
483
484/// Performs an arithmetic max reduction on the unsigned values provided by each lane in the wavefront.
485///
486/// The `STRATEGY` argument is a hint for the reduction strategy.
487/// - 0: Target default preference
488/// - 1: Iterative strategy
489/// - 2: DPP
490///
491/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
492///
493#[doc = include_str!("intrinsic_is_convergent.md")]
494#[inline]
495#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
496pub fn wave_reduce_umax<const STRATEGY: u32>(value: u32) -> u32 {
497    static_assert!(STRATEGY <= 2);
498    llvm_wave_reduce_umax(value, STRATEGY)
499}
500/// Performs an arithmetic max reduction on the signed values provided by each lane in the wavefront.
501///
502/// The `STRATEGY` argument is a hint for the reduction strategy.
503/// - 0: Target default preference
504/// - 1: Iterative strategy
505/// - 2: DPP
506///
507/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
508///
509#[doc = include_str!("intrinsic_is_convergent.md")]
510#[inline]
511#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
512pub fn wave_reduce_max<const STRATEGY: u32>(value: i32) -> i32 {
513    static_assert!(STRATEGY <= 2);
514    llvm_wave_reduce_max(value, STRATEGY)
515}
516
517/// Performs an arithmetic add reduction on the values provided by each lane in the wavefront.
518///
519/// The `STRATEGY` argument is a hint for the reduction strategy.
520/// - 0: Target default preference
521/// - 1: Iterative strategy
522/// - 2: DPP
523///
524/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
525///
526#[doc = include_str!("intrinsic_is_convergent.md")]
527#[inline]
528#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
529pub fn wave_reduce_add<const STRATEGY: u32>(value: u32) -> u32 {
530    static_assert!(STRATEGY <= 2);
531    llvm_wave_reduce_add(value, STRATEGY)
532}
533
534/// Performs a logical and reduction on the unsigned values provided by each lane in the wavefront.
535///
536/// The `STRATEGY` argument is a hint for the reduction strategy.
537/// - 0: Target default preference
538/// - 1: Iterative strategy
539/// - 2: DPP
540///
541/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
542///
543#[doc = include_str!("intrinsic_is_convergent.md")]
544#[inline]
545#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
546pub fn wave_reduce_and<const STRATEGY: u32>(value: u32) -> u32 {
547    static_assert!(STRATEGY <= 2);
548    llvm_wave_reduce_and(value, STRATEGY)
549}
550/// Performs a logical or reduction on the unsigned values provided by each lane in the wavefront.
551///
552/// The `STRATEGY` argument is a hint for the reduction strategy.
553/// - 0: Target default preference
554/// - 1: Iterative strategy
555/// - 2: DPP
556///
557/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
558///
559#[doc = include_str!("intrinsic_is_convergent.md")]
560#[inline]
561#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
562pub fn wave_reduce_or<const STRATEGY: u32>(value: u32) -> u32 {
563    static_assert!(STRATEGY <= 2);
564    llvm_wave_reduce_or(value, STRATEGY)
565}
566/// Performs a logical xor reduction on the unsigned values provided by each lane in the wavefront.
567///
568/// The `STRATEGY` argument is a hint for the reduction strategy.
569/// - 0: Target default preference
570/// - 1: Iterative strategy
571/// - 2: DPP
572///
573/// If target does not support the DPP operations (e.g. gfx6/7), reduction will be performed using default iterative strategy.
574///
575#[doc = include_str!("intrinsic_is_convergent.md")]
576#[inline]
577#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
578pub fn wave_reduce_xor<const STRATEGY: u32>(value: u32) -> u32 {
579    static_assert!(STRATEGY <= 2);
580    llvm_wave_reduce_xor(value, STRATEGY)
581}
582
583// The following intrinsics can have multiple sizes
584
585/// Get `value` from the first active lane in the wavefront.
586///
587#[doc = include_str!("intrinsic_is_convergent.md")]
588#[inline]
589#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
590pub fn readfirstlane_u32(value: u32) -> u32 {
591    llvm_readfirstlane_u32(value)
592}
593/// Get `value` from the first active lane in the wavefront.
594///
595#[doc = include_str!("intrinsic_is_convergent.md")]
596#[inline]
597#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
598pub fn readfirstlane_u64(value: u64) -> u64 {
599    llvm_readfirstlane_u64(value)
600}
601/// Get `value` from the lane at index `lane` in the wavefront.
602///
603/// The lane argument must be uniform across the currently active threads
604/// of the current wavefront. Otherwise, the result is undefined.
605///
606#[doc = include_str!("intrinsic_is_convergent.md")]
607#[inline]
608#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
609pub unsafe fn readlane_u32(value: u32, lane: u32) -> u32 {
610    unsafe { llvm_readlane_u32(value, lane) }
611}
612/// Get `value` from the lane at index `lane` in the wavefront.
613///
614/// The lane argument must be uniform across the currently active threads
615/// of the current wavefront. Otherwise, the result is undefined.
616///
617#[doc = include_str!("intrinsic_is_convergent.md")]
618#[inline]
619#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
620pub unsafe fn readlane_u64(value: u64, lane: u32) -> u64 {
621    unsafe { llvm_readlane_u64(value, lane) }
622}
623/// Return `value` for the lane at index `lane` in the wavefront.
624/// Return `default` for all other lanes.
625///
626/// The value to write and lane select arguments must be uniform across the
627/// currently active threads of the current wavefront. Otherwise, the result is
628/// undefined.
629///
630/// `value` is the value returned by `lane`.
631/// `default` is the value returned by all lanes other than `lane`.
632///
633#[doc = include_str!("intrinsic_is_convergent.md")]
634#[inline]
635#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
636pub unsafe fn writelane_u32(value: u32, lane: u32, default: u32) -> u32 {
637    unsafe { llvm_writelane_u32(value, lane, default) }
638}
639/// Return `value` for the lane at index `lane` in the wavefront.
640/// Return `default` for all other lanes.
641///
642/// The value to write and lane select arguments must be uniform across the
643/// currently active threads of the current wavefront. Otherwise, the result is
644/// undefined.
645///
646/// `value` is the value returned by `lane`.
647/// `default` is the value returned by all lanes other than `lane`.
648///
649#[doc = include_str!("intrinsic_is_convergent.md")]
650#[inline]
651#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
652pub unsafe fn writelane_u64(value: u64, lane: u32, default: u64) -> u64 {
653    unsafe { llvm_writelane_u64(value, lane, default) }
654}
655
656/// Stop execution of the wavefront.
657///
658/// This usually signals the end of a successful execution.
659///
660#[doc = include_str!("intrinsic_is_convergent.md")]
661#[inline]
662#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
663pub fn endpgm() -> ! {
664    llvm_endpgm()
665}
666
667/// The `update_dpp` intrinsic represents the `update.dpp` operation in AMDGPU.
668/// It takes an old value, a source operand, a DPP control operand, a row mask, a bank mask, and a bound control.
669/// This operation is equivalent to a sequence of `v_mov_b32` operations.
670///
671/// `llvm.amdgcn.update.dpp.i32 <old> <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl>`
672/// Should be equivalent to:
673/// ```asm
674/// v_mov_b32 <dest> <old>
675/// v_mov_b32 <dest> <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl>
676/// ```
677///
678#[doc = include_str!("intrinsic_is_convergent.md")]
679#[inline]
680#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
681pub unsafe fn update_dpp<
682    const DPP_CTRL: u32,
683    const ROW_MASK: u32,
684    const BANK_MASK: u32,
685    const BOUND_CONTROL: bool,
686>(
687    old: u32,
688    src: u32,
689) -> u32 {
690    unsafe { llvm_update_dpp(old, src, DPP_CTRL, ROW_MASK, BANK_MASK, BOUND_CONTROL) }
691}
692
693/// Measures time based on a fixed frequency.
694///
695/// Provides a real-time clock counter that runs at constant speed (typically 100 MHz) independent of ALU clock speeds.
696/// The clock is consistent across the chip, so can be used for measuring between different wavefronts.
697#[inline]
698#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
699pub fn s_memrealtime() -> u64 {
700    llvm_s_memrealtime()
701}
702
703/// Scatter data across all lanes in a wavefront.
704///
705/// Writes `value` to the lane `lane`.
706///
707/// Reading from inactive lanes returns `0`.
708/// In case multiple values get written to the same `lane`, the value from the source lane with the higher index is taken.
709///
710#[doc = include_str!("intrinsic_is_convergent.md")]
711#[inline]
712#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
713pub unsafe fn ds_permute(lane: u32, value: u32) -> u32 {
714    unsafe { llvm_ds_permute(lane, value) }
715}
716/// Gather data across all lanes in a wavefront.
717///
718/// Returns the `value` given to `ds_permute` by lane `lane`.
719///
720/// Reading from inactive lanes returns `0`.
721///
722#[doc = include_str!("intrinsic_is_convergent.md")]
723#[inline]
724#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
725pub unsafe fn ds_bpermute(lane: u32, value: u32) -> u32 {
726    unsafe { llvm_ds_bpermute(lane, value) }
727}
728/// Permute a 64-bit value.
729///
730/// `selector` selects between different patterns in which the 64-bit values represented by `src0` and `src1` are permuted.
731#[inline]
732#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
733pub unsafe fn perm(src0: u32, src1: u32, selector: u32) -> u32 {
734    unsafe { llvm_perm(src0, src1, selector) }
735}
736
737// gfx10
738/// Performs arbitrary gather-style operation within a row (16 contiguous lanes) of the second input operand.
739///
740/// The third and fourth inputs must be uniform across the current wavefront.
741/// These are combined into a single 64-bit value representing lane selects used to swizzle within each row.
742///
743#[doc = include_str!("intrinsic_is_convergent.md")]
744#[inline]
745#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
746pub unsafe fn permlane16_u32<const FI: bool, const BOUND_CONTROL: bool>(
747    old: u32,
748    src0: u32,
749    src1: u32,
750    src2: u32,
751) -> u32 {
752    unsafe { llvm_permlane16_u32(old, src0, src1, src2, FI, BOUND_CONTROL) }
753}
754
755// gfx10
756/// Performs arbitrary gather-style operation across two rows (16 contiguous lanes) of the second input operand.
757///
758/// The third and fourth inputs must be uniform across the current wavefront.
759/// These are combined into a single 64-bit value representing lane selects used to swizzle within each row.
760///
761#[doc = include_str!("intrinsic_is_convergent.md")]
762#[inline]
763#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
764pub unsafe fn permlanex16_u32<const FI: bool, const BOUND_CONTROL: bool>(
765    old: u32,
766    src0: u32,
767    src1: u32,
768    src2: u32,
769) -> u32 {
770    unsafe { llvm_permlanex16_u32(old, src0, src1, src2, FI, BOUND_CONTROL) }
771}
772
773/// Get the index of the current wavefront in the workgroup.
774#[inline]
775#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
776pub fn s_get_waveid_in_workgroup() -> u32 {
777    llvm_s_get_waveid_in_workgroup()
778}
779
780// gfx11
781/// Swap `value` between upper and lower 32 lanes in a wavefront.
782///
783/// Does nothing for wave32.
784///
785#[doc = include_str!("intrinsic_is_convergent.md")]
786#[inline]
787#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
788pub unsafe fn permlane64_u32(value: u32) -> u32 {
789    unsafe { llvm_permlane64_u32(value) }
790}
791
792// gfx12
793/// Performs arbitrary gather-style operation within a row (16 contiguous lanes) of the second input operand.
794///
795/// In contrast to [`permlane16_u32`], allows each lane to specify its own gather lane.
796///
797#[doc = include_str!("intrinsic_is_convergent.md")]
798#[inline]
799#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
800pub unsafe fn permlane16_var<const FI: bool, const BOUND_CONTROL: bool>(
801    old: u32,
802    src0: u32,
803    src1: u32,
804) -> u32 {
805    unsafe { llvm_permlane16_var(old, src0, src1, FI, BOUND_CONTROL) }
806}
807
808// gfx12
809/// Performs arbitrary gather-style operation across two rows (16 contiguous lanes) of the second input operand.
810///
811/// In contrast to [`permlanex16_u32`], allows each lane to specify its own gather lane.
812///
813#[doc = include_str!("intrinsic_is_convergent.md")]
814#[inline]
815#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
816pub unsafe fn permlanex16_var<const FI: bool, const BOUND_CONTROL: bool>(
817    old: u32,
818    src0: u32,
819    src1: u32,
820) -> u32 {
821    unsafe { llvm_permlanex16_var(old, src0, src1, FI, BOUND_CONTROL) }
822}
823
824/// Get the index of the current wavefront in the workgroup.
825#[inline]
826#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
827pub fn wave_id() -> u32 {
828    llvm_wave_id()
829}
830
831// gfx950
832/// Provide direct access to `v_permlane16_swap_b32` instruction on supported targets.
833///
834/// Swaps the values across lanes of first 2 operands.
835/// Odd rows of the first operand are swapped with even rows of the second operand (one row is 16 lanes).
836/// Returns a pair for the swapped registers.
837/// The first element of the return corresponds to the swapped element of the first argument.
838///
839#[doc = include_str!("intrinsic_is_convergent.md")]
840#[inline]
841#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
842pub unsafe fn permlane16_swap<const FI: bool, const BOUND_CONTROL: bool>(
843    vdst_old: u32,
844    vsrc_src0: u32,
845) -> (u32, u32) {
846    unsafe { llvm_permlane16_swap(vdst_old, vsrc_src0, FI, BOUND_CONTROL) }
847}
848
849// gfx950
850/// Provide direct access to `v_permlane32_swap_b32` instruction on supported targets.
851///
852/// Swaps the values across lanes of first 2 operands.
853/// Rows 2 and 3 of the first operand are swapped with rows 0 and 1 of the second operand (one row is 16 lanes).
854/// Returns a pair for the swapped registers.
855/// The first element of the return corresponds to the swapped element of the first argument.
856///
857#[doc = include_str!("intrinsic_is_convergent.md")]
858#[inline]
859#[unstable(feature = "stdarch_amdgpu", issue = "149988")]
860pub unsafe fn permlane32_swap<const FI: bool, const BOUND_CONTROL: bool>(
861    vdst_old: u32,
862    vsrc_src0: u32,
863) -> (u32, u32) {
864    unsafe { llvm_permlane32_swap(vdst_old, vsrc_src0, FI, BOUND_CONTROL) }
865}
866
867// Functions to generate code, used to check that the intrinsics build.
868// Marked as no_mangle, so the compiler does not remove the functions.
869// To test, uncomment the `#[cfg(test)]` line below and run
870// NORUN=1 NOSTD=1 TARGET=amdgcn-amd-amdhsa CARGO_UNSTABLE_BUILD_STD=core ci/run.sh
871//
872// Note that depending on the target-cpu set in run.sh, some of these intrinsics are not available
873// and compilation fails with `Cannot select: intrinsic %llvm.amdgcn...`.
874// Uncomment these intrinsics to check.
875#[cfg(test)]
876mod tests {
877    use super::*;
878
879    #[unsafe(no_mangle)]
880    fn test_workitem_id_x() -> u32 {
881        workitem_id_x()
882    }
883    #[unsafe(no_mangle)]
884    fn test_workitem_id_y() -> u32 {
885        workitem_id_y()
886    }
887    #[unsafe(no_mangle)]
888    fn test_workitem_id_z() -> u32 {
889        workitem_id_z()
890    }
891
892    #[unsafe(no_mangle)]
893    fn test_workgroup_id_x() -> u32 {
894        workgroup_id_x()
895    }
896    #[unsafe(no_mangle)]
897    fn test_workgroup_id_y() -> u32 {
898        workgroup_id_y()
899    }
900    #[unsafe(no_mangle)]
901    fn test_workgroup_id_z() -> u32 {
902        workgroup_id_z()
903    }
904
905    #[unsafe(no_mangle)]
906    fn test_groupstaticsize() -> u32 {
907        groupstaticsize()
908    }
909    #[unsafe(no_mangle)]
910    fn test_dispatch_id() -> u64 {
911        dispatch_id()
912    }
913
914    #[unsafe(no_mangle)]
915    fn test_wavefrontsize() -> u32 {
916        wavefrontsize()
917    }
918
919    #[unsafe(no_mangle)]
920    fn test_s_barrier() {
921        s_barrier()
922    }
923
924    #[unsafe(no_mangle)]
925    fn test_s_barrier_signal() {
926        unsafe { s_barrier_signal::<-1>() }
927    }
928
929    #[unsafe(no_mangle)]
930    fn test_s_barrier_signal_isfirst() -> bool {
931        unsafe { s_barrier_signal_isfirst::<-1>() }
932    }
933
934    #[unsafe(no_mangle)]
935    fn test_s_barrier_wait() {
936        unsafe { s_barrier_wait::<-1>() }
937    }
938
939    #[unsafe(no_mangle)]
940    fn test_s_get_barrier_state() -> u32 {
941        unsafe { s_get_barrier_state::<-1>() }
942    }
943
944    #[unsafe(no_mangle)]
945    fn test_wave_barrier() {
946        wave_barrier()
947    }
948
949    #[unsafe(no_mangle)]
950    fn test_sched_barrier() {
951        unsafe { sched_barrier::<1>() }
952    }
953
954    #[unsafe(no_mangle)]
955    fn test_sched_group_barrier() {
956        unsafe { sched_group_barrier::<1, 1, 0>() }
957    }
958
959    #[unsafe(no_mangle)]
960    fn test_s_sleep() {
961        s_sleep::<1>()
962    }
963
964    #[unsafe(no_mangle)]
965    fn test_s_sethalt() -> ! {
966        s_sethalt::<1>()
967    }
968
969    #[unsafe(no_mangle)]
970    fn test_s_getpc() -> i64 {
971        s_getpc()
972    }
973
974    #[unsafe(no_mangle)]
975    fn test_mbcnt_lo(value: u32, init: u32) -> u32 {
976        mbcnt_lo(value, init)
977    }
978    #[unsafe(no_mangle)]
979    fn test_mbcnt_hi(value: u32, init: u32) -> u32 {
980        mbcnt_hi(value, init)
981    }
982
983    #[unsafe(no_mangle)]
984    fn test_ballot(b: bool) -> u64 {
985        ballot(b)
986    }
987
988    #[unsafe(no_mangle)]
989    fn test_inverse_ballot(value: u64) -> bool {
990        inverse_ballot(value)
991    }
992
993    #[unsafe(no_mangle)]
994    fn test_wave_reduce_umin(value: u32) -> u32 {
995        wave_reduce_umin::<0>(value)
996    }
997    #[unsafe(no_mangle)]
998    fn test_wave_reduce_min(value: i32) -> i32 {
999        wave_reduce_min::<0>(value)
1000    }
1001
1002    #[unsafe(no_mangle)]
1003    fn test_wave_reduce_umax(value: u32) -> u32 {
1004        wave_reduce_umax::<0>(value)
1005    }
1006    #[unsafe(no_mangle)]
1007    fn test_wave_reduce_max(value: i32) -> i32 {
1008        wave_reduce_max::<0>(value)
1009    }
1010
1011    #[unsafe(no_mangle)]
1012    fn test_wave_reduce_add(value: u32) -> u32 {
1013        wave_reduce_add::<0>(value)
1014    }
1015
1016    #[unsafe(no_mangle)]
1017    fn test_wave_reduce_and(value: u32) -> u32 {
1018        wave_reduce_and::<0>(value)
1019    }
1020    #[unsafe(no_mangle)]
1021    fn test_wave_reduce_or(value: u32) -> u32 {
1022        wave_reduce_or::<0>(value)
1023    }
1024    #[unsafe(no_mangle)]
1025    fn test_wave_reduce_xor(value: u32) -> u32 {
1026        wave_reduce_xor::<0>(value)
1027    }
1028
1029    #[unsafe(no_mangle)]
1030    fn test_readfirstlane_u32(value: u32) -> u32 {
1031        readfirstlane_u32(value)
1032    }
1033    #[unsafe(no_mangle)]
1034    fn test_readfirstlane_u64(value: u64) -> u64 {
1035        readfirstlane_u64(value)
1036    }
1037    #[unsafe(no_mangle)]
1038    fn test_readlane_u32(value: u32, lane: u32) -> u32 {
1039        unsafe { readlane_u32(value, lane) }
1040    }
1041    #[unsafe(no_mangle)]
1042    fn test_readlane_u64(value: u64, lane: u32) -> u64 {
1043        unsafe { readlane_u64(value, lane) }
1044    }
1045    #[unsafe(no_mangle)]
1046    fn test_writelane_u32(value: u32, lane: u32, default: u32) -> u32 {
1047        unsafe { writelane_u32(value, lane, default) }
1048    }
1049    #[unsafe(no_mangle)]
1050    fn test_writelane_u64(value: u64, lane: u32, default: u64) -> u64 {
1051        unsafe { writelane_u64(value, lane, default) }
1052    }
1053
1054    #[unsafe(no_mangle)]
1055    fn test_endpgm() -> ! {
1056        endpgm()
1057    }
1058
1059    #[unsafe(no_mangle)]
1060    fn test_update_dpp(old: u32, src: u32) -> u32 {
1061        unsafe { update_dpp::<0, 0, 0, true>(old, src) }
1062    }
1063
1064    #[unsafe(no_mangle)]
1065    fn test_s_memrealtime() -> u64 {
1066        s_memrealtime()
1067    }
1068
1069    #[unsafe(no_mangle)]
1070    fn test_ds_permute(lane: u32, value: u32) -> u32 {
1071        unsafe { ds_permute(lane, value) }
1072    }
1073    #[unsafe(no_mangle)]
1074    fn test_ds_bpermute(lane: u32, value: u32) -> u32 {
1075        unsafe { ds_bpermute(lane, value) }
1076    }
1077    #[unsafe(no_mangle)]
1078    fn test_perm(src0: u32, src1: u32, selector: u32) -> u32 {
1079        unsafe { perm(src0, src1, selector) }
1080    }
1081
1082    #[unsafe(no_mangle)]
1083    fn test_permlane16_u32(old: u32, src0: u32, src1: u32, src2: u32) -> u32 {
1084        unsafe { permlane16_u32::<false, true>(old, src0, src1, src2) }
1085    }
1086
1087    #[unsafe(no_mangle)]
1088    fn test_permlanex16_u32(old: u32, src0: u32, src1: u32, src2: u32) -> u32 {
1089        unsafe { permlanex16_u32::<false, true>(old, src0, src1, src2) }
1090    }
1091
1092    #[unsafe(no_mangle)]
1093    fn test_s_get_waveid_in_workgroup() -> u32 {
1094        s_get_waveid_in_workgroup()
1095    }
1096
1097    #[unsafe(no_mangle)]
1098    fn test_permlane64_u32(value: u32) -> u32 {
1099        unsafe { permlane64_u32(value) }
1100    }
1101
1102    #[unsafe(no_mangle)]
1103    fn test_permlane16_var(old: u32, src0: u32, src1: u32) -> u32 {
1104        unsafe { permlane16_var::<false, true>(old, src0, src1) }
1105    }
1106
1107    #[unsafe(no_mangle)]
1108    fn test_permlanex16_var(old: u32, src0: u32, src1: u32) -> u32 {
1109        unsafe { permlanex16_var::<false, true>(old, src0, src1) }
1110    }
1111
1112    #[unsafe(no_mangle)]
1113    fn test_wave_id() -> u32 {
1114        wave_id()
1115    }
1116
1117    #[unsafe(no_mangle)]
1118    fn test_permlane16_swap(vdst_old: u32, vsrc_src0: u32) -> (u32, u32) {
1119        unsafe { permlane16_swap::<false, true>(vdst_old, vsrc_src0) }
1120    }
1121
1122    #[unsafe(no_mangle)]
1123    fn test_permlane32_swap(vdst_old: u32, vsrc_src0: u32) -> (u32, u32) {
1124        unsafe { permlane32_swap::<false, true>(vdst_old, vsrc_src0) }
1125    }
1126}