@@ -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"))
@@ -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. */