From 4204e0216a5b8b5fef8c538022683e8a4545424c Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 2 Sep 2021 15:39:36 -0700 Subject: [PATCH] compiles new inline asm without errors --- .../src/inline_assembly.rs | 73 +++++++++++++++++-- .../src/instructions.rs | 28 +++---- .../src/lib.rs | 12 ++- 3 files changed, 92 insertions(+), 21 deletions(-) diff --git a/power-instruction-analyzer-proc-macro/src/inline_assembly.rs b/power-instruction-analyzer-proc-macro/src/inline_assembly.rs index 4dbb02f..172bdc0 100644 --- a/power-instruction-analyzer-proc-macro/src/inline_assembly.rs +++ b/power-instruction-analyzer-proc-macro/src/inline_assembly.rs @@ -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::(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 { + 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 { + let input2; + Ok(Self { + io_kind: input.call(Ident::parse_any)?, + paren: parenthesized!(input2 in input), + reg: input2.parse()?, + body: input.parse()?, + }) + } +} diff --git a/power-instruction-analyzer-proc-macro/src/instructions.rs b/power-instruction-analyzer-proc-macro/src/instructions.rs index 81dd20a..2530199 100644 --- a/power-instruction-analyzer-proc-macro/src/instructions.rs +++ b/power-instruction-analyzer-proc-macro/src/instructions.rs @@ -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; diff --git a/power-instruction-analyzer-proc-macro/src/lib.rs b/power-instruction-analyzer-proc-macro/src/lib.rs index 2ad3309..923363b 100644 --- a/power-instruction-analyzer-proc-macro/src/lib.rs +++ b/power-instruction-analyzer-proc-macro/src/lib.rs @@ -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(), } -- 2.30.2