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