All j<cc> mnemonics implemented as =@cc<cc>
to make it easy for someone reading the manual
to figure out what condition is desired.
---
 gcc/config/i386/constraints.md |   5 ++
 gcc/config/i386/i386.c         | 132 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 130 insertions(+), 7 deletions(-)

diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 2271bd1..d16e728 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -146,10 +146,15 @@
  "@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
 ;;  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 "Bs"
   "@internal Sibcall memory operand."
   (and (not (match_test "TARGET_X32"))
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 7cbb465..352884d 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -45433,21 +45433,139 @@ 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 (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
-                   vec<const char *> &/*constraints*/,
+ix86_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
+                   vec<const char *> &constraints,
                    vec<rtx> &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", constraints[i]);
+         continue;
+       }
+      if (invert)
+       code = reverse_condition (code);
+
+      rtx dest = outputs[i];
+      if (!saw_asm_flag)
+       {
+         /* This is the first asm flag output.  Here we put the flags
+            register in as the real output and adjust the condition to
+            allow it.  */
+         constraints[i] = "=Bf";
+         outputs[i] = gen_rtx_REG (CCmode, FLAGS_REG);
+         saw_asm_flag = true;
+       }
+      else
+       {
+         /* We don't need the flags register as output twice.  */
+         constraints[i] = "=X";
+         outputs[i] = gen_rtx_SCRATCH (SImode);
+       }
+
+      rtx x = gen_rtx_REG (mode, FLAGS_REG);
+      x = gen_rtx_fmt_ee (code, QImode, x, const0_rtx);
+
+      machine_mode dest_mode = GET_MODE (dest);
+      if (dest_mode != QImode)
+       {
+         rtx destqi = gen_reg_rtx (QImode);
+         emit_insn (gen_rtx_SET (VOIDmode, destqi, x));
+         x = gen_rtx_ZERO_EXTEND (dest_mode, destqi);
+       }
+      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+    }
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+
+  if (saw_asm_flag)
+    return seq;
+  else
+    {
+      /* If we had no asm flag outputs, clobber the flags.  */
+      clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REG));
+      SET_HARD_REG_BIT (clobbered_regs, FLAGS_REG);
+      return NULL;
+    }
 }
 
 /* Implements target vector targetm.asm.encode_section_info.  */
-- 
2.1.0

Reply via email to