1use crate::{Error, Result};
2use std::ffi::{CStr, CString};
3
4pub const TARGET_FAMILY: &CStr = c"amdgpu";
6pub const TARGET_KEY: &str = "gfx1151";
8
9#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct Target(CString);
19impl Target {
20 pub fn new(key: &str) -> Result<Self> {
24 if key.contains(':') {
25 return Err(Error::Message(format!(
26 "expected a bare AMDGPU target, found feature-suffixed name {key:?}"
27 )));
28 }
29 let suffix = key.strip_prefix("gfx").unwrap_or("");
30 if !(3..=4).contains(&suffix.len())
31 || !suffix
32 .bytes()
33 .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
34 {
35 return Err(Error::Message(format!("invalid AMDGPU target {key:?}")));
36 }
37 Ok(Self(
38 CString::new(key).expect("validated target has no NUL"),
39 ))
40 }
41 pub(crate) fn from_device_architecture(name: &str) -> Result<Self> {
44 Self::new(name.split(':').next().unwrap_or(name))
45 }
46 pub fn as_str(&self) -> &str {
48 self.0.to_str().expect("validated ASCII target")
49 }
50 pub(crate) fn as_c_str(&self) -> &CStr {
51 &self.0
52 }
53 pub fn manifest_key(&self) -> String {
55 format!("x86_64-unknown-linux-gnu-{}", self.as_str())
56 }
57}
58
59impl Default for Target {
60 fn default() -> Self {
61 Self::new(TARGET_KEY).expect("valid default target")
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 #[test]
69 fn device_features_are_separate_from_target_keys() {
70 for name in ["gfx90a", "gfx90a:sramecc+:xnack-", "gfx90a:xnack+"] {
71 assert_eq!(
72 Target::from_device_architecture(name).unwrap().as_str(),
73 "gfx90a"
74 );
75 }
76 assert!(Target::from_device_architecture(":xnack-").is_err());
77 assert!(Target::from_device_architecture("invalid:xnack-").is_err());
78 assert!(
79 Target::new("gfx90a:sramecc+:xnack-")
80 .unwrap_err()
81 .to_string()
82 .contains("bare AMDGPU target")
83 );
84 }
85}