123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- #![deny(warnings)]
- extern crate proc_macro;
- #[macro_use]
- extern crate quote;
- extern crate core;
- extern crate proc_macro2;
- #[macro_use]
- extern crate syn;
- use proc_macro2::Span;
- use syn::{
- parse::{self, Parse},
- spanned::Spanned,
- FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
- };
- use proc_macro::TokenStream;
- #[proc_macro_attribute]
- pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
- let f = parse_macro_input!(input as ItemFn);
-
- if f.sig.inputs.len() > 3 {
- return parse::Error::new(
- f.sig.inputs.last().unwrap().span(),
- "`#[entry]` function has too many arguments",
- )
- .to_compile_error()
- .into();
- }
- for arg in &f.sig.inputs {
- match arg {
- FnArg::Receiver(_) => {
- return parse::Error::new(arg.span(), "invalid argument")
- .to_compile_error()
- .into();
- }
- FnArg::Typed(t) => {
- if !is_simple_type(&t.ty, "usize") {
- return parse::Error::new(t.ty.span(), "argument type must be usize")
- .to_compile_error()
- .into();
- }
- }
- }
- }
-
- let valid_signature = f.sig.constness.is_none()
- && f.sig.asyncness.is_none()
- && f.vis == Visibility::Inherited
- && f.sig.abi.is_none()
- && f.sig.generics.params.is_empty()
- && f.sig.generics.where_clause.is_none()
- && f.sig.variadic.is_none()
- && match f.sig.output {
- ReturnType::Default => false,
- ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)),
- };
- if !valid_signature {
- return parse::Error::new(
- f.span(),
- "`#[entry]` function must have signature `[unsafe] fn([arg0: usize, ...]) -> !`",
- )
- .to_compile_error()
- .into();
- }
- if !args.is_empty() {
- return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
- .to_compile_error()
- .into();
- }
-
- let attrs = f.attrs;
- let unsafety = f.sig.unsafety;
- let args = f.sig.inputs;
- let stmts = f.block.stmts;
- quote!(
- #[allow(non_snake_case)]
- #[export_name = "main"]
- #(#attrs)*
- pub #unsafety fn __risc_v_rt__main(#args) -> ! {
- #(#stmts)*
- }
- )
- .into()
- }
- #[allow(unused)]
- fn is_simple_type(ty: &Type, name: &str) -> bool {
- if let Type::Path(p) = ty {
- if p.qself.is_none() && p.path.leading_colon.is_none() && p.path.segments.len() == 1 {
- let segment = p.path.segments.first().unwrap();
- if segment.ident == name && segment.arguments == PathArguments::None {
- return true;
- }
- }
- }
- false
- }
- #[proc_macro_attribute]
- pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
- let f = parse_macro_input!(input as ItemFn);
-
- let valid_signature = f.sig.constness.is_none()
- && f.sig.asyncness.is_none()
- && f.vis == Visibility::Inherited
- && f.sig.unsafety.is_some()
- && f.sig.abi.is_none()
- && f.sig.inputs.is_empty()
- && f.sig.generics.params.is_empty()
- && f.sig.generics.where_clause.is_none()
- && f.sig.variadic.is_none()
- && match f.sig.output {
- ReturnType::Default => true,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Tuple(ref tuple) => tuple.elems.is_empty(),
- _ => false,
- },
- };
- if !valid_signature {
- return parse::Error::new(
- f.span(),
- "`#[pre_init]` function must have signature `unsafe fn()`",
- )
- .to_compile_error()
- .into();
- }
- if !args.is_empty() {
- return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
- .to_compile_error()
- .into();
- }
-
- let attrs = f.attrs;
- let ident = f.sig.ident;
- let block = f.block;
- quote!(
- #[export_name = "__pre_init"]
- #(#attrs)*
- pub unsafe fn #ident() #block
- )
- .into()
- }
- struct AsmLoopArgs {
- asm_template: String,
- count: usize,
- }
- impl Parse for AsmLoopArgs {
- fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
- let template: LitStr = input.parse().unwrap();
- _ = input.parse::<Token![,]>().unwrap();
- let count: LitInt = input.parse().unwrap();
- Ok(Self {
- asm_template: template.value(),
- count: count.base10_parse().unwrap(),
- })
- }
- }
- #[proc_macro]
- pub fn loop_asm(input: TokenStream) -> TokenStream {
- let args = parse_macro_input!(input as AsmLoopArgs);
- let tokens = (0..args.count)
- .map(|i| {
- let i = i.to_string();
- let asm = args.asm_template.replace("{}", &i);
- format!("core::arch::asm!(\"{}\");", asm)
- })
- .collect::<Vec<String>>()
- .join("\n");
- tokens.parse().unwrap()
- }
|