1use proc_macro::TokenStream;
2use quote::{format_ident, quote, quote_spanned};
3use syn::{braced, parenthesized, parse_macro_input, token, Ident, LitInt, Result, Token};
4use syn::parse::{Parse, ParseStream};
5use syn::punctuated::Punctuated;
6use syn::token::Brace;
7
8
9struct ImportArgs {
10 arch: Ident,
11 _arrow: Token![=>],
12 _brace: Brace,
13 items: Punctuated<Ident, Token![,]>,
14}
15
16impl Parse for ImportArgs {
17 fn parse(input: ParseStream) -> Result<Self> {
18 let items;
19 Ok(Self {
20 arch: input.parse()?,
21 _arrow: input.parse()?,
22 _brace: braced!(items in input),
23 items: items.parse_terminated(Ident::parse)?,
24 })
25 }
26}
27
28
29#[proc_macro]
30pub fn import_offsets(item: TokenStream) -> TokenStream {
31 let offsets = parse_macro_input!(item as ImportArgs);
32 let mut output = quote!(
33 use vex_sys::Int;
34 );
35 for reg in &offsets.items {
36 let offset = format_ident!("OFFSET_{1}_{0}", reg, offsets.arch);
38 output = quote!(
39 #output
40 pub const #reg: Int = vex_sys::#offset as Int;
41 );
42 }
43 quote!(
45 #[allow(non_upper_case_globals)]
46 pub mod offset {
47 #output
48 }
49 ).into()
50}
51
52#[proc_macro]
53pub fn import_hwcaps(item: TokenStream) -> TokenStream {
54 let hwcaps = parse_macro_input!(item as ImportArgs);
55 let arch = hwcaps.arch.to_string().to_uppercase();
56 let mut output = quote!();
57 for hwcap in &hwcaps.items {
58 let offset = format_ident!("VEX_HWCAPS_{}_{}", arch, hwcap);
59 output = quote!(
60 #output
61 pub use vex_sys::#offset as #hwcap;
62 );
63 }
64 quote!(
65 pub mod hwcap {
66 #output
67 }
68 ).into()
69}
70
71struct TypeEnv {
72 tmps: Vec<(Ident, Token![:], Ident)>,
73}
74
75impl Parse for TypeEnv {
76 fn parse(input: ParseStream) -> Result<Self> {
77 let mut tmps = Vec::new();
78 while input.peek(Ident) && input.peek2(Token![:]) {
79 tmps.push((input.parse()?, input.parse()?, input.parse()?));
80 }
81 Ok(TypeEnv {
82 tmps,
83 })
84 }
85}
86
87mod kw {
88 syn::custom_keyword!(IR); syn::custom_keyword!(NoOp);
90 syn::custom_keyword!(IMark);
91 syn::custom_keyword!(AbiHint);
92 syn::custom_keyword!(CCall);
93 syn::custom_keyword!(PUT);
94 syn::custom_keyword!(GET);
95 syn::custom_keyword!(STbe);
96 syn::custom_keyword!(STle);
97 syn::custom_keyword!(LDbe);
98 syn::custom_keyword!(LDle);
99 syn::custom_keyword!(exit);
100}
101
102enum LoadEndness {
103 Big(kw::LDbe),
104 Little(kw::LDle),
105}
106
107enum StoreEndness {
108 Big(kw::STbe),
109 Little(kw::STle),
110}
111
112impl quote::ToTokens for LoadEndness {
113 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
114 tokens.extend(match self {
115 Self::Big(b) => quote_spanned!(b.span => IREndness::Iend_BE),
116 Self::Little(l) => quote_spanned!(l.span => IREndness::Iend_LE),
117 })
118 }
119}
120
121impl quote::ToTokens for StoreEndness {
122 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
123 tokens.extend(match self {
124 Self::Big(b) => quote_spanned!(b.span => IREndness::Iend_BE),
125 Self::Little(l) => quote_spanned!(l.span => IREndness::Iend_LE),
126 })
127 }
128}
129
130impl Parse for LoadEndness {
131 fn parse(input: ParseStream) -> Result<Self> {
132 let lookahead = input.lookahead1();
133 if lookahead.peek(kw::LDbe) {
134 input.parse().map(Self::Big)
135 } else if lookahead.peek(kw::LDle) {
136 input.parse().map(Self::Little)
137 } else {
138 Err(lookahead.error())
139 }
140 }
141}
142
143impl Parse for StoreEndness {
144 fn parse(input: ParseStream) -> Result<Self> {
145 let lookahead = input.lookahead1();
146 if lookahead.peek(kw::STbe) {
147 input.parse().map(Self::Big)
148 } else if lookahead.peek(kw::STle) {
149 input.parse().map(Self::Little)
150 } else {
151 Err(lookahead.error())
152 }
153 }
154}
155
156enum Expr {
157 Get(ExprGet),
158 Op(ExprOp),
159 Load(ExprLoad),
160 Const(ExprConst),
161 RdTmp(Ident),
162 CCall,
163}
164
165struct ExprGet {
166 _get: kw::GET,
167 _colon: Token![:],
168 size: Ident,
169 _paren: token::Paren,
170 offset: LitInt,
171}
172
173struct ExprOp {
174 op: Ident,
175 _paren: token::Paren,
176 args: Punctuated<Expr, Token![,]>,
177}
178
179struct ExprLoad {
180 end: LoadEndness,
181 _colon: Token![:],
182 ty: Ident,
183 _paren: token::Paren,
184 addr: Box<Expr>,
185}
186
187struct ExprConst {
188 co: LitInt,
189 _colon: Token![:],
190 ty: Ident,
191}
192
193impl Parse for Expr {
194 fn parse(input: ParseStream) -> Result<Self> {
195 let lookahead = input.lookahead1();
196 if lookahead.peek(kw::GET) {
197 input.parse().map(Self::Get)
198 } else if lookahead.peek(kw::LDle) || lookahead.peek(kw::LDbe) {
199 input.parse().map(Self::Load)
200 } else if lookahead.peek(LitInt) {
201 input.parse().map(Self::Const)
202 } else if lookahead.peek(Ident) && input.peek2(token::Paren) {
203 input.parse().map(Self::Op)
204 } else if lookahead.peek(Ident) {
205 input.parse().map(Self::RdTmp)
206 } else {
207 Err(lookahead.error())
208 }
209 }
210}
211
212impl Parse for ExprGet {
213 fn parse(input: ParseStream) -> Result<Self> {
214 let offset;
215 Ok(Self {
216 _get: input.parse()?,
217 _colon: input.parse()?,
218 size: input.parse()?,
219 _paren: parenthesized!(offset in input),
220 offset: offset.parse()?,
221 })
222 }
223}
224
225impl Parse for ExprLoad {
226 fn parse(input: ParseStream) -> Result<Self> {
227 let addr;
228 Ok(Self {
229 end: input.parse()?,
230 _colon: input.parse()?,
231 ty: input.parse()?,
232 _paren: parenthesized!(addr in input),
233 addr: addr.parse()?
234 })
235 }
236}
237
238impl Parse for ExprConst {
239 fn parse(input: ParseStream) -> Result<Self> {
240 Ok(Self {
241 co: input.parse()?,
242 _colon: input.parse()?,
243 ty: input.parse()?,
244 })
245 }
246}
247
248impl Parse for ExprOp {
249 fn parse(input: ParseStream) -> Result<Self> {
250 let args;
251 Ok(Self {
252 op: input.parse()?,
253 _paren: parenthesized!(args in input),
254 args: args.parse_terminated(Expr::parse)?,
255 })
256 }
257}
258
259impl quote::ToTokens for Expr {
260 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
261 match self {
262 Self::Get(get) => get.to_tokens(tokens),
263 Self::Op(op) => op.to_tokens(tokens),
264 Self::Const(co) => co.to_tokens(tokens),
265 Self::RdTmp(tmp) => tokens.extend(quote!(Expr::rd_tmp(#tmp))),
266 Self::Load(load) => load.to_tokens(tokens),
267 Self::CCall => tokens.extend(quote!(Expr::ccall())),
268 }
269 }
270}
271
272impl quote::ToTokens for ExprGet {
273 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
274 let offset = &self.offset;
275 let ty = format_ident!("Ity_{}", self.size);
276 tokens.extend(quote!(Expr::get(#offset, Type::#ty)))
277 }
278}
279
280impl quote::ToTokens for ExprOp {
281 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
282 let op = format_ident!("Iop_{}", &self.op);
283 let args = &self.args;
284 match self.args.len() {
285 1 => tokens.extend(quote!(Expr::unop(Op::#op, #args))),
286 2 => tokens.extend(quote!(Expr::binop(Op::#op, #args))),
287 3 => tokens.extend(quote!(Expr::triop(Op::#op, #args))),
288 4 => tokens.extend(quote!(Expr::qop(Op::#op, #args))),
289 _ => panic!(),
290 }
291 }
292}
293
294impl quote::ToTokens for ExprLoad {
295 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
296 let (end, addr) = (&self.end, &self.addr);
297 let ty = format_ident!("Ity_{}", self.ty);
298 tokens.extend(quote!(Expr::load(#end, Type::#ty, #addr)))
299 }
300}
301
302impl quote::ToTokens for ExprConst {
303 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
304 tokens.extend(match self.ty.to_string().as_str() {
305 "I1" => match self.co.base10_parse() {
306 Ok(0) => quote!(Expr::const_(Const::u1(false))),
307 Ok(1) => quote!(Expr::const_(Const::u1(true))),
308 _ => quote!(compile_error!("Const of type I1 must be 0 or 1")),
309 }
310 "I8" => {
311 let co = &self.co;
312 quote!(Expr::const_(Const::u8(#co)))
313 }
314 "I16" => {
315 let co = &self.co;
316 quote!(Expr::const_(Const::u16(#co)))
317 }
318 "I32" => {
319 let co = &self.co;
320 quote!(Expr::const_(Const::u32(#co)))
321 }
322 "I64" => {
323 let co = &self.co;
324 quote!(Expr::const_(Const::u64(#co)))
325 }
326 _ => quote!(compile_error!("Invalid type")),
327 });
328 }
329}
330
331enum Stmt {
332 NoOp(StmtNoOp),
333 IMark(StmtIMark),
334 AbiHint(StmtAbiHint),
335 WrTmp(StmtWrTmp),
336 Put(StmtPut),
337 Store(StmtStore),
338}
339
340struct StmtNoOp {
341 _ir: kw::IR,
342 _dash: Token![-],
343 _no_op: kw::NoOp,
344}
345
346struct StmtIMark {
347 _imark: kw::IMark,
348 _paren: token::Paren,
349 info: Punctuated<LitInt, Token![,]>,
350}
351
352struct StmtAbiHint {
353 base: Expr,
354 len: LitInt,
355 nia: Expr,
356}
357
358struct StmtWrTmp {
359 tmp: Ident,
360 _eq: Token![=],
361 data: Expr,
362}
363
364struct StmtPut {
365 _put: kw::PUT,
366 _paren: token::Paren,
367 offset: LitInt,
368 _eq: Token![=],
369 data: Expr,
370}
371
372struct StmtStore {
373 store: StoreEndness,
374 _paren: token::Paren,
375 addr: Expr,
376 _eq: Token![=],
377 data: Expr,
378}
379
380impl Parse for Stmt {
381 fn parse(input: ParseStream) -> Result<Self> {
382 let lookahead = input.lookahead1();
383 if lookahead.peek(kw::IR) {
384 input.parse().map(Self::NoOp)
385 } else if lookahead.peek(Token![-]) || lookahead.peek(kw::IMark) {
386 input.parse().map(Self::IMark)
387 } else if lookahead.peek(Token![=]) || lookahead.peek(kw::AbiHint) {
388 input.parse().map(Self::AbiHint)
389 } else if lookahead.peek(kw::PUT) {
390 input.parse().map(Self::Put)
391 } else if lookahead.peek(kw::STbe) || lookahead.peek(kw::STle) {
392 input.parse().map(Self::Store)
393 } else if lookahead.peek(Ident) {
394 input.parse().map(Self::WrTmp)
395 } else {
396 Err(lookahead.error())
397 }
398 }
399}
400
401impl Parse for StmtNoOp {
402 fn parse(input: ParseStream) -> Result<Self> {
403 Ok(Self {
404 _ir: input.parse()?,
405 _dash: input.parse()?,
406 _no_op: input.parse()?,
407 })
408 }
409}
410
411impl Parse for StmtIMark {
412 fn parse(input: ParseStream) -> Result<Self> {
413 while input.parse::<Token![-]>().is_ok() {}
414 let info;
415 let res = Self {
416 _imark: input.parse()?,
417 _paren: parenthesized!(info in input),
418 info: info.parse_terminated(LitInt::parse)?
419 };
420 while input.parse::<Token![-]>().is_ok() {}
421 Ok(res)
422 }
423}
424
425
426enum AbiArg {
427 Expr(Expr),
428 Int(LitInt),
429}
430
431impl AbiArg {
432 fn expect_expr(self) -> syn::Result<Expr> {
433 match self {
434 Self::Expr(expr) => Ok(expr),
435 _ => panic!(),
436 }
437 }
438
439 fn expect_lit(self) -> syn::Result<LitInt> {
440 match self {
441 Self::Int(lit) => Ok(lit),
442 _ => panic!(),
443 }
444 }
445}
446
447
448impl Parse for AbiArg {
449 fn parse(input: ParseStream) -> Result<Self> {
450 let lookahead = input.lookahead1();
451 if lookahead.peek(LitInt) {
452 input.parse().map(Self::Int)
453 } else {
454 input.parse().map(Self::Expr)
455 }
456 }
457}
458
459
460impl Parse for StmtAbiHint {
461 fn parse(input: ParseStream) -> Result<Self> {
462 while input.parse::<Token![=]>().is_ok() {}
463 let info;
464 let _abi_hint: kw::AbiHint = input.parse()?;
465 let _paren = parenthesized!(info in input);
466 let info = info.parse_terminated::<_, Token![,]>(AbiArg::parse)?;
467 let mut info_iter = info.into_iter();
468
469 let res = Self {
470 base: info_iter.next().unwrap().expect_expr()?,
471 len: info_iter.next().unwrap().expect_lit()?,
472 nia: info_iter.next().unwrap().expect_expr()?,
473 };
474 while input.parse::<Token![=]>().is_ok() {}
475 Ok(res)
476 }
477}
478
479impl Parse for StmtWrTmp {
480 fn parse(input: ParseStream) -> Result<Self> {
481 Ok(Self {
482 tmp: input.parse()?,
483 _eq: input.parse()?,
484 data: input.parse()?,
485 })
486 }
487}
488
489impl Parse for StmtPut {
490 fn parse(input: ParseStream) -> Result<Self> {
491 let offset;
492 Ok(Self {
493 _put: input.parse()?,
494 _paren: parenthesized!(offset in input),
495 offset: offset.parse()?,
496 _eq: input.parse()?,
497 data: input.parse()?,
498 })
499 }
500}
501
502impl Parse for StmtStore {
503 fn parse(input: ParseStream) -> Result<Self> {
504 let addr;
505 Ok(Self {
506 store: input.parse()?,
507 _paren: parenthesized!(addr in input),
508 addr: addr.parse()?,
509 _eq: input.parse()?,
510 data: input.parse()?,
511 })
512 }
513}
514
515impl quote::ToTokens for Stmt {
516 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
517 match self {
518 Self::NoOp(..) => tokens.extend(quote!(Stmt::no_op())),
519 Self::IMark(imark) => imark.to_tokens(tokens),
520 Self::AbiHint(hint) => hint.to_tokens(tokens),
521 Self::WrTmp(wr_tmp) => wr_tmp.to_tokens(tokens),
522 Self::Put(put) => put.to_tokens(tokens),
523 Self::Store(store) => store.to_tokens(tokens),
524 }
525 }
526}
527
528impl quote::ToTokens for StmtIMark {
529 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
530 let info = &self.info;
531 tokens.extend(quote!(Stmt::imark(#info)))
532 }
533}
534
535impl quote::ToTokens for StmtAbiHint {
536 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
537 let StmtAbiHint {
538 base,
539 len,
540 nia,
541 } = self;
542 tokens.extend(quote!(Stmt::abi_hint(#base, #len, #nia)))
543 }
544}
545
546impl quote::ToTokens for StmtWrTmp {
547 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
548 let (tmp, data) = (&self.tmp, &self.data);
549 tokens.extend(quote!(Stmt::wr_tmp(#tmp, #data)))
550 }
551}
552
553impl quote::ToTokens for StmtPut {
554 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
555 let (offset, data) = (&self.offset, &self.data);
556 tokens.extend(quote!(Stmt::put(#offset, #data)))
557 }
558}
559
560impl quote::ToTokens for StmtStore {
561 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
562 let (end, addr, data) = (&self.store, &self.addr, &self.data);
563 tokens.extend(quote!(Stmt::store(#end, #addr, #data)))
564 }
565}
566
567struct ExitKind {
568 _semi: Token![;],
569 _exit: kw::exit,
570 _dash: Token![-],
571 kind: Ident,
572}
573
574impl Parse for ExitKind {
575 fn parse(input: ParseStream) -> Result<Self> {
576 Ok(Self {
577 _semi: input.parse()?,
578 _exit: input.parse()?,
579 _dash: input.parse()?,
580 kind: input.parse()?,
581 })
582 }
583}
584
585struct IRSB {
586 ty_env: TypeEnv,
587 stmts: Vec<Stmt>,
588 exit: ExitKind,
589}
590
591impl Parse for IRSB {
592 fn parse(input: ParseStream) -> Result<Self> {
593 let ty_env = input.parse()?;
594 let mut stmts = Vec::new();
595 while !(input.is_empty() || input.peek(Token![;])) {
596 stmts.push(input.parse()?);
597 }
598 Ok(IRSB {
599 ty_env,
600 stmts,
601 exit: input.parse()?
602 })
603 }
604}
605
606#[allow(non_snake_case)]
607#[proc_macro]
608pub fn IRSB(item: TokenStream) -> TokenStream {
609 let irsb = parse_macro_input!(item as IRSB);
610
611 let (ip_offset, next, stmts) = match irsb.stmts.split_last() {
612 Some((Stmt::Put(StmtPut { offset, data, .. }), stmts)) => {
613 (offset, data, stmts)
614 }
615 Some(_) => {
616 return quote!(compile_error!("The last statement is not a valid 'next' statement (PUT(ip_offset) = Expr)")).into();
617 }
618 None => {
619 return quote!(compile_error!("No statements found! (There must be at least the 'next' statement.)")).into();
620 }
621 };
622 let jk = format_ident!("Ijk_{}", &irsb.exit.kind);
623 let mut output = quote!{
624 use libvex::ir::{Const, Expr, IREndness, IRSB, JumpKind, Op, Stmt, Type};
625 let mut irsb = IRSB::new();
626 };
627 for (tmp, _colon, ty) in irsb.ty_env.tmps.iter() {
628 let ty = format_ident!("Ity_{}", ty);
629 output = quote!{
630 #output
631 let #tmp = irsb.type_env().new_tmp(Type::#ty);
632 };
633 }
634 for stmt in stmts {
635 output = quote!{
636 #output
637 irsb.add_stmt(#stmt);
638 };
639 }
640 quote!(unsafe {
641 #output
642 irsb.set_next(#next);
643 irsb.set_offs_ip(#ip_offset);
644 irsb.set_jump_kind(JumpKind::#jk);
645 irsb
646 }).into()
647}