1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 use proc_macro2::{Span, TokenStream};
5 use quote::{quote, ToTokens};
10 ops::{Deref, DerefMut},
11 sync::atomic::{AtomicU64, Ordering},
15 macro_rules! append_assembly {
16 ($retval:ident;) => {};
17 ($retval:ident; $lit:literal $($tt:tt)*) => {
18 $crate::inline_assembly::ToAssembly::append_to($lit, &mut $retval);
19 append_assembly!($retval; $($tt)*);
21 ($retval:ident; input($arg_id:ident = {$($arg_tt:tt)*}) $($tt:tt)*) => {
23 let (arg, arg_id) = $crate::inline_assembly::Assembly::make_input(quote! {$($arg_tt)*});
24 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
27 append_assembly!($retval; $($tt)*);
29 ($retval:ident; input{$($arg_tt:tt)*} $($tt:tt)*) => {
31 let (arg, _arg_id) = $crate::inline_assembly::Assembly::make_input(quote! {$($arg_tt)*});
32 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
34 append_assembly!($retval; $($tt)*);
36 ($retval:ident; output($arg_id:ident = {$($arg_tt:tt)*}) $($tt:tt)*) => {
38 let (arg, arg_id) = $crate::inline_assembly::Assembly::make_output(quote! {$($arg_tt)*});
39 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
42 append_assembly!($retval; $($tt)*);
44 ($retval:ident; output{$($arg_tt:tt)*} $($tt:tt)*) => {
46 let (arg, _arg_id) = $crate::inline_assembly::Assembly::make_output(quote! {$($arg_tt)*});
47 $crate::inline_assembly::ToAssembly::append_to(&arg, &mut $retval);
49 append_assembly!($retval; $($tt)*);
51 ($retval:ident; clobber{$($arg_tt:tt)*} $($tt:tt)*) => {
52 $crate::inline_assembly::ToAssembly::append_to(
53 &$crate::inline_assembly::Assembly::make_clobber(quote::quote! {$($arg_tt)*}),
56 append_assembly!($retval; $($tt)*);
58 ($retval:ident; ($arg_id:ident) $($tt:tt)*) => {
59 $crate::inline_assembly::ToAssembly::append_to(&$arg_id, &mut $retval);
60 append_assembly!($retval; $($tt)*);
64 macro_rules! assembly {
66 $crate::inline_assembly::Assembly::new()
70 let mut retval = $crate::inline_assembly::Assembly::new();
71 append_assembly!(retval; $($tt)*);
77 pub(crate) trait ToAssembly {
78 /// appends `self` to `retval`
79 fn append_to(&self, retval: &mut Assembly);
81 fn to_assembly(&self) -> Assembly {
82 let mut retval = Assembly::default();
83 self.append_to(&mut retval);
87 fn into_assembly(self) -> Assembly
91 let mut retval = Assembly::default();
92 self.append_to(&mut retval);
97 impl<T: ToAssembly + ?Sized> ToAssembly for &'_ T {
98 fn append_to(&self, retval: &mut Assembly) {
99 (**self).append_to(retval);
102 fn to_assembly(&self) -> Assembly {
103 (**self).to_assembly()
107 impl<T: ToAssembly + ?Sized> ToAssembly for &'_ mut T {
108 fn append_to(&self, retval: &mut Assembly) {
109 (**self).append_to(retval);
112 fn to_assembly(&self) -> Assembly {
113 (**self).to_assembly()
117 impl<T: ToAssembly> ToAssembly for Box<T> {
118 fn append_to(&self, retval: &mut Assembly) {
119 (**self).append_to(retval);
122 fn to_assembly(&self) -> Assembly {
123 (**self).to_assembly()
126 fn into_assembly(self) -> Assembly {
127 (*self).into_assembly()
131 impl ToAssembly for str {
132 fn append_to(&self, retval: &mut Assembly) {
133 if let Some(AssemblyTextFragment::Text(text)) = retval.text_fragments.last_mut() {
138 .push(AssemblyTextFragment::Text(self.into()));
143 impl ToAssembly for String {
144 fn append_to(&self, retval: &mut Assembly) {
145 str::append_to(&self, retval)
149 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
150 pub(crate) struct AssemblyMetavariableId(u64);
152 impl AssemblyMetavariableId {
153 pub(crate) fn new() -> Self {
154 // don't start at zero to help avoid confusing id with indexes
155 static NEXT_ID: AtomicU64 = AtomicU64::new(10000);
156 AssemblyMetavariableId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
160 impl ToAssembly for AssemblyMetavariableId {
161 fn append_to(&self, retval: &mut Assembly) {
164 .push(AssemblyTextFragment::Metavariable(*self));
168 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
169 pub(crate) struct AssemblyArgId(u64);
172 pub(crate) fn new() -> Self {
173 // don't start at zero to help avoid confusing id with indexes
174 static NEXT_ID: AtomicU64 = AtomicU64::new(1000);
175 AssemblyArgId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
179 impl ToAssembly for AssemblyArgId {
180 fn append_to(&self, retval: &mut Assembly) {
183 .push(AssemblyTextFragment::ArgIndex(*self));
187 macro_rules! impl_assembly_arg {
192 $id:ident: AssemblyArgId,
196 #[derive(Debug, Clone)]
199 $($id: AssemblyArgId,)?
202 impl ToTokens for $name {
203 fn to_token_stream(&self) -> TokenStream {
207 fn into_token_stream(self) -> TokenStream {
211 fn to_tokens(&self, tokens: &mut TokenStream) {
212 self.tokens.to_tokens(tokens)
216 impl From<TokenStream> for $name {
217 fn from(tokens: TokenStream) -> Self {
220 $($id: AssemblyArgId::new(),)?
228 struct AssemblyInputArg {
235 struct AssemblyOutputArg {
242 struct AssemblyClobber {
247 #[derive(Debug, Clone)]
248 pub(crate) enum AssemblyTextFragment {
250 ArgIndex(AssemblyArgId),
251 Metavariable(AssemblyMetavariableId),
254 #[derive(Debug, Default, Clone)]
255 pub(crate) struct Assembly {
256 text_fragments: Vec<AssemblyTextFragment>,
257 inputs: Vec<AssemblyInputArg>,
258 outputs: Vec<AssemblyOutputArg>,
259 clobbers: Vec<AssemblyClobber>,
262 impl From<String> for Assembly {
263 fn from(text: String) -> Self {
265 text_fragments: vec![AssemblyTextFragment::Text(text)],
271 impl From<&'_ str> for Assembly {
272 fn from(text: &str) -> Self {
273 String::from(text).into()
277 impl From<AssemblyArgId> for Assembly {
278 fn from(arg_id: AssemblyArgId) -> Self {
280 text_fragments: vec![AssemblyTextFragment::ArgIndex(arg_id)],
286 impl From<&'_ AssemblyArgId> for Assembly {
287 fn from(arg_id: &AssemblyArgId) -> Self {
292 impl From<AssemblyMetavariableId> for Assembly {
293 fn from(arg_id: AssemblyMetavariableId) -> Self {
295 text_fragments: vec![AssemblyTextFragment::Metavariable(arg_id)],
301 impl From<&'_ AssemblyMetavariableId> for Assembly {
302 fn from(arg_id: &AssemblyMetavariableId) -> Self {
308 pub(crate) fn new() -> Self {
311 pub(crate) fn make_input(tokens: impl ToTokens) -> (Self, AssemblyArgId) {
312 let input: AssemblyInputArg = tokens.into_token_stream().into();
316 text_fragments: vec![AssemblyTextFragment::ArgIndex(id)],
323 pub(crate) fn make_output(tokens: impl ToTokens) -> (Self, AssemblyArgId) {
324 let output: AssemblyOutputArg = tokens.into_token_stream().into();
328 text_fragments: vec![AssemblyTextFragment::ArgIndex(id)],
329 outputs: vec![output],
335 pub(crate) fn make_clobber(tokens: impl ToTokens) -> Self {
337 clobbers: vec![tokens.into_token_stream().into()],
341 pub(crate) fn replace_metavariables<R>(
343 mut f: impl FnMut(AssemblyMetavariableId) -> Result<Assembly, R>,
344 ) -> Result<Assembly, R> {
345 let mut retval = self.args_without_text();
346 for text_fragment in &self.text_fragments {
347 match text_fragment {
348 AssemblyTextFragment::Text(text) => text.append_to(&mut retval),
349 AssemblyTextFragment::ArgIndex(id) => id.append_to(&mut retval),
350 AssemblyTextFragment::Metavariable(id) => f(*id)?.append_to(&mut retval),
355 pub(crate) fn args_without_text(&self) -> Assembly {
357 text_fragments: Vec::new(),
358 inputs: self.inputs.clone(),
359 outputs: self.outputs.clone(),
360 clobbers: self.clobbers.clone(),
363 pub(crate) fn text_without_args(&self) -> Assembly {
365 text_fragments: self.text_fragments.clone(),
368 clobbers: Vec::new(),
371 pub(crate) fn to_text(&self) -> String {
372 let mut id_index_map = HashMap::new();
373 for (index, id) in self
377 .chain(self.inputs.iter().map(|v| v.id))
380 if let Some(old_index) = id_index_map.insert(id, index) {
382 "duplicate id in inline assembly arguments: #{} and #{}\n{:#?}",
383 old_index, index, self
387 let mut retval = String::new();
388 for text_fragment in &self.text_fragments {
389 match text_fragment {
390 AssemblyTextFragment::Text(text) => retval += text,
391 AssemblyTextFragment::Metavariable(id) => {
393 "metavariables are not allowed when converting \
394 assembly to text: metavariable id={:?}\n{:#?}",
398 AssemblyTextFragment::ArgIndex(id) => {
399 if let Some(index) = id_index_map.get(id) {
400 write!(retval, "{}", index).unwrap();
403 "unknown id in inline assembly arguments: id={:?}\n{:#?}",
414 impl ToAssembly for Assembly {
415 fn append_to(&self, retval: &mut Assembly) {
416 retval.text_fragments.reserve(self.text_fragments.len());
417 for text_fragment in &self.text_fragments {
418 match *text_fragment {
419 AssemblyTextFragment::Text(ref text) => text.append_to(retval),
420 AssemblyTextFragment::Metavariable(id) => id.append_to(retval),
421 AssemblyTextFragment::ArgIndex(id) => id.append_to(retval),
424 retval.inputs.extend_from_slice(&self.inputs);
425 retval.outputs.extend_from_slice(&self.outputs);
426 retval.clobbers.extend_from_slice(&self.clobbers);
429 fn to_assembly(&self) -> Assembly {
433 fn into_assembly(self) -> Assembly {
438 #[derive(Debug, Clone)]
439 pub(crate) struct AssemblyWithTextSpan {
440 pub(crate) asm: Assembly,
441 pub(crate) text_span: Span,
444 impl Deref for AssemblyWithTextSpan {
445 type Target = Assembly;
447 fn deref(&self) -> &Self::Target {
452 impl DerefMut for AssemblyWithTextSpan {
453 fn deref_mut(&mut self) -> &mut Self::Target {
458 impl ToTokens for AssemblyWithTextSpan {
459 fn to_tokens(&self, tokens: &mut TokenStream) {
470 let text = LitStr::new(&self.to_text(), text_span.clone());
472 llvm_asm!(#text : #(#outputs),* : #(#inputs),* : #(#clobbers),*)
474 value.to_tokens(tokens);