compiles new inline asm without errors
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 2 Sep 2021 22:39:36 +0000 (15:39 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 2 Sep 2021 22:39:36 +0000 (15:39 -0700)
power-instruction-analyzer-proc-macro/src/inline_assembly.rs
power-instruction-analyzer-proc-macro/src/instructions.rs
power-instruction-analyzer-proc-macro/src/lib.rs

index 4dbb02fa02bddd27cbb24124c8bc17cccdf7b683..172bdc0289df051399d0e9b1891436430579b855 100644 (file)
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: LGPL-2.1-or-later
 // See Notices.txt for copyright information
 
-use proc_macro2::{Span, TokenStream};
-use quote::{quote, quote_spanned, ToTokens};
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::{format_ident, quote, quote_spanned, ToTokens};
 use std::{
     collections::HashMap,
     fmt::Write,
@@ -10,7 +10,14 @@ use std::{
     ops::{Deref, DerefMut},
     sync::atomic::{AtomicU64, Ordering},
 };
-use syn::{punctuated::Punctuated, LitStr, Token};
+use syn::{
+    ext::IdentExt,
+    parenthesized,
+    parse::{Parse, ParseStream},
+    punctuated::Punctuated,
+    token::Paren,
+    LitStr, Token,
+};
 
 macro_rules! append_assembly {
     ($retval:ident;) => {};
@@ -397,7 +404,7 @@ impl Assembly {
                 }
                 AssemblyTextFragment::ArgIndex(id) => {
                     if let Some(index) = id_index_map.get(id) {
-                        write!(retval, "{}", index).unwrap();
+                        write!(retval, "arg{}", index).unwrap();
                     } else {
                         panic!(
                             "unknown id in inline assembly arguments: id={:?}\n{:#?}",
@@ -476,8 +483,27 @@ impl ToTokens for AssemblyWithTextSpan {
                 }
             })
             .collect();
-        args.extend(outputs.iter().map(ToTokens::to_token_stream));
-        args.extend(inputs.iter().map(ToTokens::to_token_stream));
+        let mut named_args = Vec::new();
+        let mut unnamed_args = Vec::new();
+        for (index, tokens) in outputs
+            .iter()
+            .map(|v| &v.tokens)
+            .chain(inputs.iter().map(|v| &v.tokens))
+            .enumerate()
+        {
+            match syn::parse2::<AsmArg>(tokens.clone())
+                .unwrap_or_else(|e| panic!("failed to parse AsmArg: {}\nTokens:\n{}", e, tokens))
+                .reg
+            {
+                AsmArgReg::RegClass(_) => {
+                    let id = format_ident!("arg{}", index);
+                    named_args.push(quote! { #id = #tokens });
+                }
+                AsmArgReg::RegLit(_) => unnamed_args.push(tokens.clone()),
+            }
+        }
+        args.extend(named_args);
+        args.extend(unnamed_args);
         args.extend(clobbers.iter().map(ToTokens::to_token_stream));
         let value = quote! {
             asm!(#args)
@@ -485,3 +511,38 @@ impl ToTokens for AssemblyWithTextSpan {
         value.to_tokens(tokens);
     }
 }
+
+enum AsmArgReg {
+    RegClass(Ident),
+    RegLit(LitStr),
+}
+
+impl Parse for AsmArgReg {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        if input.peek(Ident::peek_any) {
+            Ok(Self::RegClass(input.call(Ident::parse_any)?))
+        } else {
+            Ok(Self::RegLit(input.parse()?))
+        }
+    }
+}
+
+#[allow(dead_code)]
+struct AsmArg {
+    io_kind: Ident,
+    paren: Paren,
+    reg: AsmArgReg,
+    body: TokenStream,
+}
+
+impl Parse for AsmArg {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let input2;
+        Ok(Self {
+            io_kind: input.call(Ident::parse_any)?,
+            paren: parenthesized!(input2 in input),
+            reg: input2.parse()?,
+            body: input.parse()?,
+        })
+    }
+}
index 81dd20a1df74a4fe28ea57ac05c94286a9bc41fe..253019996f0ebfd47b49221385925029e089af7a 100644 (file)
@@ -606,10 +606,10 @@ impl Instruction {
                 "or {" (xer_out) "}, {" (xer_out) "}, {" input{in(reg_nonzero) xer_in} "}"
             });
             before_instr_asm_lines.push(assembly! {
-                "mtxer $" (xer_out) clobber{"xer"}
+                "mtxer {" (xer_out) "}" clobber{out("xer") _}
             });
             after_instr_asm_lines.push(assembly! {
-                "mfxer $" (xer_out)
+                "mfxer {" (xer_out) "}"
             });
             if need_carry_output {
                 after_asm.push(quote! {
@@ -627,7 +627,7 @@ impl Instruction {
                 let cr: u32;
             });
             after_instr_asm_lines.push(assembly! {
-                "mfcr $" output{"=&b"(cr)} clobber{"cr"}
+                "mfcr {" output{out(reg_nonzero) cr} "}" clobber{out("cr") _}
             });
         }
         let mut asm_instrs = asm_instr;
@@ -653,12 +653,14 @@ impl Instruction {
             // and https://bugs.llvm.org/show_bug.cgi?id=47812
             before_asm.push(quote! {let lr_temp: u64;});
             let lr_temp;
-            before_instr_asm_lines.push(assembly! {"mflr $" output(lr_temp = {"=&b"(lr_temp)})});
-            after_instr_asm_lines.push(assembly! {"mtlr $" (lr_temp)});
+            before_instr_asm_lines
+                .push(assembly! {"mflr {" output(lr_temp = {out(reg_nonzero) lr_temp}) "}"});
+            after_instr_asm_lines.push(assembly! {"mtlr {" (lr_temp) "}"});
             before_asm.push(quote! {let ctr_temp: u64;});
             let ctr_temp;
-            before_instr_asm_lines.push(assembly! {"mfctr $" output(ctr_temp = {"=&b"(ctr_temp)})});
-            after_instr_asm_lines.push(assembly! {"mtctr $" (ctr_temp)});
+            before_instr_asm_lines
+                .push(assembly! {"mfctr {" output(ctr_temp = {out(reg_nonzero) ctr_temp}) "}"});
+            after_instr_asm_lines.push(assembly! {"mtctr {" (ctr_temp) "}"});
             let template = mem::replace(&mut asm_instrs, assembly! {});
             let target_temp;
             before_asm.push(quote! {let target_temp: u64;});
@@ -668,11 +670,11 @@ impl Instruction {
                 asm_instrs;
                 "bl 3f\n"
                 "4:\n"
-                "mulli $" output(target_temp = {"=&b"(target_temp)}) ", $" input{"b"(immediate)} ", 1f - 0f\n"
-                "addi $" (target_temp) ", $" (target_temp) ", 0f - 4b\n"
-                "mflr $" output(target_temp2 = {"=&b"(target_temp2)}) "\n"
-                "add $" (target_temp) ", $" (target_temp) ", $" (target_temp2) "\n"
-                "mtctr $" (target_temp) "\n"
+                "mulli {" output(target_temp = {out(reg_nonzero) target_temp}) "}, {" input{in(reg_nonzero) immediate} "}, 1f - 0f\n"
+                "addi {" (target_temp) "}, {" (target_temp) "}, 0f - 4b\n"
+                "mflr {" output(target_temp2 = {out(reg_nonzero) target_temp2}) "}\n"
+                "add {" (target_temp) "}, {" (target_temp) "}, {" (target_temp2) "}\n"
+                "mtctr {" (target_temp) "}\n"
                 "bctrl\n"
                 "b 2f\n"
                 "3:\n"
@@ -721,7 +723,7 @@ impl Instruction {
         };
         Ok(quote! {
             pub fn #fn_name(inputs: InstructionInput) -> InstructionResult {
-                #![allow(unused_variables, unused_assignments)]
+                #![allow(unused_variables, unused_assignments, unused_mut)]
                 #(#before_asm)*
                 unsafe {
                     #asm;
index 2ad330940821db5295a29431c59afce5c38b92b0..923363bb490356b40d819b1ae556cf7e5e356f47 100644 (file)
@@ -7,6 +7,8 @@ mod instructions;
 
 use instructions::Instructions;
 use proc_macro::TokenStream;
+use quote::quote;
+use std::{env, fs, path::Path};
 use syn::parse_macro_input;
 
 #[proc_macro]
@@ -14,8 +16,14 @@ pub fn instructions(input: TokenStream) -> TokenStream {
     let input = parse_macro_input!(input as Instructions);
     match input.to_tokens() {
         Ok(retval) => {
-            eprintln!("macro output:\n----------\n{}\n----------", retval);
-            retval
+            fs::write(
+                Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("out.rs"),
+                retval.to_string(),
+            )
+            .unwrap();
+            quote! {
+                include!(concat!(env!("CARGO_MANIFEST_DIR"), "/out.rs"));
+            }
         }
         Err(err) => err.to_compile_error(),
     }