3

Im trying to implement my own memcpy function in asm. CPU is dsPIC33F, compiler Microchip C30.

asm("repeat %2 \n mov.b [%1++], [%0++]" 
   : : "r"(dst), "r"(src), "ri"(len));

When len is variable, this works fine: the compiler picks a register and there is no problem. But when len is a compile-time constant (eg 10), assembler says: Error: Invalid operands specified ('repeat 10').

This is because microchip assembler requires # before immediates: repeat #10
Using #%2 in the source wouldn't be viable because that would break if the compiler picked a register.

Is it a microchip compiler bug?

Is there any way to write inline asm that will expand correctly to
repeat reg or repeat #imm for "ri" or "g"?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Woodoo
  • 129
  • 6
  • You should be able to use '#', how do you create the inline statement? Can you show some code? – Devolus Feb 08 '21 at 12:14
  • If I use `#` (`repeat #%2`) there is no error until `len` is variable. If `len` becomes variable (e.g. stored in w10), I got error: `Invalid operands specified ('repeat #w10')`. Full code is just `#define memcpy(dst, src, len) asm(...)` – Woodoo Feb 08 '21 at 12:20
  • Did you try `"ri"` and `"g"`? – the busybee Feb 08 '21 at 15:19
  • Yes, both. I also tried `"rI"`, `"rn"` – Woodoo Feb 08 '21 at 15:39
  • How about wrapping the asm with [__builtin_constant_p](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html)? Since it's a compile-time builtin, the "if" should not produce any runtime code. Then you could have one asm statement with # and one without. Also, shouldn't you have a memory clobber? And doesn't this code end up changing src/dst? Per [spec](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands) (see the Warning), input parameters to asm (the ones after the second colon) are "read-only" and must have the same value on exiting the asm statement as on entry. – David Wohlferd Feb 09 '21 at 06:03
  • I used `__builtin_constant_p` with compile-time ternary operator `?:`. Surprisingly, it does not allow `asm(...)` to be an argument, coz it is code-block, not an expr. Solution is to wrap `asm` like this: `({asm(...);})`. It works:) Instead of ternary, I would use `#if-#else-#endif` but it is not permitted inside `#define memcpy` due to `#define` is sing-line (even with `\ `) and `#if` must be first in line. I am not sure about correct clobbering in my case: should I clubber input reg coz they modified? However, they are automatic, exact reg name is not known for me. – Woodoo Feb 09 '21 at 09:23
  • Solution from spec: "One common work-around is to tie the changing input variable to an output variable that never gets used". Thanx, @DavidWohlferd – Woodoo Feb 09 '21 at 09:30
  • Note: When your asm statement had no outputs, it was implicitly volatile. This meant the compiler couldn't remove it. By adding unused outputs, there's the possibility the optimizer could recognize that none of the outputs are needed and remove the statement entirely. Add the `volatile` qualifier to ensure this doesn't happen. Also (from the docs): *Clobber descriptions may not in any way overlap with an input or output operand.* – David Wohlferd Feb 09 '21 at 19:29

0 Answers0