4

I'd like to clean up my assembly code and povide a way to call "NOP" multiple times through a macro:

#define NOP() asm(" nop")

#define NOP_N( N ) \
    NOP(); \
    NOP(); \
    .... call NOP() N times

I can't figure if this is possible in a macro.

Obviously, for performance reasons, I don't want something like this:

#define NOP_N( n ) { register int i; for(i=0;i<n;i++) asm(" nop"); }

Which defeats the purpose of NOP:

L17:                                    ; NOP_N(3);
        nop
        addi      1,r0                  ; Unsigned
        cmpi      3,r0
        blo       L17

The code is in C and assembly, so no C++ can be involved in here. Also, the compiler is fairly old and doesn't support variadic macros...

4

3 回答 3

7

我不认为无界的解决方案N是可能的。对于有界N的,您可以执行以下操作:

#define REPEAT_0(WHAT)
#define REPEAT_1(WHAT) WHAT REPEAT_0(WHAT)
#define REPEAT_2(WHAT) WHAT REPEAT_1(WHAT)
#define REPEAT_3(WHAT) WHAT REPEAT_2(WHAT)

#define NOP_N(N) REPEAT_##N(asm("nop");)

第一部分可以很容易地自动生成。第二部分采用的技术有时称为令牌粘贴

于 2013-05-17T09:01:48.027 回答
2

那么这个C预处理器图灵是否完整?

#define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__

和 REPEAT_INDIRECT

#define REPEAT(count, macro, ...) \
    WHEN(count) \
    ( \
        DEFER(REPEAT_INDIRECT) () \
        ( \
            DEC(count), macro, __VA_ARGS__ \
        ) \
        DEFER(macro) \
        ( \
            DEC(count), __VA_ARGS__ \
        ) \
    )
#define REPEAT_INDIRECT() REPEAT

//An example of using this macro
#define M(s, i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7

永远:

#define FOREVER() \
    ? \
    DEFER(FOREVER_INDIRECT) () ()
#define FOREVER_INDIRECT() FOREVER
// Outputs question marks forever
EVAL(FOREVER())
于 2013-05-17T09:07:56.193 回答
0

如果您真的想在预处理器中执行此操作(并且拥有符合 C99 的编译器),您可以使用P99 中的P99_UNROLL

但是您完全低估了现代编译器的优化能力。只要边界是编译时常量,一个具有优化功能的好的编译器就应该为您展开代码。查看汇编程序以确定(gcc 有-S)。

但是您可能可以通过“正确”编码来帮助编译器:

#define NOP_N(N) for(register unsigned i=0; i < (N); i++) asm(" nop")

也就是说,让循环计数器位于本地for并使用无符号类型,这样就不会出现溢出的理论问题。

于 2013-05-17T10:04:47.393 回答