> On Sep 23, 2020, at 9:32 AM, Richard Sandiford <richard.sandif...@arm.com> 
> wrote:
> 
> 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.

How can the syntax of asm volatile distinguish “Uses” and “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.

Is EPILOGUE_USES the only way for this purpose? Will add another “asm volatile” 
immediately before the return serve the same purpose?


> 
>> 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.
Okay.
> 
>>>> 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.

Okay, I see. 

> 
>>> 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.

Okay. 

thanks.

Qing
> 
> Thanks,
> Richard

Reply via email to