Re: [committed] Flags outputs for asms

2015-07-08 Thread H.J. Lu
On Mon, Jun 29, 2015 at 7:44 AM, Richard Henderson r...@redhat.com wrote:
 Sorry for the delay, but here's the third and final version.
 This includes the requested cpp symbol and updated documentation.

gcc.target/i386/asm-flag-5.c failed with -march=pentium:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66813

-- 
H.J.


[committed] Flags outputs for asms

2015-06-29 Thread Richard Henderson

Sorry for the delay, but here's the third and final version.
This includes the requested cpp symbol and updated documentation.


r~

* config/i386/constraints.md (Bf): New constraint.
* config/i386/i386-c.c (ix86_target_macros): Define
__GCC_ASM_FLAG_OUTPUTS__.
* config/i386/i386.c (ix86_md_asm_adjust): Handle =@cc* constraints
as flags outputs.
* doc/extend.texi (FlagOutputOperands): Document them.

* gcc.target/i386/asm-flag-1.c: New.
* gcc.target/i386/asm-flag-2.c: New.
* gcc.target/i386/asm-flag-3.c: New.
* gcc.target/i386/asm-flag-4.c: New.
* gcc.target/i386/asm-flag-5.c: New.


diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index c718bc1..2861d8d 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -146,11 +146,16 @@
  @internal Lower SSE register when avoiding REX prefix and all SSE registers 
otherwise.)
 
 ;; We use the B prefix to denote any number of internal operands:
+;;  f  FLAGS_REG
 ;;  g  GOT memory operand.
 ;;  s  Sibcall memory operand, not valid for TARGET_X32
 ;;  w  Call memory operand, not valid for TARGET_X32
 ;;  z  Constant call address operand.
 
+(define_constraint Bf
+  @internal Flags register operand.
+  (match_operand 0 flags_reg_operand))
+
 (define_constraint Bg
   @internal GOT memory operand.
   (match_operand 0 GOT_memory_operand))
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 28444f9..d506345 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -560,6 +560,8 @@ ix86_target_macros (void)
   cpp_define_formatted (parse_in, __ATOMIC_HLE_ACQUIRE=%d, IX86_HLE_ACQUIRE);
   cpp_define_formatted (parse_in, __ATOMIC_HLE_RELEASE=%d, IX86_HLE_RELEASE);
 
+  cpp_define (parse_in, __GCC_ASM_FLAG_OUTPUTS__);
+
   ix86_target_macros_internal (ix86_isa_flags,
   ix86_arch,
   ix86_tune,
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 9598600..144c1a6 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4,21 +4,144 @@ ix86_c_mode_for_suffix (char suffix)
 
 /* Worker function for TARGET_MD_ASM_ADJUST.
 
-   We do this in the new i386 backend to maintain source compatibility
+   We implement asm flag outputs, and maintain source compatibility
with the old cc0-based compiler.  */
 
 static rtx_insn *
-ix86_md_asm_adjust (vecrtx /*outputs*/, vecrtx /*inputs*/,
-   vecconst char * /*constraints*/,
+ix86_md_asm_adjust (vecrtx outputs, vecrtx /*inputs*/,
+   vecconst char * constraints,
vecrtx clobbers, HARD_REG_SET clobbered_regs)
 {
-  clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REG));
   clobbers.safe_push (gen_rtx_REG (CCFPmode, FPSR_REG));
-
-  SET_HARD_REG_BIT (clobbered_regs, FLAGS_REG);
   SET_HARD_REG_BIT (clobbered_regs, FPSR_REG);
 
-  return NULL;
+  bool saw_asm_flag = false;
+
+  start_sequence ();
+  for (unsigned i = 0, n = outputs.length (); i  n; ++i)
+{
+  const char *con = constraints[i];
+  if (strncmp (con, =@cc, 4) != 0)
+   continue;
+  con += 4;
+  if (strchr (con, ',') != NULL)
+   {
+ error (alternatives not allowed in asm flag output);
+ continue;
+   }
+
+  bool invert = false;
+  if (con[0] == 'n')
+   invert = true, con++;
+
+  machine_mode mode = CCmode;
+  rtx_code code = UNKNOWN;
+
+  switch (con[0])
+   {
+   case 'a':
+ if (con[1] == 0)
+   mode = CCAmode, code = EQ;
+ else if (con[1] == 'e'  con[2] == 0)
+   mode = CCCmode, code = EQ;
+ break;
+   case 'b':
+ if (con[1] == 0)
+   mode = CCCmode, code = EQ;
+ else if (con[1] == 'e'  con[2] == 0)
+   mode = CCAmode, code = NE;
+ break;
+   case 'c':
+ if (con[1] == 0)
+   mode = CCCmode, code = EQ;
+ break;
+   case 'e':
+ if (con[1] == 0)
+   mode = CCZmode, code = EQ;
+ break;
+   case 'g':
+ if (con[1] == 0)
+   mode = CCGCmode, code = GT;
+ else if (con[1] == 'e'  con[2] == 0)
+   mode = CCGCmode, code = GE;
+ break;
+   case 'l':
+ if (con[1] == 0)
+   mode = CCGCmode, code = LT;
+ else if (con[1] == 'e'  con[2] == 0)
+   mode = CCGCmode, code = LE;
+ break;
+   case 'o':
+ if (con[1] == 0)
+   mode = CCOmode, code = EQ;
+ break;
+   case 'p':
+ if (con[1] == 0)
+   mode = CCPmode, code = EQ;
+ break;
+   case 's':
+ if (con[1] == 0)
+   mode = CCSmode, code = EQ;
+ break;
+   case 'z':
+ if (con[1] == 0)
+   mode = CCZmode, code = EQ;
+ break;
+   }
+  if (code == UNKNOWN)
+   {
+ error (unknown asm flag output %qs,