2

I'm developing a small language in Rust. To improve the performance, I'd like to use fastcall calling convention for x86. The "fastcall" ABI is not supported for ARM.

For x86:

fn add_primitive(&mut self, name: &str, action: extern "fastcall" fn(&mut Self)) {
    ...
}

extern "fastcall" fn a_primitive(&mut self) {}

For ARM:

fn add_primitive(&mut self, name: &str, action: fn(&mut Self)) {
    ...
}

fn a_primitive(&mut self) {}

Using C I can define a macro

#ifdef x86
#define PRIMITIVE extern "fastcall" fn
#endif
#ifdef arm
#define PRIMITIVE fn
#endif

fn add_primitive(&mut self, name: &str, action: PRIMITIVE(&mut Self)) {
    ...
}

PRIMITIVE a_primitive(&mut self) {}

I do not know how to solve this problem using Rust's macro system.

EDIT:

I need two different macros. I know how to use target_arch to define different versions of functions but not macros.

Stargateur
  • 24,473
  • 8
  • 65
  • 91
Cheng-Chang Wu
  • 187
  • 1
  • 7
  • 2
    Possible duplicate of [How to check in Rust if architecture is 32 or 64 bit?](https://stackoverflow.com/questions/41896462/how-to-check-in-rust-if-architecture-is-32-or-64-bit) - the question is slightly different, but the answer is the same. – Joe Clay Jun 05 '17 at 13:29
  • 1
    The answer to [How to check in Rust if architecture is 32 or 64 bit?](https://stackoverflow.com/questions/41896462/how-to-check-in-rust-if-architecture-is-32-or-64-bit) is not enough for my problem. Because I need two different version of macros. I know how to use target_arch to define different version of functions but not macros. – Cheng-Chang Wu Jun 05 '17 at 14:01
  • 2
    `#[cfg]` works on macros just like it does on functions. – DK. Jun 05 '17 at 14:55
  • Be aware that Rust's macros aren't just simple text substitution like they are in C. They have to expand to a whole 'thing' (an item, method, statement, expression, or pattern, to be precise). Your C example won't translate exactly into Rust. – Joe Clay Jun 05 '17 at 14:59
  • 1
    Generally I have seen stuff like this done by having two versions of the function, both annotated with `target_arch` (or a similar attribute) to determine which ends up in the final build. If they share functionality, pull that out into a separate function and then call it from both. – Joe Clay Jun 05 '17 at 14:59
  • IMO, a better approach would be to use generics instead of function pointers, which would let the compiler inline the function call, thus the calling convention becomes irrelevant. – Francis Gagné Jun 05 '17 at 23:11
  • Please post your solution in an answer, here your previous source https://stackoverflow.com/revisions/44369360/4. – Stargateur Jun 21 '17 at 05:47

1 Answers1

2
#[cfg(target_arch = "arm")]
#[macro_export]
macro_rules! primitive {
    (fn $args:tt) => { fn $args };
    (fn $f:ident $args:tt $body:tt) => { fn $f $args $body };
    (fn $f:ident $args:tt -> isize $body:tt) => { fn $f $args -> isize $body };
}

#[cfg(target_arch = "x86")]
#[macro_export]
macro_rules! primitive {
    (fn $args:tt) => { extern "fastcall" fn $args };
    (fn $f:ident $args:tt $body:tt) => { extern "fastcall" fn $f $args $body };
    (fn $f:ident $args:tt -> isize $body:tt) => { extern "fastcall" fn $f $args -> isize $body };
}

Example:

pub struct Word<Target> {
    symbol: Symbol,
    is_immediate: bool,
    is_compile_only: bool,
    hidden: bool,
    dfa: usize,
    cfa: usize,
    action: primitive!{ fn (&mut Target) },
    pub(crate) compilation_semantics: fn(&mut Target, usize),
}

primitive!{fn dup(&mut self) {
    let slen = self.s_stack().len.wrapping_add(1);
    self.s_stack().len = slen;
    self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(2)];
}}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • Can you put an example of how to use it? – Boiethios Jun 28 '17 at 07:58
  • @Boiethios This is a wiki answer feel free to improve it, I just create it because OP had answer in the question. I have no idea about how this work or what is the purpose. – Stargateur Jun 28 '17 at 08:04
  • 1
    I used it in my own Forth to define primitive forth words. Please see https://github.com/chengchangwu/rtforth/blob/master/src/core.rs . – Cheng-Chang Wu Jul 30 '17 at 07:44