Skip to main content

rustc_target/asm/
amdgpu.rs

1use std::fmt;
2
3use rustc_span::Symbol;
4
5use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
6
7// Types are listed as SGPR_*/VGPR_* in llvm/lib/Target/AMDGPU/SIRegisterInfo.td
8
9/// Amdgpu register classes
10///
11/// The number is the size of the register class in bits.
12#[derive(
13    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::marker::Copy for AmdgpuInlineAsmRegClass { }Copy,
14    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::clone::Clone for AmdgpuInlineAsmRegClass {
    #[inline]
    fn clone(&self) -> AmdgpuInlineAsmRegClass {
        let _: ::core::clone::AssertParamIsClone<u16>;
        *self
    }
}Clone,
15    const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AmdgpuInlineAsmRegClass {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        AmdgpuInlineAsmRegClass::Sgpr(ref __binding_0) => { 0usize }
                        AmdgpuInlineAsmRegClass::Vgpr(ref __binding_0) => { 1usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    AmdgpuInlineAsmRegClass::Sgpr(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    AmdgpuInlineAsmRegClass::Vgpr(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };rustc_macros::Encodable,
16    const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AmdgpuInlineAsmRegClass {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        AmdgpuInlineAsmRegClass::Sgpr(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        AmdgpuInlineAsmRegClass::Vgpr(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `AmdgpuInlineAsmRegClass`, expected 0..2, actual {0}",
                                n));
                    }
                }
            }
        }
    };rustc_macros::Decodable,
17    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::fmt::Debug for AmdgpuInlineAsmRegClass {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            AmdgpuInlineAsmRegClass::Sgpr(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Sgpr",
                    &__self_0),
            AmdgpuInlineAsmRegClass::Vgpr(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Vgpr",
                    &__self_0),
        }
    }
}Debug,
18    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::Eq for AmdgpuInlineAsmRegClass {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u16>;
    }
}Eq,
19    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialEq for AmdgpuInlineAsmRegClass {
    #[inline]
    fn eq(&self, other: &AmdgpuInlineAsmRegClass) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (AmdgpuInlineAsmRegClass::Sgpr(__self_0),
                    AmdgpuInlineAsmRegClass::Sgpr(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (AmdgpuInlineAsmRegClass::Vgpr(__self_0),
                    AmdgpuInlineAsmRegClass::Vgpr(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq,
20    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialOrd for AmdgpuInlineAsmRegClass {
    #[inline]
    fn partial_cmp(&self, other: &AmdgpuInlineAsmRegClass)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (AmdgpuInlineAsmRegClass::Sgpr(__self_0),
                AmdgpuInlineAsmRegClass::Sgpr(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (AmdgpuInlineAsmRegClass::Vgpr(__self_0),
                AmdgpuInlineAsmRegClass::Vgpr(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd,
21    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::hash::Hash for AmdgpuInlineAsmRegClass {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            AmdgpuInlineAsmRegClass::Sgpr(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            AmdgpuInlineAsmRegClass::Vgpr(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash,
22    const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for
            AmdgpuInlineAsmRegClass {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    AmdgpuInlineAsmRegClass::Sgpr(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    AmdgpuInlineAsmRegClass::Vgpr(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };rustc_macros::StableHash
23)]
24#[allow(non_camel_case_types)]
25pub enum AmdgpuInlineAsmRegClass {
26    Sgpr(u16),
27    Vgpr(u16),
28}
29
30pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
31    super::InlineAsmRegClass,
32    rustc_data_structures::fx::FxIndexSet<super::InlineAsmReg>,
33> {
34    use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
35
36    use super::InlineAsmRegClass;
37    let mut map = FxHashMap::default();
38
39    // SGPR and VGPR sizes
40    for i in [32, 64, 96, 128, 256, 512] {
41        map.insert(
42            InlineAsmRegClass::Amdgpu(AmdgpuInlineAsmRegClass::Sgpr(i)),
43            FxIndexSet::default(),
44        );
45        map.insert(
46            InlineAsmRegClass::Amdgpu(AmdgpuInlineAsmRegClass::Vgpr(i)),
47            FxIndexSet::default(),
48        );
49    }
50
51    // VGPR-only sizes
52    for i in [16, 160, 192, 224, 288, 320, 352, 384, 1024] {
53        map.insert(
54            InlineAsmRegClass::Amdgpu(AmdgpuInlineAsmRegClass::Vgpr(i)),
55            FxIndexSet::default(),
56        );
57    }
58
59    map
60}
61
62// See https://llvm.org/docs/AMDGPUOperandSyntax.html
63impl AmdgpuInlineAsmRegClass {
64    /// Prefix when printed and register constraint in LLVM
65    fn prefix(self) -> &'static str {
66        match self {
67            Self::Sgpr(_) => "s",
68            Self::Vgpr(_) => "v",
69        }
70    }
71
72    /// Return size of the register class in bits
73    fn bits(self) -> u16 {
74        let (Self::Sgpr(i) | Self::Vgpr(i)) = self;
75        i
76    }
77
78    /// Return size of the register class in bytes
79    fn bytes(self) -> u16 {
80        self.bits() / 8
81    }
82
83    /// Returns the name or `None` if this is not a valid register class
84    fn try_get_name(self) -> Option<rustc_span::Symbol> {
85        let s = match self {
86            Self::Sgpr(32) => rustc_span::sym::sgpr32,
87            Self::Sgpr(64) => rustc_span::sym::sgpr64,
88            Self::Sgpr(96) => rustc_span::sym::sgpr96,
89            Self::Sgpr(128) => rustc_span::sym::sgpr128,
90            Self::Sgpr(256) => rustc_span::sym::sgpr256,
91            Self::Sgpr(512) => rustc_span::sym::sgpr512,
92            Self::Vgpr(16) => rustc_span::sym::vgpr16,
93            Self::Vgpr(32) => rustc_span::sym::vgpr32,
94            Self::Vgpr(64) => rustc_span::sym::vgpr64,
95            Self::Vgpr(96) => rustc_span::sym::vgpr96,
96            Self::Vgpr(128) => rustc_span::sym::vgpr128,
97            Self::Vgpr(160) => rustc_span::sym::vgpr160,
98            Self::Vgpr(192) => rustc_span::sym::vgpr192,
99            Self::Vgpr(224) => rustc_span::sym::vgpr224,
100            Self::Vgpr(256) => rustc_span::sym::vgpr256,
101            Self::Vgpr(288) => rustc_span::sym::vgpr288,
102            Self::Vgpr(320) => rustc_span::sym::vgpr320,
103            Self::Vgpr(352) => rustc_span::sym::vgpr352,
104            Self::Vgpr(384) => rustc_span::sym::vgpr384,
105            Self::Vgpr(512) => rustc_span::sym::vgpr512,
106            Self::Vgpr(1024) => rustc_span::sym::vgpr1024,
107            _ => return None,
108        };
109        Some(s)
110    }
111
112    pub fn name(self) -> rustc_span::Symbol {
113        self.try_get_name().expect("Invalid amdgpu register class")
114    }
115
116    pub fn parse(name: rustc_span::Symbol) -> Result<Self, &'static [rustc_span::Symbol]> {
117        match name {
118            rustc_span::sym::sgpr32 => Ok(Self::Sgpr(32)),
119            rustc_span::sym::sgpr64 => Ok(Self::Sgpr(64)),
120            rustc_span::sym::sgpr96 => Ok(Self::Sgpr(96)),
121            rustc_span::sym::sgpr128 => Ok(Self::Sgpr(128)),
122            rustc_span::sym::sgpr256 => Ok(Self::Sgpr(256)),
123            rustc_span::sym::sgpr512 => Ok(Self::Sgpr(512)),
124            rustc_span::sym::vgpr16 => Ok(Self::Vgpr(16)),
125            rustc_span::sym::vgpr32 => Ok(Self::Vgpr(32)),
126            rustc_span::sym::vgpr64 => Ok(Self::Vgpr(64)),
127            rustc_span::sym::vgpr96 => Ok(Self::Vgpr(96)),
128            rustc_span::sym::vgpr128 => Ok(Self::Vgpr(128)),
129            rustc_span::sym::vgpr160 => Ok(Self::Vgpr(160)),
130            rustc_span::sym::vgpr192 => Ok(Self::Vgpr(192)),
131            rustc_span::sym::vgpr224 => Ok(Self::Vgpr(224)),
132            rustc_span::sym::vgpr256 => Ok(Self::Vgpr(256)),
133            rustc_span::sym::vgpr288 => Ok(Self::Vgpr(288)),
134            rustc_span::sym::vgpr320 => Ok(Self::Vgpr(320)),
135            rustc_span::sym::vgpr352 => Ok(Self::Vgpr(352)),
136            rustc_span::sym::vgpr384 => Ok(Self::Vgpr(384)),
137            rustc_span::sym::vgpr512 => Ok(Self::Vgpr(512)),
138            rustc_span::sym::vgpr1024 => Ok(Self::Vgpr(1024)),
139            _ => Err(&[
140                rustc_span::sym::sgpr32,
141                rustc_span::sym::sgpr64,
142                rustc_span::sym::sgpr96,
143                rustc_span::sym::sgpr128,
144                rustc_span::sym::sgpr256,
145                rustc_span::sym::sgpr512,
146                rustc_span::sym::vgpr16,
147                rustc_span::sym::vgpr32,
148                rustc_span::sym::vgpr64,
149                rustc_span::sym::vgpr96,
150                rustc_span::sym::vgpr128,
151                rustc_span::sym::vgpr160,
152                rustc_span::sym::vgpr192,
153                rustc_span::sym::vgpr224,
154                rustc_span::sym::vgpr256,
155                rustc_span::sym::vgpr288,
156                rustc_span::sym::vgpr320,
157                rustc_span::sym::vgpr352,
158                rustc_span::sym::vgpr384,
159                rustc_span::sym::vgpr512,
160                rustc_span::sym::vgpr1024,
161            ]),
162        }
163    }
164
165    pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
166        &[]
167    }
168
169    pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
170        // 8-bit types and f128 are not supported
171        if #[allow(non_exhaustive_omitted_patterns)] match ty {
    InlineAsmType::I8 | InlineAsmType::VecI8(_) | InlineAsmType::F128 |
        InlineAsmType::VecF128(_) => true,
    _ => false,
}matches!(
172            ty,
173            InlineAsmType::I8
174                | InlineAsmType::VecI8(_)
175                | InlineAsmType::F128
176                | InlineAsmType::VecF128(_)
177        ) {
178            return None;
179        }
180
181        Some(Self::Vgpr(ty.size().bits().try_into().ok()?))
182    }
183
184    pub fn suggest_modifier(
185        self,
186        _arch: InlineAsmArch,
187        _ty: InlineAsmType,
188    ) -> Option<ModifierInfo> {
189        None
190    }
191
192    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
193        None
194    }
195
196    pub fn supported_types(self, _arch: InlineAsmArch) -> Vec<(InlineAsmType, Option<Symbol>)> {
197        use InlineAsmType::*;
198        let mut types = Vec::new();
199        let mut add_types = |ts: &[_]| {
200            for t in ts {
201                types.push((*t, None))
202            }
203        };
204        let bits = self.bits() as u64;
205
206        // Primitive types
207        match bits {
208            16 => add_types(&[I16, F16]),
209            // Many 16-bit instructions take 32-bit registers, so allow 16-bit values
210            32 => add_types(&[I16, F16, I32, F32]),
211            64 => add_types(&[I64, F64]),
212            128 => add_types(&[I128]),
213            _ => {}
214        }
215
216        // Vector types
217        if bits == 1024 {
218            add_types(&[VecF32(1024 / 32)]);
219        } else {
220            if bits > 16 && bits.is_power_of_two() {
221                // 32, 64, 128, 256, 512
222                add_types(&[VecI16(bits / 16), VecF16(bits / 16)]);
223            }
224            if bits > 32 {
225                // 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 512
226                add_types(&[VecI32(bits / 32), VecF32(bits / 32)]);
227            }
228        }
229
230        // The LLVM backend supports more vector types, but these are rather uncommon
231        // and not systematic, so we only list common types here.
232
233        types
234    }
235
236    /// The number of supported registers in this class.
237    /// The returned number is the length, so supported register
238    /// indices are 0 to max_num()-1.
239    fn max_num(self) -> u16 {
240        if self == Self::Vgpr(16) {
241            return 512;
242        }
243        let size = self.bytes();
244        match self {
245            Self::Sgpr(_) => 106 - (size / 4 - 1),
246            Self::Vgpr(_) => 256 - (size / 4 - 1),
247        }
248    }
249
250    /// Get register class from prefix and size.
251    fn parse_with_prefix(prefix: char, bits: u16) -> Result<Self, &'static str> {
252        let res = match prefix {
253            's' => Self::Sgpr(bits),
254            'v' => Self::Vgpr(bits),
255            _ => return Err("unknown register prefix"),
256        };
257
258        // Check that the size is valid by converting it to a symbol
259        if res.try_get_name().is_none() {
260            return Err("invalid register size for this class");
261        }
262
263        Ok(res)
264    }
265}
266
267/// Start index of a register.
268///
269/// Together with the register size this gives the range occupied by a register.
270#[derive(
271    #[automatically_derived]
impl ::core::marker::Copy for AmdgpuRegStart { }Copy,
272    #[automatically_derived]
impl ::core::clone::Clone for AmdgpuRegStart {
    #[inline]
    fn clone(&self) -> AmdgpuRegStart {
        let _: ::core::clone::AssertParamIsClone<u16>;
        *self
    }
}Clone,
273    const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AmdgpuRegStart {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        AmdgpuRegStart::Low(ref __binding_0) => { 0usize }
                        AmdgpuRegStart::High(ref __binding_0) => { 1usize }
                        AmdgpuRegStart::Full(ref __binding_0) => { 2usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    AmdgpuRegStart::Low(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    AmdgpuRegStart::High(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    AmdgpuRegStart::Full(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };rustc_macros::Encodable,
274    const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AmdgpuRegStart {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        AmdgpuRegStart::Low(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        AmdgpuRegStart::High(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        AmdgpuRegStart::Full(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `AmdgpuRegStart`, expected 0..3, actual {0}",
                                n));
                    }
                }
            }
        }
    };rustc_macros::Decodable,
275    #[automatically_derived]
impl ::core::fmt::Debug for AmdgpuRegStart {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            AmdgpuRegStart::Low(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Low",
                    &__self_0),
            AmdgpuRegStart::High(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "High",
                    &__self_0),
            AmdgpuRegStart::Full(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Full",
                    &__self_0),
        }
    }
}Debug,
276    #[automatically_derived]
impl ::core::cmp::Eq for AmdgpuRegStart {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u16>;
    }
}Eq,
277    #[automatically_derived]
impl ::core::cmp::PartialEq for AmdgpuRegStart {
    #[inline]
    fn eq(&self, other: &AmdgpuRegStart) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (AmdgpuRegStart::Low(__self_0), AmdgpuRegStart::Low(__arg1_0))
                    => __self_0 == __arg1_0,
                (AmdgpuRegStart::High(__self_0),
                    AmdgpuRegStart::High(__arg1_0)) => __self_0 == __arg1_0,
                (AmdgpuRegStart::Full(__self_0),
                    AmdgpuRegStart::Full(__arg1_0)) => __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq,
278    #[automatically_derived]
impl ::core::cmp::PartialOrd for AmdgpuRegStart {
    #[inline]
    fn partial_cmp(&self, other: &AmdgpuRegStart)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (AmdgpuRegStart::Low(__self_0), AmdgpuRegStart::Low(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (AmdgpuRegStart::High(__self_0), AmdgpuRegStart::High(__arg1_0))
                => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (AmdgpuRegStart::Full(__self_0), AmdgpuRegStart::Full(__arg1_0))
                => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd,
279    #[automatically_derived]
impl ::core::hash::Hash for AmdgpuRegStart {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            AmdgpuRegStart::Low(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            AmdgpuRegStart::High(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            AmdgpuRegStart::Full(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash,
280    const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for
            AmdgpuRegStart {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    AmdgpuRegStart::Low(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    AmdgpuRegStart::High(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    AmdgpuRegStart::Full(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };rustc_macros::StableHash
281)]
282enum AmdgpuRegStart {
283    /// Low 16-bit of the register at this index
284    Low(u16),
285    /// High 16-bit of the register at this index
286    High(u16),
287    /// One or more 32-bit registers, starting at this index
288    Full(u16),
289}
290
291#[derive(
292    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::marker::Copy for AmdgpuInlineAsmReg { }Copy,
293    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::clone::Clone for AmdgpuInlineAsmReg {
    #[inline]
    fn clone(&self) -> AmdgpuInlineAsmReg {
        let _: ::core::clone::AssertParamIsClone<AmdgpuInlineAsmRegClass>;
        let _: ::core::clone::AssertParamIsClone<AmdgpuRegStart>;
        *self
    }
}Clone,
294    const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AmdgpuInlineAsmReg {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    AmdgpuInlineAsmReg {
                        class: ref __binding_0, range: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };rustc_macros::Encodable,
295    const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AmdgpuInlineAsmReg {
            fn decode(__decoder: &mut __D) -> Self {
                AmdgpuInlineAsmReg {
                    class: ::rustc_serialize::Decodable::decode(__decoder),
                    range: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };rustc_macros::Decodable,
296    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::fmt::Debug for AmdgpuInlineAsmReg {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "AmdgpuInlineAsmReg", "class", &self.class, "range", &&self.range)
    }
}Debug,
297    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::Eq for AmdgpuInlineAsmReg {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<AmdgpuInlineAsmRegClass>;
        let _: ::core::cmp::AssertParamIsEq<AmdgpuRegStart>;
    }
}Eq,
298    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialEq for AmdgpuInlineAsmReg {
    #[inline]
    fn eq(&self, other: &AmdgpuInlineAsmReg) -> bool {
        self.class == other.class && self.range == other.range
    }
}PartialEq,
299    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialOrd for AmdgpuInlineAsmReg {
    #[inline]
    fn partial_cmp(&self, other: &AmdgpuInlineAsmReg)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.class, &other.class)
            {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.range,
                    &other.range),
            cmp => cmp,
        }
    }
}PartialOrd,
300    #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::hash::Hash for AmdgpuInlineAsmReg {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.class, state);
        ::core::hash::Hash::hash(&self.range, state)
    }
}Hash,
301    const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for
            AmdgpuInlineAsmReg {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    AmdgpuInlineAsmReg {
                        class: ref __binding_0, range: ref __binding_1 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };rustc_macros::StableHash
302)]
303#[allow(non_camel_case_types)]
304pub struct AmdgpuInlineAsmReg {
305    class: AmdgpuInlineAsmRegClass,
306    range: AmdgpuRegStart,
307}
308
309impl AmdgpuInlineAsmReg {
310    pub fn name(self) -> String {
311        let c = self.class.prefix();
312        match self.range {
313            AmdgpuRegStart::Low(n) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}.l", c, n))
    })format!("{c}{n}.l"),
314            AmdgpuRegStart::High(n) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}.h", c, n))
    })format!("{c}{n}.h"),
315            AmdgpuRegStart::Full(n) if self.class.bytes() == 4 => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", c, n))
    })format!("{c}{n}"),
316            AmdgpuRegStart::Full(n) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}[{2}:{0}]",
                n + self.class.bytes() / 4 - 1, c, n))
    })format!("{c}[{n}:{}]", n + self.class.bytes() / 4 - 1),
317        }
318    }
319
320    pub fn reg_class(self) -> AmdgpuInlineAsmRegClass {
321        self.class
322    }
323
324    pub fn parse(name: &str) -> Result<Self, &'static str> {
325        if name.is_empty() {
326            return Err("invalid empty register");
327        }
328        // s or v
329        let prefix = name.chars().next().unwrap();
330        // Form with range, e.g. s[2:3]
331        let res;
332        if name[1..].starts_with('[') {
333            if !name.ends_with(']') {
334                return Err("invalid register, missing closing bracket");
335            }
336            if let Some((start, end)) = name[2..name.len() - 1].split_once(':') {
337                let Ok(start) = start.parse() else {
338                    return Err("invalid register range start");
339                };
340                let Ok(end) = end.parse() else {
341                    return Err("invalid register range end");
342                };
343
344                // Check range
345                if start > end {
346                    return Err("invalid reversed register range");
347                }
348
349                let class =
350                    AmdgpuInlineAsmRegClass::parse_with_prefix(prefix, ((end - start) + 1) * 32)?;
351                if end >= class.max_num() {
352                    return Err("too large register for this class");
353                }
354                res = Self { class, range: AmdgpuRegStart::Full(start) };
355            } else {
356                return Err("invalid register range");
357            }
358        } else {
359            let parse_num = |core: &str| {
360                let Ok(start) = core.parse() else {
361                    return Err("invalid register number");
362                };
363
364                let class = AmdgpuInlineAsmRegClass::parse_with_prefix(prefix, 32)?;
365                if start >= class.max_num() {
366                    return Err("too large register for this class");
367                }
368
369                Ok(start)
370            };
371
372            let name = &name[1..];
373            let class;
374            let range = if let Some(name) = name.strip_suffix(".l") {
375                class = AmdgpuInlineAsmRegClass::parse_with_prefix(prefix, 16)?;
376                if #[allow(non_exhaustive_omitted_patterns)] match class {
    AmdgpuInlineAsmRegClass::Sgpr(_) => true,
    _ => false,
}matches!(class, AmdgpuInlineAsmRegClass::Sgpr(_)) {
377                    return Err("invalid 16-bit SGPR register");
378                }
379                AmdgpuRegStart::Low(parse_num(name)?)
380            } else if let Some(name) = name.strip_suffix(".h") {
381                class = AmdgpuInlineAsmRegClass::parse_with_prefix(prefix, 16)?;
382                if #[allow(non_exhaustive_omitted_patterns)] match class {
    AmdgpuInlineAsmRegClass::Sgpr(_) => true,
    _ => false,
}matches!(class, AmdgpuInlineAsmRegClass::Sgpr(_)) {
383                    return Err("invalid 16-bit SGPR register");
384                }
385                AmdgpuRegStart::High(parse_num(name)?)
386            } else {
387                class = AmdgpuInlineAsmRegClass::parse_with_prefix(prefix, 32)?;
388                let start = parse_num(name)?;
389                AmdgpuRegStart::Full(start)
390            };
391            res = Self { class, range };
392        }
393        Ok(res)
394    }
395
396    pub fn validate(
397        self,
398        _arch: super::InlineAsmArch,
399        _reloc_model: crate::spec::RelocModel,
400        _target_features: &rustc_data_structures::fx::FxIndexSet<Symbol>,
401        _target: &crate::spec::Target,
402        _is_clobber: bool,
403    ) -> Result<(), &'static str> {
404        Ok(())
405    }
406}
407
408pub(super) fn fill_reg_map(
409    _arch: super::InlineAsmArch,
410    _reloc_model: crate::spec::RelocModel,
411    _target_features: &rustc_data_structures::fx::FxIndexSet<Symbol>,
412    _target: &crate::spec::Target,
413    map: &mut rustc_data_structures::fx::FxHashMap<
414        super::InlineAsmRegClass,
415        rustc_data_structures::fx::FxIndexSet<super::InlineAsmReg>,
416    >,
417) {
418    use super::{InlineAsmReg, InlineAsmRegClass};
419
420    #[allow(rustc::potential_query_instability)]
421    for class in regclass_map().keys() {
422        let InlineAsmRegClass::Amdgpu(class) = *class else { {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Must be amdgpu class")));
}unreachable!("Must be amdgpu class") };
423        if let Some(set) = map.get_mut(&InlineAsmRegClass::Amdgpu(class)) {
424            if class == AmdgpuInlineAsmRegClass::Vgpr(16) {
425                for i in 0..(class.max_num() / 2) {
426                    set.insert(InlineAsmReg::Amdgpu(AmdgpuInlineAsmReg {
427                        class,
428                        range: AmdgpuRegStart::Low(i),
429                    }));
430                    set.insert(InlineAsmReg::Amdgpu(AmdgpuInlineAsmReg {
431                        class,
432                        range: AmdgpuRegStart::High(i),
433                    }));
434                }
435            } else {
436                for i in 0..class.max_num() {
437                    set.insert(InlineAsmReg::Amdgpu(AmdgpuInlineAsmReg {
438                        class,
439                        range: AmdgpuRegStart::Full(i),
440                    }));
441                }
442            }
443        }
444    }
445}
446
447impl AmdgpuInlineAsmReg {
448    pub fn emit(
449        self,
450        out: &mut dyn fmt::Write,
451        _arch: InlineAsmArch,
452        _modifier: Option<char>,
453    ) -> fmt::Result {
454        out.write_str(&self.name())
455    }
456
457    pub fn overlapping_regs(self, mut cb: impl FnMut(AmdgpuInlineAsmReg)) {
458        if #[allow(non_exhaustive_omitted_patterns)] match self.class {
    AmdgpuInlineAsmRegClass::Vgpr(_) => true,
    _ => false,
}matches!(self.class, AmdgpuInlineAsmRegClass::Vgpr(_)) {
459            // Overlapping 16-bit registers (not supported for sgprs)
460            if let AmdgpuRegStart::Full(start) = self.range {
461                for i in start..(start + self.class.bytes().div_ceil(4) - 1) {
462                    cb(AmdgpuInlineAsmReg {
463                        class: AmdgpuInlineAsmRegClass::Vgpr(16),
464                        range: AmdgpuRegStart::Low(i),
465                    });
466                    cb(AmdgpuInlineAsmReg {
467                        class: AmdgpuInlineAsmRegClass::Vgpr(16),
468                        range: AmdgpuRegStart::High(i),
469                    });
470                }
471            }
472        }
473
474        // Overlapping 32-bit registers, up to size 32
475        for size in 1..=32 {
476            let (AmdgpuRegStart::Low(start)
477            | AmdgpuRegStart::High(start)
478            | AmdgpuRegStart::Full(start)) = self.range;
479
480            let size_range = size - 1;
481            for overlap_start in
482                start.saturating_sub(size_range)..=(start + self.class.bytes().div_ceil(4) - 1)
483            {
484                let class = match self.class {
485                    AmdgpuInlineAsmRegClass::Sgpr(_) => AmdgpuInlineAsmRegClass::Sgpr(size * 32),
486                    AmdgpuInlineAsmRegClass::Vgpr(_) => AmdgpuInlineAsmRegClass::Vgpr(size * 32),
487                };
488                cb(AmdgpuInlineAsmReg { class, range: AmdgpuRegStart::Full(overlap_start) });
489            }
490        }
491    }
492}