2017-10-23 Jakub Jelinek <jakub@redhat.com>
+ PR target/82628
+ * config/i386/predicates.md (x86_64_dwzext_immediate_operand): New.
+ * config/i386/constraints.md (Wf): New constraint.
+ * config/i386/i386.md (UNSPEC_SBB): New unspec.
+ (cmp<dwi>_doubleword): Removed.
+ (sub<mode>3_carry_ccc, *sub<mode>3_carry_ccc_1): New patterns.
+ (sub<mode>3_carry_ccgz): Use unspec instead of compare.
+ * config/i386/i386.c (ix86_expand_branch) <case E_TImode>: Don't
+ expand with cmp<dwi>_doubleword. For LTU and GEU use
+ sub<mode>3_carry_ccc instead of sub<mode>3_carry_ccgz and use CCCmode.
+
* common.opt (gcolumn-info): Enable by default.
* doc/invoke.texi (gcolumn-info): Document new default.
of it satisfies the e constraint."
(match_operand 0 "x86_64_hilo_int_operand"))
+(define_constraint "Wf"
+ "32-bit signed integer constant zero extended from word size
+ to double word size."
+ (match_operand 0 "x86_64_dwzext_immediate_operand"))
+
(define_constraint "Z"
"32-bit unsigned integer constant, or a symbolic reference known
to fit that range (for immediate operands in zero-extending x86-64
switch (code)
{
case LE: case LEU: case GT: case GTU:
- std::swap (op0, op1);
+ std::swap (lo[0], lo[1]);
+ std::swap (hi[0], hi[1]);
code = swap_condition (code);
/* FALLTHRU */
case LT: case LTU: case GE: case GEU:
{
- rtx (*cmp_insn) (rtx, rtx, rtx);
+ rtx (*cmp_insn) (rtx, rtx);
+ rtx (*sbb_insn) (rtx, rtx, rtx);
+ bool uns = (code == LTU || code == GEU);
if (TARGET_64BIT)
- cmp_insn = gen_cmpti_doubleword;
+ {
+ cmp_insn = gen_cmpdi_1;
+ sbb_insn
+ = uns ? gen_subdi3_carry_ccc : gen_subdi3_carry_ccgz;
+ }
else
- cmp_insn = gen_cmpdi_doubleword;
+ {
+ cmp_insn = gen_cmpsi_1;
+ sbb_insn
+ = uns ? gen_subsi3_carry_ccc : gen_subsi3_carry_ccgz;
+ }
+
+ if (!nonimmediate_operand (lo[0], submode))
+ lo[0] = force_reg (submode, lo[0]);
+ if (!x86_64_general_operand (lo[1], submode))
+ lo[1] = force_reg (submode, lo[1]);
- if (!register_operand (op0, mode))
- op0 = force_reg (mode, op0);
- if (!x86_64_hilo_general_operand (op1, mode))
- op1 = force_reg (mode, op1);
+ if (!register_operand (hi[0], submode))
+ hi[0] = force_reg (submode, hi[0]);
+ if ((uns && !nonimmediate_operand (hi[1], submode))
+ || (!uns && !x86_64_general_operand (hi[1], submode)))
+ hi[1] = force_reg (submode, hi[1]);
- emit_insn (cmp_insn (gen_rtx_SCRATCH (mode), op0, op1));
+ emit_insn (cmp_insn (lo[0], lo[1]));
+ emit_insn (sbb_insn (gen_rtx_SCRATCH (submode), hi[0], hi[1]));
- tmp = gen_rtx_REG (CCGZmode, FLAGS_REG);
+ tmp = gen_rtx_REG (uns ? CCCmode : CCGZmode, FLAGS_REG);
ix86_expand_branch (code, tmp, const0_rtx, label);
return;
UNSPEC_STOS
UNSPEC_PEEPSIB
UNSPEC_INSN_FALSE_DEP
+ UNSPEC_SBB
;; For SSE/MMX support:
UNSPEC_FIX_NOTRUNC
(compare:CC (match_operand:SWI48 0 "nonimmediate_operand")
(match_operand:SWI48 1 "<general_operand>")))])
-(define_insn_and_split "cmp<dwi>_doubleword"
- [(set (reg:CCGZ FLAGS_REG)
- (compare:CCGZ
- (match_operand:<DWI> 1 "register_operand" "0")
- (match_operand:<DWI> 2 "x86_64_hilo_general_operand" "ro<di>")))
- (clobber (match_scratch:<DWI> 0 "=r"))]
- ""
- "#"
- "reload_completed"
- [(set (reg:CC FLAGS_REG)
- (compare:CC (match_dup 1) (match_dup 2)))
- (parallel [(set (reg:CCGZ FLAGS_REG)
- (compare: CCGZ
- (match_dup 4)
- (plus:DWIH
- (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))
- (match_dup 5))))
- (clobber (match_dup 3))])]
- "split_double_mode (<DWI>mode, &operands[0], 3, &operands[0], &operands[3]);")
-
(define_insn "*cmp<mode>_ccno_1"
[(set (reg FLAGS_REG)
(compare (match_operand:SWI 0 "nonimmediate_operand" "<r>,?m<r>")
(set_attr "pent_pair" "pu")
(set_attr "mode" "SI")])
-(define_insn "*sub<mode>3_carry_ccgz"
+(define_insn "sub<mode>3_carry_ccc"
+ [(set (reg:CCC FLAGS_REG)
+ (compare:CCC
+ (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+ (plus:<DWI>
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 2 "x86_64_sext_operand" "rmWe")))))
+ (clobber (match_scratch:DWIH 0 "=r"))]
+ ""
+ "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*sub<mode>3_carry_ccc_1"
+ [(set (reg:CCC FLAGS_REG)
+ (compare:CCC
+ (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+ (plus:<DWI>
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+ (match_operand:<DWI> 2 "x86_64_dwzext_immediate_operand" "Wf"))))
+ (clobber (match_scratch:DWIH 0 "=r"))]
+ ""
+{
+ operands[3] = simplify_subreg (<MODE>mode, operands[2], <DWI>mode, 0);
+ return "sbb{<imodesuffix>}\t{%3, %0|%0, %3}";
+}
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
+;; The sign flag is set from the
+;; (compare (match_dup 1) (plus:DWIH (ltu:DWIH ...) (match_dup 2)))
+;; result, the overflow flag likewise, but the overflow flag is also
+;; set if the (plus:DWIH (ltu:DWIH ...) (match_dup 2)) overflows.
+(define_insn "sub<mode>3_carry_ccgz"
[(set (reg:CCGZ FLAGS_REG)
- (compare:CCGZ
- (match_operand:DWIH 1 "register_operand" "0")
- (plus:DWIH
- (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))
- (match_operand:DWIH 2 "x86_64_general_operand" "rme"))))
+ (unspec:CCGZ [(match_operand:DWIH 1 "register_operand" "0")
+ (match_operand:DWIH 2 "x86_64_general_operand" "rme")
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))]
+ UNSPEC_SBB))
(clobber (match_scratch:DWIH 0 "=r"))]
""
"sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
}
})
+;; Return true if VALUE is a constant integer whose value is
+;; x86_64_immediate_operand value zero extended from word mode to mode.
+(define_predicate "x86_64_dwzext_immediate_operand"
+ (match_code "const_int,const_wide_int")
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ if (!TARGET_64BIT)
+ return UINTVAL (op) <= HOST_WIDE_INT_UC (0xffffffff);
+ return UINTVAL (op) <= HOST_WIDE_INT_UC (0x7fffffff);
+
+ case CONST_WIDE_INT:
+ if (!TARGET_64BIT)
+ return false;
+ return (CONST_WIDE_INT_NUNITS (op) == 2
+ && CONST_WIDE_INT_ELT (op, 1) == 0
+ && (trunc_int_for_mode (CONST_WIDE_INT_ELT (op, 0), SImode)
+ == (HOST_WIDE_INT) CONST_WIDE_INT_ELT (op, 0)));
+
+ default:
+ gcc_unreachable ();
+ }
+})
+
;; Return true if size of VALUE can be stored in a sign
;; extended immediate field.
(define_predicate "x86_64_immediate_size_operand"