]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: Implement asm flag outputs
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Jun 2015 14:35:19 +0000 (14:35 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Jun 2015 14:35:19 +0000 (14:35 +0000)
        * 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.
testsuite/
        * 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@225122 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/config/i386/constraints.md
gcc/config/i386/i386-c.c
gcc/config/i386/i386.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/asm-flag-0.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-flag-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-flag-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-flag-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-flag-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/asm-flag-5.c [new file with mode: 0644]

index 40fd3257d133ac5fd125b5a5b2738a7be1b436d4..b07930194226250a0d1090161db2592a9c671d34 100644 (file)
@@ -1,3 +1,12 @@
+2015-06-29  Richard Henderson  <rth@redhat.com>
+
+       * 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.
+
 2015-06-29  Jiong Wang  <jiong.wang@arm.com>
 
        * config/arch64/aarch64.md (UNSPEC_TLSLE): New enumeration.
index c718bc10017bbb865fcced256329cb80830fb34f..2861d8dfdd2af189f94fbf36320709bf3007c9f0 100644 (file)
  "@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"))
index 28444f9039a44134eebf20b493d1d08867ed27a3..d5063457b904de77288a2137709131c5fe566a15 100644 (file)
@@ -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,
index 95986006ec8a7435f2c05dc412e4272ee2830ab9..144c1a6fd67f5476cd04597c4c592080dccd6247 100644 (file)
@@ -45555,21 +45555,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 (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 (!SCALAR_INT_MODE_P (dest_mode))
+       {
+         error ("invalid type for asm flag output");
+         continue;
+       }
+      if (dest_mode != QImode)
+       {
+         rtx destqi = gen_reg_rtx (QImode);
+         emit_insn (gen_rtx_SET (destqi, x));
+         x = gen_rtx_ZERO_EXTEND (dest_mode, destqi);
+       }
+      emit_insn (gen_rtx_SET (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.  */
index 8258000510ec37d9b027e945b311a7dcd82571bf..bb858a84f96052b8df55fe00b5903ab4744d26a2 100644 (file)
@@ -7683,6 +7683,84 @@ pointed to by @code{e}
 in a register, you can enable it to choose the best location
 for @code{d} by specifying both constraints.
 
+@anchor{FlagOutputOperands}
+@subsection Flag Output Operands
+@cindex @code{asm} flag output operands
+
+Some targets have a special register that holds the ``flags'' for the
+result of an operation or comparison.  Normally, the contents of that
+register are either unmodifed by the asm, or the asm is considered to
+clobber the contents.
+
+On some targets, a special form of output operand exists by which
+conditions in the flags register may be outputs of the asm.  The set of
+conditions supported are target specific, but the general rule is that
+the output variable must be a scalar integer, and the value will be boolean.
+When supported, the target will define the preprocessor symbol
+@code{__GCC_ASM_FLAG_OUTPUTS__}.
+
+Because of the special nature of the flag output operands, the constraint
+may not include alternatives.
+
+Most often, the target has only one flags register, and thus is an implied
+operand of many instructions.  In this case, the operand should not be
+referenced within the assembler template via @code{%0} etc, as there's
+no corresponding text in the assembly language.
+
+@table @asis
+@item x86 family
+The flag output constraints for the x86 family are of the form
+@samp{=@@cc@var{cond}} where @var{cond} is one of the standard
+conditions defined in the ISA manual for @code{j@var{cc}} or
+@code{set@var{cc}}.
+
+@table @code
+@item a
+``above'' or unsigned greater than
+@item ae
+``above or equal'' or unsigned greater than or equal
+@item b
+``below'' or unsigned less than
+@item be
+``below or equal'' or unsigned less than or equal
+@item c
+carry flag set
+@item e
+@itemx z
+``equal'' or zero flag set
+@item g
+signed greater than
+@item ge
+signed greater than or equal
+@item l
+signed less than
+@item le
+signed less than or equal
+@item o
+overflow flag set
+@item p
+parity flag set
+@item s
+sign flag set
+@item na
+@itemx nae
+@itemx nb
+@itemx nbe
+@itemx nc
+@itemx ne
+@itemx ng
+@itemx nge
+@itemx nl
+@itemx nle
+@itemx no
+@itemx np
+@itemx ns
+@itemx nz
+``not'' @var{flag}, or inverted versions of those above
+@end table
+
+@end table
+
 @anchor{InputOperands}
 @subsubsection Input Operands
 @cindex @code{asm} input operands
index fc2b9bc0d7689bcbdbb2fad5f62901934292dd6c..3163ba6305e83d24b8a5e41e02d59d09741ce243 100644 (file)
@@ -1,3 +1,11 @@
+2015-06-29  Richard Henderson  <rth@redhat.com>
+
+       * 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.
+
 2015-06-29  Marek Polacek  <polacek@redhat.com>
 
        PR c/66322
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-0.c b/gcc/testsuite/gcc.target/i386/asm-flag-0.c
new file mode 100644 (file)
index 0000000..b0c0523
--- /dev/null
@@ -0,0 +1,15 @@
+/* Test error conditions of asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void a(void)
+{
+  char x;
+  asm("" : "=@cca,@ccc"(x));  /* { dg-error "alternatives not allowed" } */
+}
+
+void b(void)
+{
+  char x;
+  asm("" : "=@ccbad"(x)); /* { dg-error "unknown asm flag output" } */
+}
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-1.c b/gcc/testsuite/gcc.target/i386/asm-flag-1.c
new file mode 100644 (file)
index 0000000..bcc4952
--- /dev/null
@@ -0,0 +1,18 @@
+/* Test some of the valid @cc<cc> asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void f(char *out)
+{
+  asm("" : "=@cca"(out[0]), "=@ccc"(out[1]), "=@cce"(out[2]),
+           "=@ccg"(out[3]), "=@cco"(out[4]), "=@ccp"(out[5]),
+           "=@ccs"(out[6]));
+}
+
+/* { dg-final { scan-assembler "seta" } } */
+/* { dg-final { scan-assembler "setc" } } */
+/* { dg-final { scan-assembler "sete" } } */
+/* { dg-final { scan-assembler "setg" } } */
+/* { dg-final { scan-assembler "seto" } } */
+/* { dg-final { scan-assembler "setp" } } */
+/* { dg-final { scan-assembler "sets" } } */
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-2.c b/gcc/testsuite/gcc.target/i386/asm-flag-2.c
new file mode 100644 (file)
index 0000000..5f8fa13
--- /dev/null
@@ -0,0 +1,16 @@
+/* Test some of the valid @cc<cc> asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void f(char *out)
+{
+  asm("" : "=@ccb"(out[0]), "=@ccl"(out[1]), "=@ccz"(out[2]),
+           "=@ccbe"(out[4]), "=@ccge"(out[5]), "=@ccle"(out[6]));
+}
+
+/* { dg-final { scan-assembler "setc" } } */
+/* { dg-final { scan-assembler "setl" } } */
+/* { dg-final { scan-assembler "sete" } } */
+/* { dg-final { scan-assembler "setna" } } */
+/* { dg-final { scan-assembler "setge" } } */
+/* { dg-final { scan-assembler "setle" } } */
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-3.c b/gcc/testsuite/gcc.target/i386/asm-flag-3.c
new file mode 100644 (file)
index 0000000..220c07c
--- /dev/null
@@ -0,0 +1,22 @@
+/* Test some of the valid @cc<cc> asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+#define DO(C) \
+void f##C(int *y) { char x; asm("" : "=@cc"#C(x)); if (!x) *y = 0; }
+
+DO(a)
+DO(c)
+DO(e)
+DO(g)
+DO(o)
+DO(p)
+DO(s)
+
+/* { dg-final { scan-assembler "ja" } } */
+/* { dg-final { scan-assembler "jc" } } */
+/* { dg-final { scan-assembler "je" } } */
+/* { dg-final { scan-assembler "jg" } } */
+/* { dg-final { scan-assembler "jo" } } */
+/* { dg-final { scan-assembler "jp" } } */
+/* { dg-final { scan-assembler "js" } } */
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-4.c b/gcc/testsuite/gcc.target/i386/asm-flag-4.c
new file mode 100644 (file)
index 0000000..b84b7df
--- /dev/null
@@ -0,0 +1,20 @@
+/* Test some of the valid @cc<cc> asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+#define DO(C) \
+void f##C(int *y) { char x; asm("" : "=@cc"#C(x)); if (!x) *y = 0; }
+
+DO(b)
+DO(l)
+DO(z)
+DO(be)
+DO(ge)
+DO(le)
+
+/* { dg-final { scan-assembler "jc" } } */
+/* { dg-final { scan-assembler "jl" } } */
+/* { dg-final { scan-assembler "je" } } */
+/* { dg-final { scan-assembler "jna" } } */
+/* { dg-final { scan-assembler "jge" } } */
+/* { dg-final { scan-assembler "jle" } } */
diff --git a/gcc/testsuite/gcc.target/i386/asm-flag-5.c b/gcc/testsuite/gcc.target/i386/asm-flag-5.c
new file mode 100644 (file)
index 0000000..151157d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Test error conditions of asm flag outputs.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void f_B(void) { _Bool x; asm("" : "=@ccc"(x)); }
+void f_c(void) { char x; asm("" : "=@ccc"(x)); }
+void f_s(void) { short x; asm("" : "=@ccc"(x)); }
+void f_i(void) { int x; asm("" : "=@ccc"(x)); }
+void f_l(void) { long x; asm("" : "=@ccc"(x)); }
+
+void f_f(void)
+{
+  float x;
+  asm("" : "=@ccc"(x)); /* { dg-error invalid type } */
+}
+
+void f_d(void)
+{
+  double x;
+  asm("" : "=@ccc"(x)); /* { dg-error invalid type } */
+}
+
+struct S { int x[3]; };
+
+void f_S(void)
+{
+  struct S x;
+  asm("" : "=@ccc"(x)); /* { dg-error invalid type } */
+}