Skip to content

Conversation

@Flakebi
Copy link

@Flakebi Flakebi commented Dec 14, 2025

Add intrinsics for the amdgpu architecture.

I’m not sure how to add/run CI (ci/run.sh fails for me e.g. for
nvptx because core cannot be found), but I checked that it compiles
without warnings with

$ CARGO_BUILD_RUSTFLAGS=-Ctarget-cpu=gfx900 cargo check --target amdgcn-amd-amdhsa -Zbuild-std=core

Tracking issue: rust-lang/rust#149988

@rustbot
Copy link
Collaborator

rustbot commented Dec 14, 2025

r? @sayantn

rustbot has assigned @sayantn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@sayantn
Copy link
Contributor

sayantn commented Dec 14, 2025

I think it can be "tested" the same way we do core::arch::nvptx (this is also a similar NO_RUN, NO_STD target). For those targets, we just test in CI that it builds. You can just look at how we handle nvptx64-nvidia-cuda in .github/workflows/main.yml. Also you would need to add this target to ci/dox.sh to check that the documentation builds

@Flakebi Flakebi force-pushed the amdgpu-intrinsics branch 4 times, most recently from e429208 to d6043df Compare December 14, 2025 20:24
Add intrinsics for the amdgpu architecture.
@Flakebi
Copy link
Author

Flakebi commented Dec 14, 2025

Thanks, I tried to replicate what’s there for nvptx + adding -Ctarget-cpu (as amdgpu doesn’t compile without, it has no generic cpu) + build-std=core.
I still can’t build ci/run-docker.sh or ci/run.sh locally (ci/dox.sh seems to work if I remove s390x), but I think I got it working now.
Sorry for the many force-pushes!

The diff to my first push from when opening this PR is here: https://github.com/rust-lang/stdarch/compare/b3f5bdae0efbdd5f7297d0225623bd31c7fe895b..e1028110e77561574bfb7ea349154d46b5ea7b86

Copy link
Contributor

@sayantn sayantn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I have put some comments

if [ "$CI" != "" ]; then
rustup component add rust-src
fi
export CARGO_UNSTABLE_BUILD_STD=core,alloc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to build alloc, core_arch is no_std, no_alloc

Comment on lines +645 to +652
pub unsafe fn update_dpp(
old: u32,
src: u32,
dpp_ctrl: u32,
row_mask: u32,
bank_mask: u32,
bound_control: bool,
) -> u32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

llvm.amdgcn.update.dpp should have the last 4 arguments immediate, i.e. it should use const generics

Suggested change
pub unsafe fn update_dpp(
old: u32,
src: u32,
dpp_ctrl: u32,
row_mask: u32,
bank_mask: u32,
bound_control: bool,
) -> u32 {
pub unsafe fn update_dpp<
const DPP_CTRL: u32,
const ROW_MASK: u32,
const BANK_MASK: u32,
const BOUND_CONTROL: bool
>(old: u32, src: u32) -> u32 {

Copy link
Contributor

@sayantn sayantn Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have commented on several intrinsics that they should use const-generics, as the LLVM intrinsics use ImmArg. There are a few more, just ensure that the Immediate arguments use const-generics. I checked by temporarily making all the intrinsics #[inline(never)], and running ci/run.sh (this ensures that the functions are actually codegened)

  • update.dpp
  • wave.reduce.{or,and,max,min,xor,umax,umin}
  • permlane{x}16{.var}
  • permlane{16,32}.swap
  • sched.barrier
  • sched.group.barrier
  • s.barrier.wait
  • s.barrier.signal
  • s.barrier.signal.isfirst
  • s.sleep
  • s.sethalt

also, if an Immediate argument has some kind of restrictions (e.g. it needs to be in range 0..10, then you can check that using the static_assert macros in )

@sayantn
Copy link
Contributor

sayantn commented Dec 16, 2025

Also I have noticed that Clang provides a different set of intrinsics than these (amdgpuintrin.h and gpuintrin.h). Is this divergence intentional? We normally stick to following the C conventions in stdarch

@Flakebi
Copy link
Author

Flakebi commented Dec 16, 2025

Thanks for the review!

Interesting, I thought core_arch is more akin to the __builtin_* family of functions in clang.
The clang __gpu intrinsics are definitely useful, though they are (to no surprise) missing low-level, hardware-specific intrinsics (e.g. wave_id, sethalt and buffer/image intrinsics, which I can’t add yet because they need simd type support in rustc).

I do plan to write a common gpu module for amdgpu and nvptx as well.
Maybe this one should follow gpuintrin.h?
We could e.g. have

mod amdgpu {
    mod gpu {
        use super::*;
        pub fn block_id_x() -> u32 {
            workitem_id_x()
        }
    }
}
// Same for nvptx

mod gpu {
    #[cfg(target_arch = "amdgpu")]
    pub use amdgpu::gpu::*;
    #[cfg(target_arch = "nvptx64")]
    pub use nvptx::gpu::*;

    // + more intrinsics as in gpuintrin.h
}

@sayantn
Copy link
Contributor

sayantn commented Dec 16, 2025

The analogue to __builtin functions in C are #[rust_intrinsic] functions and linked LLVM intrinsics. They are generally not exposed to users (in stable) as they are tightly linked to the compiler implementation.

If there are some interesting platform-specific intrinsics, we can add them, but generally we follow GCC and Clang in regards to intrinsics.

Yea, a common gpu module can be added following gpuintrin.h.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants