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};
11 marker::PhantomPinned,
12 ops::{Add, AddAssign, Deref, DerefMut},
15 sync::atomic::{AtomicU64, Ordering},
19 pub(crate) trait ToAssembly {
20 fn to_assembly(&self) -> Assembly;
23 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
24 pub(crate) struct AssemblyArgId(u64);
27 pub(crate) fn new() -> Self {
28 // don't start at zero to help avoid confusing id with indexes
29 static NEXT_ID: AtomicU64 = AtomicU64::new(1000);
30 AssemblyArgId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
34 macro_rules! impl_assembly_arg {
36 $vis:vis struct $name:ident {
39 $id:ident: AssemblyArgId,
43 #[derive(Debug, Clone)]
46 $($id: AssemblyArgId,)?
50 $vis fn new(tokens: impl ToTokens) -> Self {
51 tokens.into_token_stream().into()
55 impl ToTokens for $name {
56 fn to_token_stream(&self) -> TokenStream {
60 fn into_token_stream(self) -> TokenStream {
64 fn to_tokens(&self, tokens: &mut TokenStream) {
65 self.tokens.to_tokens(tokens)
69 impl From<TokenStream> for $name {
70 fn from(tokens: TokenStream) -> Self {
73 $($id: AssemblyArgId::new(),)?
81 pub(crate) struct AssemblyInputArg {
88 pub(crate) struct AssemblyOutputArg {
95 pub(crate) struct AssemblyClobber {
100 #[derive(Debug, Clone)]
101 pub(crate) enum AssemblyTextFragment {
103 ArgIndex(AssemblyArgId),
106 #[derive(Debug, Default, Clone)]
107 pub(crate) struct Assembly {
108 text_fragments: Vec<AssemblyTextFragment>,
109 inputs: Vec<AssemblyInputArg>,
110 outputs: Vec<AssemblyOutputArg>,
111 clobbers: Vec<AssemblyClobber>,
114 impl From<String> for Assembly {
115 fn from(text: String) -> Self {
117 text_fragments: vec![AssemblyTextFragment::Text(text)],
123 impl From<&'_ str> for Assembly {
124 fn from(text: &str) -> Self {
125 String::from(text).into()
130 pub(crate) fn new() -> Self {
133 pub(crate) fn to_text(&self) -> String {
134 let mut id_index_map = HashMap::new();
135 for (index, id) in self
139 .chain(self.inputs.iter().map(|v| v.id))
142 if let Some(old_index) = id_index_map.insert(id, index) {
144 "duplicate id in inline assembly arguments: #{} and #{}\n{:#?}",
145 old_index, index, self
149 let mut retval = String::new();
150 for text_fragment in &self.text_fragments {
151 match text_fragment {
152 AssemblyTextFragment::Text(text) => retval += text,
153 AssemblyTextFragment::ArgIndex(id) => {
154 if let Some(index) = id_index_map.get(id) {
155 write!(retval, "{}", index).unwrap();
158 "unknown id in inline assembly arguments: id={:?}\n{:#?}",
169 impl AddAssign<&'_ Assembly> for Assembly {
170 fn add_assign(&mut self, rhs: &Assembly) {
177 text_fragments.reserve(rhs.text_fragments.len());
178 for text_fragment in &rhs.text_fragments {
179 match *text_fragment {
180 AssemblyTextFragment::Text(ref rhs_text) => {
181 if let Some(AssemblyTextFragment::Text(text)) = text_fragments.last_mut() {
184 text_fragments.push(AssemblyTextFragment::Text(rhs_text.clone()));
187 AssemblyTextFragment::ArgIndex(id) => {
188 self.text_fragments.push(AssemblyTextFragment::ArgIndex(id));
192 inputs.extend_from_slice(&rhs.inputs);
193 outputs.extend_from_slice(&rhs.outputs);
194 clobbers.extend_from_slice(&rhs.clobbers);
198 impl AddAssign<Assembly> for Assembly {
199 fn add_assign(&mut self, rhs: Assembly) {
204 impl Add for Assembly {
205 type Output = Assembly;
207 fn add(mut self, rhs: Self) -> Self::Output {
213 impl Add<&'_ Assembly> for Assembly {
214 type Output = Assembly;
216 fn add(mut self, rhs: &Assembly) -> Self::Output {
222 impl Add<Assembly> for &'_ Assembly {
223 type Output = Assembly;
225 fn add(self, rhs: Assembly) -> Self::Output {
226 Assembly::clone(self) + rhs
230 impl Add<&'_ Assembly> for &'_ Assembly {
231 type Output = Assembly;
233 fn add(self, rhs: &Assembly) -> Self::Output {
234 Assembly::clone(self) + rhs
238 #[derive(Debug, Clone)]
239 pub(crate) struct AssemblyWithTextSpan {
240 pub(crate) asm: Assembly,
241 pub(crate) text_span: Span,
244 impl Deref for AssemblyWithTextSpan {
245 type Target = Assembly;
247 fn deref(&self) -> &Self::Target {
252 impl DerefMut for AssemblyWithTextSpan {
253 fn deref_mut(&mut self) -> &mut Self::Target {
258 impl ToTokens for AssemblyWithTextSpan {
259 fn to_tokens(&self, tokens: &mut TokenStream) {
270 let text = LitStr::new(&self.to_text(), text_span.clone());
272 llvm_asm!(#text : #(#outputs),* : #(#inputs),* : #(#clobbers),*)
274 value.to_tokens(tokens);