From 47a6cc4e2932003063c2b56021f4b31bdeb5f746 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 23 Oct 2017 16:58:23 +0200 Subject: [PATCH] re PR rtl-optimization/82628 (wrong code at -Os on x86_64-linux-gnu in the 32-bit mode) 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_doubleword): Removed. (sub3_carry_ccc, *sub3_carry_ccc_1): New patterns. (sub3_carry_ccgz): Use unspec instead of compare. * config/i386/i386.c (ix86_expand_branch) : Don't expand with cmp_doubleword. For LTU and GEU use sub3_carry_ccc instead of sub3_carry_ccgz and use CCCmode. From-SVN: r254011 --- gcc/ChangeLog | 11 ++++++ gcc/config/i386/constraints.md | 5 +++ gcc/config/i386/i386.c | 38 ++++++++++++++------ gcc/config/i386/i386.md | 66 ++++++++++++++++++++-------------- gcc/config/i386/predicates.md | 25 +++++++++++++ 5 files changed, 109 insertions(+), 36 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5a458a27cd4..cc64d7d3a2a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2017-10-23 Jakub Jelinek + 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_doubleword): Removed. + (sub3_carry_ccc, *sub3_carry_ccc_1): New patterns. + (sub3_carry_ccgz): Use unspec instead of compare. + * config/i386/i386.c (ix86_expand_branch) : Don't + expand with cmp_doubleword. For LTU and GEU use + sub3_carry_ccc instead of sub3_carry_ccgz and use CCCmode. + * common.opt (gcolumn-info): Enable by default. * doc/invoke.texi (gcolumn-info): Document new default. diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 98c05c9ebab..619b465f059 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -332,6 +332,11 @@ 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 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index ff0f6f89f91..5840a273685 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -22378,27 +22378,45 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label) 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; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 1fc4a38b82c..57d258298aa 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -112,6 +112,7 @@ UNSPEC_STOS UNSPEC_PEEPSIB UNSPEC_INSN_FALSE_DEP + UNSPEC_SBB ;; For SSE/MMX support: UNSPEC_FIX_NOTRUNC @@ -1273,26 +1274,6 @@ (compare:CC (match_operand:SWI48 0 "nonimmediate_operand") (match_operand:SWI48 1 "")))]) -(define_insn_and_split "cmp_doubleword" - [(set (reg:CCGZ FLAGS_REG) - (compare:CCGZ - (match_operand: 1 "register_operand" "0") - (match_operand: 2 "x86_64_hilo_general_operand" "ro"))) - (clobber (match_scratch: 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 (mode, &operands[0], 3, &operands[0], &operands[3]);") - (define_insn "*cmp_ccno_1" [(set (reg FLAGS_REG) (compare (match_operand:SWI 0 "nonimmediate_operand" ",?m") @@ -6911,13 +6892,46 @@ (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) -(define_insn "*sub3_carry_ccgz" +(define_insn "sub3_carry_ccc" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend: (match_operand:DWIH 1 "register_operand" "0")) + (plus: + (ltu: (reg:CC FLAGS_REG) (const_int 0)) + (zero_extend: + (match_operand:DWIH 2 "x86_64_sext_operand" "rmWe"))))) + (clobber (match_scratch:DWIH 0 "=r"))] + "" + "sbb{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*sub3_carry_ccc_1" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extend: (match_operand:DWIH 1 "register_operand" "0")) + (plus: + (ltu: (reg:CC FLAGS_REG) (const_int 0)) + (match_operand: 2 "x86_64_dwzext_immediate_operand" "Wf")))) + (clobber (match_scratch:DWIH 0 "=r"))] + "" +{ + operands[3] = simplify_subreg (mode, operands[2], mode, 0); + return "sbb{}\t{%3, %0|%0, %3}"; +} + [(set_attr "type" "alu") + (set_attr "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 "sub3_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{}\t{%2, %0|%0, %2}" diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 4f3f1560f45..c46dd5c83e3 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -366,6 +366,31 @@ } }) +;; 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" -- 2.30.2