Skip to main content

rustc_target/asm/
amdgpu.rs

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