1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 use proc_macro2::{Ident, Span, TokenStream};
5 use quote::{format_ident, quote, quote_spanned, ToTokens};
10 ops::{Deref, DerefMut},
11 sync::atomic::{AtomicU64, Ordering},
16 parse::{Parse, ParseStream},
17 punctuated::Punctuated,
22 macro_rules! append_assembly {
23 ($retval:ident;) => {};
24 ($retval:ident; $lit:literal $($tt:tt)*) => {
25 $crate::inline_assembly::ToAssembly::append_to($lit, &mut $retval);
26 append_assembly!($retval; $($tt)*);
28 ($retval:ident; input($arg_id:ident = {$($arg_tt:tt)*}) $($tt:tt)*) => {
30 let (arg, arg_id) = $crate::inline_assembly::Assembly::make_input(quote! {$($arg_tt)*});
31 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
34 append_assembly!($retval; $($tt)*);
36 ($retval:ident; input{$($arg_tt:tt)*} $($tt:tt)*) => {
38 let (arg, _arg_id) = $crate::inline_assembly::Assembly::make_input(quote! {$($arg_tt)*});
39 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
41 append_assembly!($retval; $($tt)*);
43 ($retval:ident; output($arg_id:ident = {$($arg_tt:tt)*}) $($tt:tt)*) => {
45 let (arg, arg_id) = $crate::inline_assembly::Assembly::make_output(quote! {$($arg_tt)*});
46 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
49 append_assembly!($retval; $($tt)*);
51 ($retval:ident; output{$($arg_tt:tt)*} $($tt:tt)*) => {
53 let (arg, _arg_id) = $crate::inline_assembly::Assembly::make_output(quote! {$($arg_tt)*});
54 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
56 append_assembly!($retval; $($tt)*);
58 ($retval:ident; clobber{$($arg_tt:tt)*} $($tt:tt)*) => {
59 $crate::inline_assembly::ToAssembly::append_to(
60 &$crate::inline_assembly::Assembly::make_clobber(quote::quote! {$($arg_tt)*}),
63 append_assembly!($retval; $($tt)*);
65 ($retval:ident; ($arg_id:ident) $($tt:tt)*) => {
66 $crate::inline_assembly::ToAssembly::append_to(&$arg_id, &mut $retval);
67 append_assembly!($retval; $($tt)*);
71 macro_rules! assembly {
73 $crate::inline_assembly::Assembly::new()
77 let mut retval = $crate::inline_assembly::Assembly::new();
78 append_assembly!(retval; $($tt)*);
84 pub(crate) trait ToAssembly {
85 /// appends `self` to `retval`
86 fn append_to(&self, retval: &mut Assembly);
88 fn to_assembly(&self) -> Assembly {
89 let mut retval = Assembly::default();
90 self.append_to(&mut retval);
94 fn into_assembly(self) -> Assembly
98 let mut retval = Assembly::default();
99 self.append_to(&mut retval);
104 impl<T: ToAssembly + ?Sized> ToAssembly for &'_ T {
105 fn append_to(&self, retval: &mut Assembly) {
106 (**self).append_to(retval);
109 fn to_assembly(&self) -> Assembly {
110 (**self).to_assembly()
114 impl<T: ToAssembly + ?Sized> ToAssembly for &'_ mut T {
115 fn append_to(&self, retval: &mut Assembly) {
116 (**self).append_to(retval);
119 fn to_assembly(&self) -> Assembly {
120 (**self).to_assembly()
124 impl<T: ToAssembly> ToAssembly for Box<T> {
125 fn append_to(&self, retval: &mut Assembly) {
126 (**self).append_to(retval);
129 fn to_assembly(&self) -> Assembly {
130 (**self).to_assembly()
133 fn into_assembly(self) -> Assembly {
134 (*self).into_assembly()
138 impl ToAssembly for str {
139 fn append_to(&self, retval: &mut Assembly) {
140 if let Some(AssemblyTextFragment::Text(text)) = retval.text_fragments.last_mut() {
145 .push(AssemblyTextFragment::Text(self.into()));
150 impl ToAssembly for String {
151 fn append_to(&self, retval: &mut Assembly) {
152 str::append_to(&self, retval)
156 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
157 pub(crate) struct AssemblyMetavariableId(u64);
159 impl AssemblyMetavariableId {
160 pub(crate) fn new() -> Self {
161 // don't start at zero to help avoid confusing id with indexes
162 static NEXT_ID: AtomicU64 = AtomicU64::new(10000);
163 AssemblyMetavariableId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
167 impl ToAssembly for AssemblyMetavariableId {
168 fn append_to(&self, retval: &mut Assembly) {
171 .push(AssemblyTextFragment::Metavariable(*self));
175 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
176 pub(crate) struct AssemblyArgId(u64);
179 pub(crate) fn new() -> Self {
180 // don't start at zero to help avoid confusing id with indexes
181 static NEXT_ID: AtomicU64 = AtomicU64::new(1000);
182 AssemblyArgId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
186 impl ToAssembly for AssemblyArgId {
187 fn append_to(&self, retval: &mut Assembly) {
190 .push(AssemblyTextFragment::ArgIndex(*self));
194 macro_rules! impl_assembly_arg {
199 $id:ident: AssemblyArgId,
203 #[derive(Debug, Clone)]
206 $($id: AssemblyArgId,)?
209 impl ToTokens for $name {
210 fn to_token_stream(&self) -> TokenStream {
214 fn into_token_stream(self) -> TokenStream {
218 fn to_tokens(&self, tokens: &mut TokenStream) {
219 self.tokens.to_tokens(tokens)
223 impl From<TokenStream> for $name {
224 fn from(tokens: TokenStream) -> Self {
227 $($id: AssemblyArgId::new(),)?
235 struct AssemblyInputArg {
242 struct AssemblyOutputArg {
249 struct AssemblyClobber {
254 #[derive(Debug, Clone)]
255 pub(crate) enum AssemblyTextFragment {
257 ArgIndex(AssemblyArgId),
258 Metavariable(AssemblyMetavariableId),
261 #[derive(Debug, Default, Clone)]
262 pub(crate) struct Assembly {
263 text_fragments: Vec<AssemblyTextFragment>,
264 inputs: Vec<AssemblyInputArg>,
265 outputs: Vec<AssemblyOutputArg>,
266 clobbers: Vec<AssemblyClobber>,
269 impl From<String> for Assembly {
270 fn from(text: String) -> Self {
272 text_fragments: vec![AssemblyTextFragment::Text(text)],
278 impl From<&'_ str> for Assembly {
279 fn from(text: &str) -> Self {
280 String::from(text).into()
284 impl From<AssemblyArgId> for Assembly {
285 fn from(arg_id: AssemblyArgId) -> Self {
287 text_fragments: vec![AssemblyTextFragment::ArgIndex(arg_id)],
293 impl From<&'_ AssemblyArgId> for Assembly {
294 fn from(arg_id: &AssemblyArgId) -> Self {
299 impl From<AssemblyMetavariableId> for Assembly {
300 fn from(arg_id: AssemblyMetavariableId) -> Self {
302 text_fragments: vec![AssemblyTextFragment::Metavariable(arg_id)],
308 impl From<&'_ AssemblyMetavariableId> for Assembly {
309 fn from(arg_id: &AssemblyMetavariableId) -> Self {
315 pub(crate) fn new() -> Self {
318 pub(crate) fn make_input(tokens: impl ToTokens) -> (Self, AssemblyArgId) {
319 let input: AssemblyInputArg = tokens.into_token_stream().into();
323 text_fragments: vec![AssemblyTextFragment::ArgIndex(id)],
330 pub(crate) fn make_output(tokens: impl ToTokens) -> (Self, AssemblyArgId) {
331 let output: AssemblyOutputArg = tokens.into_token_stream().into();
335 text_fragments: vec![AssemblyTextFragment::ArgIndex(id)],
336 outputs: vec![output],
342 pub(crate) fn make_clobber(tokens: impl ToTokens) -> Self {
344 clobbers: vec![tokens.into_token_stream().into()],
348 pub(crate) fn replace_metavariables<R>(
350 mut f: impl FnMut(AssemblyMetavariableId) -> Result<Assembly, R>,
351 ) -> Result<Assembly, R> {
352 let mut retval = self.args_without_text();
353 for text_fragment in &self.text_fragments {
354 match text_fragment {
355 AssemblyTextFragment::Text(text) => text.append_to(&mut retval),
356 AssemblyTextFragment::ArgIndex(id) => id.append_to(&mut retval),
357 AssemblyTextFragment::Metavariable(id) => f(*id)?.append_to(&mut retval),
362 pub(crate) fn args_without_text(&self) -> Assembly {
364 text_fragments: Vec::new(),
365 inputs: self.inputs.clone(),
366 outputs: self.outputs.clone(),
367 clobbers: self.clobbers.clone(),
370 pub(crate) fn text_without_args(&self) -> Assembly {
372 text_fragments: self.text_fragments.clone(),
375 clobbers: Vec::new(),
378 pub(crate) fn to_text(&self) -> String {
379 let mut id_index_map = HashMap::new();
380 for (index, id) in self
384 .chain(self.inputs.iter().map(|v| v.id))
387 if let Some(old_index) = id_index_map.insert(id, index) {
389 "duplicate id in inline assembly arguments: #{} and #{}\n{:#?}",
390 old_index, index, self
394 let mut retval = String::new();
395 for text_fragment in &self.text_fragments {
396 match text_fragment {
397 AssemblyTextFragment::Text(text) => retval += text,
398 AssemblyTextFragment::Metavariable(id) => {
400 "metavariables are not allowed when converting \
401 assembly to text: metavariable id={:?}\n{:#?}",
405 AssemblyTextFragment::ArgIndex(id) => {
406 if let Some(index) = id_index_map.get(id) {
407 write!(retval, "arg{}", index).unwrap();
410 "unknown id in inline assembly arguments: id={:?}\n{:#?}",
421 impl ToAssembly for Assembly {
422 fn append_to(&self, retval: &mut Assembly) {
423 retval.text_fragments.reserve(self.text_fragments.len());
424 for text_fragment in &self.text_fragments {
425 match *text_fragment {
426 AssemblyTextFragment::Text(ref text) => text.append_to(retval),
427 AssemblyTextFragment::Metavariable(id) => id.append_to(retval),
428 AssemblyTextFragment::ArgIndex(id) => id.append_to(retval),
431 retval.inputs.extend_from_slice(&self.inputs);
432 retval.outputs.extend_from_slice(&self.outputs);
433 retval.clobbers.extend_from_slice(&self.clobbers);
436 fn to_assembly(&self) -> Assembly {
440 fn into_assembly(self) -> Assembly {
445 #[derive(Debug, Clone)]
446 pub(crate) struct AssemblyWithTextSpan {
447 pub(crate) asm: Assembly,
448 pub(crate) text_span: Span,
451 impl Deref for AssemblyWithTextSpan {
452 type Target = Assembly;
454 fn deref(&self) -> &Self::Target {
459 impl DerefMut for AssemblyWithTextSpan {
460 fn deref_mut(&mut self) -> &mut Self::Target {
465 impl ToTokens for AssemblyWithTextSpan {
466 fn to_tokens(&self, tokens: &mut TokenStream) {
477 let mut args: Punctuated<TokenStream, Token![,]> = self
481 quote_spanned! {*text_span=>
486 let mut named_args = Vec::new();
487 let mut unnamed_args = Vec::new();
488 for (index, tokens) in outputs
491 .chain(inputs.iter().map(|v| &v.tokens))
494 match syn::parse2::<AsmArg>(tokens.clone())
495 .unwrap_or_else(|e| panic!("failed to parse AsmArg: {}\nTokens:\n{}", e, tokens))
498 AsmArgReg::RegClass(_) => {
499 let id = format_ident!("arg{}", index);
500 named_args.push(quote! { #id = #tokens });
502 AsmArgReg::RegLit(_) => unnamed_args.push(tokens.clone()),
505 args.extend(named_args);
506 args.extend(unnamed_args);
507 args.extend(clobbers.iter().map(ToTokens::to_token_stream));
511 value.to_tokens(tokens);
520 impl Parse for AsmArgReg {
521 fn parse(input: ParseStream) -> syn::Result<Self> {
522 if input.peek(Ident::peek_any) {
523 Ok(Self::RegClass(input.call(Ident::parse_any)?))
525 Ok(Self::RegLit(input.parse()?))
538 impl Parse for AsmArg {
539 fn parse(input: ParseStream) -> syn::Result<Self> {
542 io_kind: input.call(Ident::parse_any)?,
543 paren: parenthesized!(input2 in input),
544 reg: input2.parse()?,
545 body: input.parse()?,