On 10/29/2015 1:47 PM, Richard Henderson wrote:
On 10/27/2015 02:05 PM, Jeff Law wrote:
On 10/25/2015 09:41 PM, David Wohlferd wrote:
Does gcc's inline asm support multi-alternative constraints?  Or are
they only supported for md?

dw

PS If it *is* supported, then the docs need some work.
I think Richard corrected me last I spoke on this topic :-)  They *are*
supported.  ie, something like this should work on a ciscy target.

   asm("add %0,%1" : "=r,m"(x) : "rim,ri"(y))
Correct.

They are supported, so long as the assembly can use the same text for all
alternatives.  Thus multiple alternatives in inline asm is basically useless
for RISC targets, but occasionally useful for CISC targets.

Aha.  Thank you for the info.

Ok, I have discarded the other patch. I'm not sure what this means for 10396, since that seemed to be the solution there.

I have updated the non-md text with (most of) the changes I think it needs (attached). These changes are pleasantly minor, mostly just adding some example text and a bit of formatting.

However. Trying to actually use the information on this page is turning up some problems.

First, it could use a bit more clarity in the text that describes how gcc chooses among the alternatives. There are apparently 3 criteria that affect this decision: # of statements needed to copy params, order of alternatives, and flags. But it appears that they aren't all weighted equally. For example no number of '?' seem to be able to override an alternative that causes a reload (change the example below to use eax instead of ebx). But before I try to re-phrase this paragraph, I'm hoping someone can provide more details. What exactly are the rules here?

Second, attempting to use ! and $ isn't working the way the docs led me to expect (actually, I can't make them work at all). Starting with this (contrived) i386 code, gcc selects the second alternative (using -O2 for x64). This makes sense to me.

    int main()
    {
       int x = 3;
       int y = 17;

       asm("or %1,%0" : "+r,b"(x) : "r,i"(y));

       return x;
    }

It took two '?' in front of the 'b' to convince gcc to use the first alternative. This seems reasonable, and shows that the first alternative is indeed viable.

The problem started when I tried to replace the '??' with '!'. Being "severe," I figured one '!' should do the work of two '?'. But even using multiple '!' doesn't cause it to switch to the first alternative. Parsing the current docs:

"! - Disparage severely the alternative that the '!' appears in. This alternative can still be used if it fits without reloading, but if reloading is needed, some other alternative will be used. "

The alternative I am trying to disparage uses ebx. Using that register causes a push/pop. That seems to me like "reloading is needed," so I expected that by definition the other alternative would be used. Even if reloading isn't a factor (or if I don't understand it correctly), the alternative '!' is applied to should still be "severely" disparaged (ie at least as much as 2 '?'). But apparently it's not.

Using '^' does change the selection if I use two of them. But according to the docs, '^' *only* applies if "the operand with the '^' needs a reload." Since the '^' is having an effect, doesn't that imply that there is a reload associated with the second alternative? But if there is, why didn't '!' work as expected?

'$' also doesn't affect the selection, probably for the same reasons as '!'.

I don't know if ! and $ are broken, or if the docs just aren't explaining them well enough. But something isn't working here.

Lastly, while it is a core concept to compiler-writers, 'reloads' isn't really a compiler-user concept. Perhaps some of these flags aren't user manual appropriate (I'm looking at you !^$).

dw

PS

Current text: https://gcc.gnu.org/onlinedocs/gcc/Multi-Alternative.html
Proposed text: http://limegreensocks.com/gcc/Multi_002dAlternative.html

Index: md.texi
===================================================================
--- md.texi	(revision 229470)
+++ md.texi	(working copy)
@@ -1465,6 +1465,8 @@
 constraint for an operand is made from the letters for this operand
 from the first alternative, a comma, the letters for this operand from
 the second alternative, a comma, and so on until the last alternative.
+All operands for a single instruction must have the same number of 
+alternatives.
 @ifset INTERNALS
 Here is how it is done for fullword logical-or on the 68000:
 
@@ -1483,8 +1485,20 @@
 @samp{%} in the constraints apply to all the alternatives; their
 meaning is explained in the next section (@pxref{Class Preferences}).
 @end ifset
+@ifclear INTERNALS
 
+So the first alternative for the 68000's logical-or could be written as 
+@code{"+m" (output) : "ir" (input)}.  The second could be @code{"+r" 
+(output): "irm" (input)}.  However, the fact that two memory locations 
+cannot be used in a single instruction prevents simply using @code{"+rm" 
+(output) : "irm" (input)}.  Using multi-alternatives, this might be 
+written as @code{"+m,r" (output) : "ir,irm" (input)}.  This describes
+all the available alternatives to GCC, allowing it to choose the most
+efficient one for the current conditions.
+@end ifclear
+
 @c FIXME Is this ? and ! stuff of use in asm()?  If not, hide unless INTERNAL
+@ifset INTERNALS
 If all the operands fit any one alternative, the instruction is valid.
 Otherwise, for each alternative, the compiler counts how many instructions
 must be added to copy the operands so that that alternative applies.
@@ -1491,35 +1505,55 @@
 The alternative requiring the least copying is chosen.  If two alternatives
 need the same amount of copying, the one that comes first is chosen.
 These choices can be altered with the @samp{?} and @samp{!} characters:
+@end ifset
+@ifclear INTERNALS
+To choose among the alternatives, the compiler counts how many 
+instructions must be added to copy the operands to match the alternative. 
+The alternative requiring the least amount of copying is chosen. If two 
+alternatives need the same amount of copying, the one that comes first is 
+chosen. This weighting can be modified using the flags below.
 
-@table @code
+For example to (slightly) encourage the compiler to use the register form 
+of the logical-or instruction, you could list it first:  @code{"+r,m" 
+(output) : "irm,ir" (input)}.  To discourage GCC from using the memory 
+form, you could add one or more @samp{?} to that alternative: 
+@code{"+r,??m" (output) : "irm,ir" (input)}.
+
+GCC provides no way within the template to determine which alternative was 
+chosen.  However you may be able to wrap your @code{asm} statements with 
+builtins such as @code{__builtin_constant_p} to achieve the desired results.
+@end ifclear
+
+@multitable
+@headitem Flag @tab Meaning
 @cindex @samp{?} in constraint
 @cindex question mark
 @item ?
+@tab
 Disparage slightly the alternative that the @samp{?} appears in,
 as a choice when no alternative applies exactly.  The compiler regards
 this alternative as one unit more costly for each @samp{?} that appears
 in it.
-
 @cindex @samp{!} in constraint
 @cindex exclamation point
 @item !
+@tab
 Disparage severely the alternative that the @samp{!} appears in.
 This alternative can still be used if it fits without reloading,
 but if reloading is needed, some other alternative will be used.
-
 @cindex @samp{^} in constraint
 @cindex caret
 @item ^
+@tab
 This constraint is analogous to @samp{?} but it disparages slightly
 the alternative only if the operand with the @samp{^} needs a reload.
-
 @cindex @samp{$} in constraint
 @cindex dollar sign
 @item $
+@tab
 This constraint is analogous to @samp{!} but it disparages severely
 the alternative only if the operand with the @samp{$} needs a reload.
-@end table
+@end multitable
 
 @ifset INTERNALS
 When an insn pattern has multiple alternatives in its constraints, often

Reply via email to