Qing Zhao <qing.z...@oracle.com> writes:
>> On Sep 23, 2020, at 6:05 AM, Richard Sandiford <richard.sandif...@arm.com> 
>> wrote:
>> 
>> Qing Zhao <qing.z...@oracle.com <mailto:qing.z...@oracle.com>> writes:
>>>> On Sep 22, 2020, at 12:06 PM, Richard Sandiford 
>>>> <richard.sandif...@arm.com> wrote:
>>>>>>> 
>>>>>>> The following is what I see from i386.md: (I didn’t look at how 
>>>>>>> “UNSPEC_volatile” is used in data flow analysis in GCC yet)
>>>>>>> 
>>>>>>> ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers 
>>>>>>> and
>>>>>>> ;; all of memory.  This blocks insns from being moved across this point.
>>>>>> 
>>>>>> Heh, it looks like that comment dates back to 1994. :-)
>>>>>> 
>>>>>> The comment is no longer correct though.  I wasn't around at the time,
>>>>>> but I assume the comment was only locally true even then.
>>>>>> 
>>>>>> If what the comment said was true, then something like:
>>>>>> 
>>>>>> (define_insn "cld"
>>>>>> [(unspec_volatile [(const_int 0)] UNSPECV_CLD)]
>>>>>> ""
>>>>>> "cld"
>>>>>> [(set_attr "length" "1")
>>>>>> (set_attr "length_immediate" "0")
>>>>>> (set_attr "modrm" "0")])
>>>>>> 
>>>>>> would invalidate the entire register file and so would require all values
>>>>>> to be spilt to the stack around the CLD.
>>>>> 
>>>>> Okay, thanks for the info. 
>>>>> then, what’s the current definition of UNSPEC_VOLATILE? 
>>>> 
>>>> I'm not sure it's written down anywhere TBH.  rtl.texi just says:
>>>> 
>>>> @code{unspec_volatile} is used for volatile operations and operations
>>>> that may trap; @code{unspec} is used for other operations.
>>>> 
>>>> which seems like a cyclic definition: volatile expressions are defined
>>>> to be expressions that are volatile.
>>>> 
>>>> But IMO the semantics are that unspec_volatile patterns with a given
>>>> set of inputs and outputs act for dataflow purposes like volatile asms
>>>> with the same inputs and outputs.  The semantics of asm volatile are
>>>> at least slightly more well-defined (if only by example); see extend.texi
>>>> for details.  In particular:
>>>> 
>>>> Note that the compiler can move even @code{volatile asm} instructions 
>>>> relative
>>>> to other code, including across jump instructions. For example, on many 
>>>> targets there is a system register that controls the rounding mode of 
>>>> floating-point operations. Setting it with a @code{volatile asm} statement,
>>>> as in the following PowerPC example, does not work reliably.
>>>> 
>>>> @example
>>>> asm volatile("mtfsf 255, %0" : : "f" (fpenv));
>>>> sum = x + y;
>>>> @end example
>>>> 
>>>> The compiler may move the addition back before the @code{volatile asm}
>>>> statement. To make it work as expected, add an artificial dependency to
>>>> the @code{asm} by referencing a variable in the subsequent code, for
>>>> example:
>>>> 
>>>> @example
>>>> asm volatile ("mtfsf 255,%1" : "=X" (sum) : "f" (fpenv));
>>>> sum = x + y;
>>>> @end example
>>>> 
>>>> which is very similar to the unspec_volatile case we're talking about.
>>>> 
>>>> To take an x86 example:
>>>> 
>>>> void
>>>> f (char *x)
>>>> {
>>>>   asm volatile ("");
>>>>   x[0] = 0;
>>>>   asm volatile ("");
>>>>   x[1] = 0;
>>>>   asm volatile ("");
>>>> }
>>> 
>>> If we change the above as the following: (but it might not correct on the 
>>> asm format):
>>> 
>>> Void
>>> F (char *x)
>>> {
>>> asm volatile (“x[0]”);
>>> x[0] = 0;
>>> asm volatile (“x[1]"); 
>>> x[1] = 0;
>>> asm volatile ("”);
>>> }
>>> 
>>> Will the moving and merging be blocked?
>> 
>> That would stop assignments moving up, but it wouldn't stop x[0] moving
>> down across the x[1] asm.  Using:
>> 
>>  asm volatile ("" ::: "memory");
>> 
>> would prevent moves in both directions, which was what I meant in my
>> later comment about memory clobbers.
>> 
>> In each case, the same would be true for unspec_volatile.
>
> So, is the following good enough:
>
> asm volatile (reg1, reg2, … regN, memory)
> mov reg1, 0
> mov reg2, 0
> ...
> mov regN,0
> asm volatile (reg1, reg2,… regN, memory)
> return
>
>
> I.e, just add one “asm volatile” insn whose operands include all registers 
> and memory BEFORE and AFTER the whole zeroing sequence.

It isn't clear from your syntax whether the asm volatile arguments
are uses or clobbers.  The idea was:

- There would be an asm volatile before the moves that clobbers (but does
  not use) (mem:BLK (scratch)) and the zeroed registers.

- EPILOGUE_USES would make the zeroed registers live after the return.

> Or, we have to add one “asm volatile” insn before and after each “mov” insn? 

No, the idea with the multiple clobber thing was to have a single asm.

>>> If we use “ASM_OPERANDS” instead of “UNSPEXC_VOLATILE” as you suggested, 
>>> the data flow analysis should automatically pick up the operands of 
>>> “ASM_OPERANDS”, and fix the data flow, right?
>> 
>> Using a volatile asm or an unspec_volatile would be equally correct.
>> The reason for preferring a volatile asm is that it doesn't require
>> target-specific .md patterns.
> Okay.
>
> Then is there any benefit to use “UNSPEC_volatile” over “volatile asm”?

In general, yes: you can use the full .md functionality with
unspec_volatiles, such as splitting insns, adding match_scratches
with different clobber requirements, writing custom output code,
setting attributes, etc.

But there isn't an advantage to using unspec_volatile in this case,
where the instruction doesn't actually do anything.

>> Of course, as mentioned before, “correct” in this case is: make a good
>> but not foolproof attempt at trying to prevent later passes from moving
>> the zeroing instructions further away from the return instruction
>> (or, equivalently, moving other instructions closer to the return
>> instruction).  Remember that we arrived here from a discussion about
>> whether the volatile insns would be enough to prevent machine_reorg and
>> other passes from moving instructions around (modulo bugs in those passes).
>> My position was that the volatile insns would help, but that we might
>> still find cases where a machine_reorg makes a behaviourally-correct
>> transformation that we don't want.
> So, you mean after adding “volatile asm” or “UNSPEC_volatile”,  although 
> most of the insn movement can be prevented, there might still be small 
> possibitly 
> Some unwanted transformation might happen?

I wouldn't want to quantify the possibility.  The point is just that the
possibility exists.  The unspec_volatile does not prevent movement of
unrelated non-volatile operations.

Thanks,
Richard

Reply via email to