mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 04:57:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			373 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use proc_macro2::TokenStream;
 | |
| use quote::{format_ident, quote, ToTokens, TokenStreamExt};
 | |
| use serde::de::{self, MapAccess, Visitor};
 | |
| use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize};
 | |
| use std::fmt;
 | |
| 
 | |
| use crate::{
 | |
|     context::{self, Context},
 | |
|     typekinds::{BaseType, BaseTypeKind},
 | |
|     wildstring::WildString,
 | |
| };
 | |
| 
 | |
| #[derive(Debug, Clone, Serialize, Deserialize)]
 | |
| #[serde(untagged)]
 | |
| pub enum InstructionAssertion {
 | |
|     Basic(WildString),
 | |
|     WithArgs(WildString, WildString),
 | |
| }
 | |
| 
 | |
| impl InstructionAssertion {
 | |
|     fn build(&mut self, ctx: &Context) -> context::Result {
 | |
|         match self {
 | |
|             InstructionAssertion::Basic(ws) => ws.build_acle(ctx.local),
 | |
|             InstructionAssertion::WithArgs(ws, args_ws) => [ws, args_ws]
 | |
|                 .into_iter()
 | |
|                 .try_for_each(|ws| ws.build_acle(ctx.local)),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl ToTokens for InstructionAssertion {
 | |
|     fn to_tokens(&self, tokens: &mut TokenStream) {
 | |
|         let instr = format_ident!(
 | |
|             "{}",
 | |
|             match self {
 | |
|                 Self::Basic(instr) => instr,
 | |
|                 Self::WithArgs(instr, _) => instr,
 | |
|             }
 | |
|             .to_string()
 | |
|         );
 | |
|         tokens.append_all(quote! { #instr });
 | |
| 
 | |
|         if let Self::WithArgs(_, args) = self {
 | |
|             let ex: TokenStream = args
 | |
|                 .to_string()
 | |
|                 .parse()
 | |
|                 .expect("invalid instruction assertion arguments expression given");
 | |
|             tokens.append_all(quote! {, #ex})
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Asserts that the given instruction is present for the intrinsic of the associated type bitsize.
 | |
| #[derive(Debug, Clone, Serialize, Deserialize)]
 | |
| #[serde(remote = "Self")]
 | |
| pub struct InstructionAssertionMethodForBitsize {
 | |
|     pub default: InstructionAssertion,
 | |
|     pub byte: Option<InstructionAssertion>,
 | |
|     pub halfword: Option<InstructionAssertion>,
 | |
|     pub word: Option<InstructionAssertion>,
 | |
|     pub doubleword: Option<InstructionAssertion>,
 | |
| }
 | |
| 
 | |
| impl InstructionAssertionMethodForBitsize {
 | |
|     fn build(&mut self, ctx: &Context) -> context::Result {
 | |
|         if let Some(ref mut byte) = self.byte {
 | |
|             byte.build(ctx)?
 | |
|         }
 | |
|         if let Some(ref mut halfword) = self.halfword {
 | |
|             halfword.build(ctx)?
 | |
|         }
 | |
|         if let Some(ref mut word) = self.word {
 | |
|             word.build(ctx)?
 | |
|         }
 | |
|         if let Some(ref mut doubleword) = self.doubleword {
 | |
|             doubleword.build(ctx)?
 | |
|         }
 | |
|         self.default.build(ctx)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Serialize for InstructionAssertionMethodForBitsize {
 | |
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | |
|     where
 | |
|         S: serde::Serializer,
 | |
|     {
 | |
|         match self {
 | |
|             InstructionAssertionMethodForBitsize {
 | |
|                 default: InstructionAssertion::Basic(instr),
 | |
|                 byte: None,
 | |
|                 halfword: None,
 | |
|                 word: None,
 | |
|                 doubleword: None,
 | |
|             } => serializer.serialize_str(&instr.to_string()),
 | |
|             InstructionAssertionMethodForBitsize {
 | |
|                 default: InstructionAssertion::WithArgs(instr, args),
 | |
|                 byte: None,
 | |
|                 halfword: None,
 | |
|                 word: None,
 | |
|                 doubleword: None,
 | |
|             } => {
 | |
|                 let mut seq = serializer.serialize_seq(Some(2))?;
 | |
|                 seq.serialize_element(&instr.to_string())?;
 | |
|                 seq.serialize_element(&args.to_string())?;
 | |
|                 seq.end()
 | |
|             }
 | |
|             _ => InstructionAssertionMethodForBitsize::serialize(self, serializer),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'de> Deserialize<'de> for InstructionAssertionMethodForBitsize {
 | |
|     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 | |
|     where
 | |
|         D: Deserializer<'de>,
 | |
|     {
 | |
|         struct IAMVisitor;
 | |
| 
 | |
|         impl<'de> Visitor<'de> for IAMVisitor {
 | |
|             type Value = InstructionAssertionMethodForBitsize;
 | |
| 
 | |
|             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 | |
|                 formatter.write_str("array, string or map")
 | |
|             }
 | |
| 
 | |
|             fn visit_str<E>(self, value: &str) -> Result<InstructionAssertionMethodForBitsize, E>
 | |
|             where
 | |
|                 E: de::Error,
 | |
|             {
 | |
|                 Ok(InstructionAssertionMethodForBitsize {
 | |
|                     default: InstructionAssertion::Basic(value.parse().map_err(E::custom)?),
 | |
|                     byte: None,
 | |
|                     halfword: None,
 | |
|                     word: None,
 | |
|                     doubleword: None,
 | |
|                 })
 | |
|             }
 | |
| 
 | |
|             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
 | |
|             where
 | |
|                 A: de::SeqAccess<'de>,
 | |
|             {
 | |
|                 use serde::de::Error;
 | |
|                 let make_err =
 | |
|                     || Error::custom("invalid number of arguments passed to assert_instruction");
 | |
|                 let instruction = seq.next_element()?.ok_or_else(make_err)?;
 | |
|                 let args = seq.next_element()?.ok_or_else(make_err)?;
 | |
| 
 | |
|                 if let Some(true) = seq.size_hint().map(|len| len > 0) {
 | |
|                     Err(make_err())
 | |
|                 } else {
 | |
|                     Ok(InstructionAssertionMethodForBitsize {
 | |
|                         default: InstructionAssertion::WithArgs(instruction, args),
 | |
|                         byte: None,
 | |
|                         halfword: None,
 | |
|                         word: None,
 | |
|                         doubleword: None,
 | |
|                     })
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             fn visit_map<M>(self, map: M) -> Result<InstructionAssertionMethodForBitsize, M::Error>
 | |
|             where
 | |
|                 M: MapAccess<'de>,
 | |
|             {
 | |
|                 InstructionAssertionMethodForBitsize::deserialize(
 | |
|                     de::value::MapAccessDeserializer::new(map),
 | |
|                 )
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         deserializer.deserialize_any(IAMVisitor)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Asserts that the given instruction is present for the intrinsic of the associated type.
 | |
| #[derive(Debug, Clone, Serialize, Deserialize)]
 | |
| #[serde(remote = "Self")]
 | |
| pub struct InstructionAssertionMethod {
 | |
|     /// Instruction for integer intrinsics
 | |
|     pub default: InstructionAssertionMethodForBitsize,
 | |
|     /// Instruction for floating-point intrinsics (optional)
 | |
|     #[serde(default)]
 | |
|     pub float: Option<InstructionAssertionMethodForBitsize>,
 | |
|     /// Instruction for unsigned integer intrinsics (optional)
 | |
|     #[serde(default)]
 | |
|     pub unsigned: Option<InstructionAssertionMethodForBitsize>,
 | |
| }
 | |
| 
 | |
| impl InstructionAssertionMethod {
 | |
|     pub(crate) fn build(&mut self, ctx: &Context) -> context::Result {
 | |
|         if let Some(ref mut float) = self.float {
 | |
|             float.build(ctx)?
 | |
|         }
 | |
|         if let Some(ref mut unsigned) = self.unsigned {
 | |
|             unsigned.build(ctx)?
 | |
|         }
 | |
|         self.default.build(ctx)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Serialize for InstructionAssertionMethod {
 | |
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | |
|     where
 | |
|         S: serde::Serializer,
 | |
|     {
 | |
|         match self {
 | |
|             InstructionAssertionMethod {
 | |
|                 default:
 | |
|                     InstructionAssertionMethodForBitsize {
 | |
|                         default: InstructionAssertion::Basic(instr),
 | |
|                         byte: None,
 | |
|                         halfword: None,
 | |
|                         word: None,
 | |
|                         doubleword: None,
 | |
|                     },
 | |
|                 float: None,
 | |
|                 unsigned: None,
 | |
|             } => serializer.serialize_str(&instr.to_string()),
 | |
|             InstructionAssertionMethod {
 | |
|                 default:
 | |
|                     InstructionAssertionMethodForBitsize {
 | |
|                         default: InstructionAssertion::WithArgs(instr, args),
 | |
|                         byte: None,
 | |
|                         halfword: None,
 | |
|                         word: None,
 | |
|                         doubleword: None,
 | |
|                     },
 | |
|                 float: None,
 | |
|                 unsigned: None,
 | |
|             } => {
 | |
|                 let mut seq = serializer.serialize_seq(Some(2))?;
 | |
|                 seq.serialize_element(&instr.to_string())?;
 | |
|                 seq.serialize_element(&args.to_string())?;
 | |
|                 seq.end()
 | |
|             }
 | |
|             _ => InstructionAssertionMethod::serialize(self, serializer),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'de> Deserialize<'de> for InstructionAssertionMethod {
 | |
|     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 | |
|     where
 | |
|         D: Deserializer<'de>,
 | |
|     {
 | |
|         struct IAMVisitor;
 | |
| 
 | |
|         impl<'de> Visitor<'de> for IAMVisitor {
 | |
|             type Value = InstructionAssertionMethod;
 | |
| 
 | |
|             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 | |
|                 formatter.write_str("array, string or map")
 | |
|             }
 | |
| 
 | |
|             fn visit_str<E>(self, value: &str) -> Result<InstructionAssertionMethod, E>
 | |
|             where
 | |
|                 E: de::Error,
 | |
|             {
 | |
|                 Ok(InstructionAssertionMethod {
 | |
|                     default: InstructionAssertionMethodForBitsize {
 | |
|                         default: InstructionAssertion::Basic(value.parse().map_err(E::custom)?),
 | |
|                         byte: None,
 | |
|                         halfword: None,
 | |
|                         word: None,
 | |
|                         doubleword: None,
 | |
|                     },
 | |
|                     float: None,
 | |
|                     unsigned: None,
 | |
|                 })
 | |
|             }
 | |
| 
 | |
|             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
 | |
|             where
 | |
|                 A: de::SeqAccess<'de>,
 | |
|             {
 | |
|                 use serde::de::Error;
 | |
|                 let make_err =
 | |
|                     || Error::custom("invalid number of arguments passed to assert_instruction");
 | |
|                 let instruction = seq.next_element()?.ok_or_else(make_err)?;
 | |
|                 let args = seq.next_element()?.ok_or_else(make_err)?;
 | |
| 
 | |
|                 if let Some(true) = seq.size_hint().map(|len| len > 0) {
 | |
|                     Err(make_err())
 | |
|                 } else {
 | |
|                     Ok(InstructionAssertionMethod {
 | |
|                         default: InstructionAssertionMethodForBitsize {
 | |
|                             default: InstructionAssertion::WithArgs(instruction, args),
 | |
|                             byte: None,
 | |
|                             halfword: None,
 | |
|                             word: None,
 | |
|                             doubleword: None,
 | |
|                         },
 | |
|                         float: None,
 | |
|                         unsigned: None,
 | |
|                     })
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             fn visit_map<M>(self, map: M) -> Result<InstructionAssertionMethod, M::Error>
 | |
|             where
 | |
|                 M: MapAccess<'de>,
 | |
|             {
 | |
|                 InstructionAssertionMethod::deserialize(de::value::MapAccessDeserializer::new(map))
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         deserializer.deserialize_any(IAMVisitor)
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Debug)]
 | |
| pub struct InstructionAssertionsForBaseType<'a>(
 | |
|     pub &'a Vec<InstructionAssertionMethod>,
 | |
|     pub &'a Option<&'a BaseType>,
 | |
| );
 | |
| 
 | |
| impl<'a> ToTokens for InstructionAssertionsForBaseType<'a> {
 | |
|     fn to_tokens(&self, tokens: &mut TokenStream) {
 | |
|         self.0.iter().for_each(
 | |
|             |InstructionAssertionMethod {
 | |
|                  default,
 | |
|                  float,
 | |
|                  unsigned,
 | |
|              }| {
 | |
|                 let kind = self.1.map(|ty| ty.kind());
 | |
|                 let instruction = match (kind, float, unsigned) {
 | |
|                     (None, float, unsigned) if float.is_some() || unsigned.is_some() => {
 | |
|                         unreachable!(
 | |
|                         "cannot determine the base type kind for instruction assertion: {self:#?}")
 | |
|                     }
 | |
|                     (Some(BaseTypeKind::Float), Some(float), _) => float,
 | |
|                     (Some(BaseTypeKind::UInt), _, Some(unsigned)) => unsigned,
 | |
|                     _ => default,
 | |
|                 };
 | |
| 
 | |
|                 let bitsize = self.1.and_then(|ty| ty.get_size().ok());
 | |
|                 let instruction = match (bitsize, instruction) {
 | |
|                     (
 | |
|                         Some(8),
 | |
|                         InstructionAssertionMethodForBitsize {
 | |
|                             byte: Some(byte), ..
 | |
|                         },
 | |
|                     ) => byte,
 | |
|                     (
 | |
|                         Some(16),
 | |
|                         InstructionAssertionMethodForBitsize {
 | |
|                             halfword: Some(halfword),
 | |
|                             ..
 | |
|                         },
 | |
|                     ) => halfword,
 | |
|                     (
 | |
|                         Some(32),
 | |
|                         InstructionAssertionMethodForBitsize {
 | |
|                             word: Some(word), ..
 | |
|                         },
 | |
|                     ) => word,
 | |
|                     (
 | |
|                         Some(64),
 | |
|                         InstructionAssertionMethodForBitsize {
 | |
|                             doubleword: Some(doubleword),
 | |
|                             ..
 | |
|                         },
 | |
|                     ) => doubleword,
 | |
|                     (_, InstructionAssertionMethodForBitsize { default, .. }) => default,
 | |
|                 };
 | |
| 
 | |
|                 tokens.append_all(quote! { #[cfg_attr(test, assert_instr(#instruction))]})
 | |
|             },
 | |
|         );
 | |
|     }
 | |
| }
 | 
