GCC ARM Assembly Preprocessor Macro

China☆狼群 提交于 2019-12-04 07:26:45

Have you tried simple C-code instead of assembly? On my system with GCC 4.5.3 the compiler generates code that is at least as good as your hand written assembler:

int mul (int a, int b)
{
  long long x = ((long long)a * b + 0x8000);
  return x>>16;
}

compiles to the following asm-code:

# input: r0, r1
mov    r3, #32768
mov    r4, #0
smlal  r3, r4, r0, r1
mov    r0, r3, lsr #16
orr    r0, r0, r4, asl #16
# result in r0

(Function call epilog and prolog removed)

The code becomes even better if you have multiple multiplications in a single function because the compiler will remove the redundant mov r3, #32768 instructions.

The first part is easy enough: the problem is that an __asm__ block is a statement, not an expression.

You can use GCC's statement expressions extension to achieve what you want - something like this:

#define MULT(a,b) \
  ({ \
    __asm__ __volatile__ ( \
      /* ... asm stuff here ... */
    ); \
    a; \
  })

The second part is due to problems in the input and output operand specifications. You have two different versions here, and both are wrong. In the macro version, you've said:

: "=r" (a) : "0"(a), "1"(b) : "r2", "r3"

which constrains

  • the output a to a register (this is operand 0);
  • the input a to be the same as operand 0, i.e. the same register (this is operand 1);
  • the input b to be the same as operand 1, i.e. the same again (this is operand 2).

You need "r"(b) here, and can refer to it as %2.

In the inline version, you've said:

: "=r" (a) : [a] "r" (a), [b] "r" (b) : "r2", "r3"

which constrains the output a and the input a and b to registers, but

  • it does not declare any relationship between them;
  • the asm never explicitly refers to the output operand (you haven't given the output operand a name, and the asm code doesn't refer to %0).

You should be able to fix the original version with:

: "=r" (a) : "0" (a), "r" (b) : "r2", "r3"

and refer to the a as either %0 or %1, and b as %2.

The inline version can be fixed like this:

: [a] "=r" (a) : "[a]" (a), [b] "r" (b) : "r2", "r3"

and refer the operands as %[a] and %[b].

If you want to use names in the macro version, you'll need something along the lines of

: [arg_a] "=r" (a) : "[arg_a]" (a), [arg_b] "r" (b) : "r2", "r3"

(and refer to %[arg_a] and %[arg_b]) because otherwise the preprocessor will expand the a and b inside [a] and [b].

Note the subtlety in the named argument cases: when a name is being given to an argument (as in the output a) you write [a] - no quotes - but when you are referring to the name of another already-named operand (as in the input a) you need to put it inside quotes: "[a]".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!