Hi everyone, 

I am looking for some clarification about how are working the memory operands, 
especially when the constraint allows memory only (eg. "m"). 
Please note that in a lesser extent, I know (by looking the gcc sources) how 
the things are currently working but I wonder if it is a design choice or 
simply a serendipitous engineering consequence. 
Indeed, as far as I know, the documentation is not explicit on this. 

Only things related to memory I have found are: 
> A string constant specifying constraints on the placement of the operand; See 
> Constraints, for details. 
> ‘ m ’ A memory operand is allowed, with any kind of address that the machine 
> supports in general. 

When I read this, I think that "m" work exactly as "r" from a C point of view. 
But in fact, there are some conceptual corner cases where there are not 
equivalent. 

(1) It is said that an output must be an lvalue. However, it is said nowhere 
(except that compilation fails) that if the constraint allows only memory, an 
input expression must be an lvalue too. 
  There are a lot of workarounds, but why the following code (actually not 
relevant) is rejected? 
  __asm__ ("movl %1, %0" : "=r" (x) : "m" (1)); 
  I would think that the compiler could put the constant 1 in the stack or in a 
static address or even reuse any memory address known to hold the value 1. 

(2) If the constraint allows only memory, does the compiler allowed to make a 
copy? (if no, why?)
 
 (2.1) Thus, if I declare an output and an input using the same lvalue, am I 
guaranteed that they both point to the same location? (as far as I know, it is 
not true for register constraint)
    __asm__ ("incl %0" : "=m" (x) : "m" (x)); 
  
 (2.2) Moreover, in the following example of the doc, is edi guaranteed to 
point to the memory pointed by "m" (*(const char (*)[]) p) ? 

> asm("repne scasb"
>    : "=c" (count), "+D" (p)
>    : "m" (*(const char (*)[]) p), "0" (-1), "a" (0)); 

  I had a hard time to figure out why it is actually working -- partially 
explaining the (1). 
  In fact, from a C perspective, *(const char (*)[]) evaluates to a (const char 
*), so I would think: place the value of p in an arbitrary memory location. 
  (Note that it is what is happening when the constraint also allows a 
register, but no register is free) 

 (2.3) Would it make sense to use early clobber '&' to force two memory 
locations to be distinct? 
  char t[4] = "abcd"; int x = 0x64636261; 
  __asm__ ("..." : "+&m" (t) : "m" (x)); 
  From a low-level optimizer perspective, both t and x have the same value so 
it would be interesting to pass the same memory location if the first one was 
not early clobber. 

(3) I understand that writing a "phantom" entry like in (2.2) make possible to 
avoid the use of the "memory" keyword.
  Would it make it simpler if there is a dedicated syntax to state that memory 
from an input pointer is accessed? 
  For instance, something like: 
  __asm__ ("repne scasb" : "=c" (count), "+D" (p) : "0" (-1), "a" (0) : 
"memory(1)"); or __asm__ ("repne scasb" : "=c" (count), [P] "+D" (p) : "0" 
(-1), "a" (0) : "@[P]");


Regards,
Frédéric Recoules

Reply via email to