There are several situations that combine.c:change_zero_ext does not handle well yet. One of them is
(and:SI (subreg:SI (zero_extract:DI (reg:DI) ...) ...) (with const_int operands to "and" and "zero_extract") => (and:SI (subreg:SI (and:DI (lshiftrt:DI ...))) with two nested "and"s. Another one is (zero_extract:DI (foo:SI) ...) which is ignored by change_zero_ext. Attached are two experimental patches: 0001-* Deal with mode expanding zero_extracts in change_zero_ext. The patch looks good to me, but not sure whether endianness is handled properly. Is the second argument of gen_rtx_SUBREG correct? 0002-* This is a work in progress with the goal of fixing the first problem and similar ones by calling simplify_set after change_zero_ext to get rid of the overly complex code. That works fine in principle, but replaces back the (and (lshiftrt ...) ...) that change_zero_ext generates back into zero_extract form. Fiddling with simplify_set and make_compound_operation* a bit, trying to suppress undoing the transformations that change_zero_ext has just done, resulted in the (unfinished) patch. As it's not clear to me whether this is a valid approach I'd appreciate any advice on the patch or alternative ways of doing that. Ciao Dominik ^_^ ^_^ -- Dominik Vogt IBM Germany
>From 600ed3dadd5bc2568ab53be8466686abaf27ff3f Mon Sep 17 00:00:00 2001 From: Dominik Vogt <v...@linux.vnet.ibm.com> Date: Fri, 9 Dec 2016 02:48:30 +0100 Subject: [PATCH 1/2] combine: Handle mode expanding zero_extracts in change_zero_ext. Example: (zero_extract:DI (reg:SI) (const_int 24) (const_int 0)) --> (and:DI (subreg:DI (lshiftrt:SI (reg:SI) (const_int 8)) 0) (const_int 16777215)) --- gcc/combine.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gcc/combine.c b/gcc/combine.c index b429453..e14a08f 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -11237,18 +11237,24 @@ change_zero_ext (rtx pat) if (GET_CODE (x) == ZERO_EXTRACT && CONST_INT_P (XEXP (x, 1)) && CONST_INT_P (XEXP (x, 2)) - && GET_MODE (XEXP (x, 0)) == mode) + && (GET_MODE (XEXP (x, 0)) == mode + || GET_MODE_PRECISION (GET_MODE (XEXP (x, 0))) + < GET_MODE_PRECISION (mode))) { + machine_mode inner_mode = GET_MODE (XEXP (x, 0)); + size = INTVAL (XEXP (x, 1)); int start = INTVAL (XEXP (x, 2)); if (BITS_BIG_ENDIAN) - start = GET_MODE_PRECISION (mode) - size - start; + start = GET_MODE_PRECISION (inner_mode) - size - start; if (start) - x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start)); + x = gen_rtx_LSHIFTRT (inner_mode, XEXP (x, 0), GEN_INT (start)); else x = XEXP (x, 0); + if (mode != inner_mode) + x = gen_rtx_SUBREG (mode, x, 0); } else if (GET_CODE (x) == ZERO_EXTEND && SCALAR_INT_MODE_P (mode) -- 2.3.0
>From 8566f5a551cfd98978577b24ff05e8341410a56f Mon Sep 17 00:00:00 2001 From: Dominik Vogt <v...@linux.vnet.ibm.com> Date: Fri, 9 Dec 2016 15:56:15 +0100 Subject: [PATCH 2/2] combine: Call simplify_set after change_zero_ext. --- gcc/combine.c | 156 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 105 insertions(+), 51 deletions(-) diff --git a/gcc/combine.c b/gcc/combine.c index e14a08f..4c53fe1 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -431,12 +431,14 @@ static rtx *find_split_point (rtx *, rtx_insn *, bool); static rtx subst (rtx, rtx, rtx, int, int, int); static rtx combine_simplify_rtx (rtx, machine_mode, int, int); static rtx simplify_if_then_else (rtx); -static rtx simplify_set (rtx); +static rtx simplify_set (rtx, bool); static rtx simplify_logical (rtx); static rtx expand_compound_operation (rtx); static const_rtx expand_field_assignment (const_rtx); static rtx make_extraction (machine_mode, rtx, HOST_WIDE_INT, rtx, unsigned HOST_WIDE_INT, int, int, int); +static rtx make_compound_operation_1 (rtx, enum rtx_code, bool); +static rtx make_compound_operation_no_zero_ext (rtx, enum rtx_code); static rtx extract_left_shift (rtx, int); static int get_pos_from_mask (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT *); @@ -6186,7 +6188,7 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest, return expand_compound_operation (x); case SET: - return simplify_set (x); + return simplify_set (x, true); case AND: case IOR: @@ -6564,10 +6566,12 @@ simplify_if_then_else (rtx x) return x; } -/* Simplify X, a SET expression. Return the new expression. */ +/* Simplify X, a SET expression. Return the new expression. + Internally calls make_compound_operation_no_zero_ext instead of + make_compound_operation if ALLOW_ZERO_EXT is false. */ static rtx -simplify_set (rtx x) +simplify_set (rtx x, bool allow_zero_ext) { rtx src = SET_SRC (x); rtx dest = SET_DEST (x); @@ -6757,7 +6761,10 @@ simplify_set (rtx x) { /* Get SET_SRC in a form where we have placed back any compound expressions. Then do the checks below. */ - src = make_compound_operation (src, SET); + if (allow_zero_ext) + src = make_compound_operation (src, SET); + else + src = make_compound_operation_no_zero_ext (src, SET); SUBST (SET_SRC (x), src); } @@ -7793,12 +7800,15 @@ extract_left_shift (rtx x, int count) - Return null. This tells the caller to recurse on *X_PTR with IN_CODE equal to *NEXT_CODE_PTR, after which *X_PTR holds the final value. - - Return a new rtx, which the caller returns directly. */ + - Return a new rtx, which the caller returns directly. + + If ALLOW_ZERO_EXT is false, skip transformations to + ZERO_EXTRACT and ZERO_EXTEND. */ static rtx make_compound_operation_int (machine_mode mode, rtx *x_ptr, enum rtx_code in_code, - enum rtx_code *next_code_ptr) + enum rtx_code *next_code_ptr, bool allow_zero_ext) { rtx x = *x_ptr; enum rtx_code next_code = *next_code_ptr; @@ -7809,6 +7819,7 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, int i; rtx tem; bool equality_comparison = false; + int in_dest = allow_zero_ext ? 0 : 1; if (in_code == EQ) { @@ -7831,7 +7842,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, HOST_WIDE_INT count = INTVAL (XEXP (x, 1)); HOST_WIDE_INT multval = HOST_WIDE_INT_1 << count; - new_rtx = make_compound_operation (XEXP (x, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code, + allow_zero_ext); if (GET_CODE (new_rtx) == NEG) { new_rtx = XEXP (new_rtx, 0); @@ -7845,8 +7857,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, case PLUS: lhs = XEXP (x, 0); rhs = XEXP (x, 1); - lhs = make_compound_operation (lhs, next_code); - rhs = make_compound_operation (rhs, next_code); + lhs = make_compound_operation_1 (lhs, next_code, allow_zero_ext); + rhs = make_compound_operation_1 (rhs, next_code, allow_zero_ext); if (GET_CODE (lhs) == MULT && GET_CODE (XEXP (lhs, 0)) == NEG) { tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (lhs, 0), 0), @@ -7873,8 +7885,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, case MINUS: lhs = XEXP (x, 0); rhs = XEXP (x, 1); - lhs = make_compound_operation (lhs, next_code); - rhs = make_compound_operation (rhs, next_code); + lhs = make_compound_operation_1 (lhs, next_code, allow_zero_ext); + rhs = make_compound_operation_1 (rhs, next_code, allow_zero_ext); if (GET_CODE (rhs) == MULT && GET_CODE (XEXP (rhs, 0)) == NEG) { tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (rhs, 0), 0), @@ -7908,9 +7920,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, if (GET_CODE (XEXP (x, 0)) == LSHIFTRT && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0) { - new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (XEXP (x, 0), 0), next_code, + allow_zero_ext); new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), i, 1, - 0, in_code == COMPARE); + in_dest, in_code == COMPARE); } /* Same as previous, but for (subreg (lshiftrt ...)) in first op. */ @@ -7921,10 +7934,11 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, { rtx inner_x0 = SUBREG_REG (XEXP (x, 0)); machine_mode inner_mode = GET_MODE (inner_x0); - new_rtx = make_compound_operation (XEXP (inner_x0, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (inner_x0, 0), next_code, + allow_zero_ext); new_rtx = make_extraction (inner_mode, new_rtx, 0, XEXP (inner_x0, 1), - i, 1, 0, in_code == COMPARE); + i, 1, in_dest, in_code == COMPARE); if (new_rtx) { @@ -7943,9 +7957,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, its own. */ if (!new_rtx && i >= 0) { - new_rtx = make_compound_operation (XEXP (x, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code, + allow_zero_ext); new_rtx = make_extraction (mode, new_rtx, 0, NULL_RTX, i, 1, - 0, in_code == COMPARE); + in_dest, in_code == COMPARE); } } /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)). */ @@ -7961,7 +7976,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, XEXP (x, 1)), gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1), XEXP (x, 1))); - new_rtx = make_compound_operation (new_rtx, in_code); + new_rtx = make_compound_operation_1 (new_rtx, in_code, + allow_zero_ext); } /* If we are have (and (rotate X C) M) and C is larger than the number @@ -7972,11 +7988,12 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0 && i <= INTVAL (XEXP (XEXP (x, 0), 1))) { - new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (XEXP (x, 0), 0), next_code, + allow_zero_ext); new_rtx = make_extraction (mode, new_rtx, (GET_MODE_PRECISION (mode) - INTVAL (XEXP (XEXP (x, 0), 1))), - NULL_RTX, i, 1, 0, in_code == COMPARE); + NULL_RTX, i, 1, in_dest, in_code == COMPARE); } /* On machines without logical shifts, if the operand of the AND is @@ -7996,8 +8013,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, if ((INTVAL (XEXP (x, 1)) & ~mask) == 0) SUBST (XEXP (x, 0), gen_rtx_ASHIFTRT (mode, - make_compound_operation - (XEXP (XEXP (x, 0), 0), next_code), + make_compound_operation_1 + (XEXP (XEXP (x, 0), 0), next_code, + allow_zero_ext), XEXP (XEXP (x, 0), 1))); } @@ -8007,9 +8025,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, we are in a COMPARE. */ else if ((i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0) new_rtx = make_extraction (mode, - make_compound_operation (XEXP (x, 0), - next_code), - 0, NULL_RTX, i, 1, 0, in_code == COMPARE); + make_compound_operation_1 (XEXP (x, 0), + next_code, + allow_zero_ext), + 0, NULL_RTX, i, 1, in_dest, in_code == COMPARE); /* If we are in a comparison and this is an AND with a power of two, convert this into the appropriate bit extract. */ @@ -8017,9 +8036,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0 && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1)) new_rtx = make_extraction (mode, - make_compound_operation (XEXP (x, 0), - next_code), - i, NULL_RTX, 1, 1, 0, 1); + make_compound_operation_1 (XEXP (x, 0), + next_code, + allow_zero_ext), + i, NULL_RTX, 1, 1, in_dest, 1); /* If the one operand is a paradoxical subreg of a register or memory and the constant (limited to the smaller mode) has only zero bits where @@ -8041,10 +8061,11 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, mask = UINTVAL (XEXP (x, 1)) | (~nonzero_bits (sub, sub_mode)); if ((mask & mode_mask) == mode_mask) { - new_rtx = make_compound_operation (sub, next_code); + new_rtx = make_compound_operation_1 (sub, next_code, + allow_zero_ext); new_rtx = make_extraction (mode, new_rtx, 0, 0, GET_MODE_PRECISION (sub_mode), - 1, 0, in_code == COMPARE); + 1, in_dest, in_code == COMPARE); } } } @@ -8060,9 +8081,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0) { new_rtx = gen_rtx_ASHIFTRT (mode, - make_compound_operation (XEXP (x, 0), - next_code), - XEXP (x, 1)); + make_compound_operation_1 + (XEXP (x, 0), next_code, allow_zero_ext), + XEXP (x, 1)); break; } @@ -8081,11 +8102,13 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, && INTVAL (XEXP (lhs, 1)) >= 0 && INTVAL (rhs) < mode_width) { - new_rtx = make_compound_operation (XEXP (lhs, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (lhs, 0), next_code, + allow_zero_ext); new_rtx = make_extraction (mode, new_rtx, INTVAL (rhs) - INTVAL (XEXP (lhs, 1)), NULL_RTX, mode_width - INTVAL (rhs), - code == LSHIFTRT, 0, in_code == COMPARE); + code == LSHIFTRT, in_dest, + in_code == COMPARE); break; } @@ -8102,9 +8125,10 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT && INTVAL (rhs) < mode_width && (new_rtx = extract_left_shift (lhs, INTVAL (rhs))) != 0) - new_rtx = make_extraction (mode, make_compound_operation (new_rtx, next_code), + new_rtx = make_extraction (mode, make_compound_operation_1 + (new_rtx, next_code, allow_zero_ext), 0, NULL_RTX, mode_width - INTVAL (rhs), - code == LSHIFTRT, 0, in_code == COMPARE); + code == LSHIFTRT, in_dest, in_code == COMPARE); break; @@ -8125,13 +8149,14 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, < GET_MODE_PRECISION (GET_MODE (inner))) && subreg_lowpart_p (x)) { - new_rtx = make_compound_operation (XEXP (inner, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (inner, 0), next_code, + allow_zero_ext); int width = GET_MODE_PRECISION (GET_MODE (inner)) - INTVAL (XEXP (inner, 1)); if (width > mode_width) width = mode_width; new_rtx = make_extraction (mode, new_rtx, 0, XEXP (inner, 1), - width, 1, 0, in_code == COMPARE); + width, 1, in_dest, in_code == COMPARE); break; } @@ -8150,7 +8175,7 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, >= GET_MODE_BITSIZE (mode)))) subreg_code = SET; - tem = make_compound_operation (inner, subreg_code); + tem = make_compound_operation_1 (inner, subreg_code, allow_zero_ext); simplified = simplify_subreg (mode, tem, GET_MODE (inner), SUBREG_BYTE (x)); @@ -8167,7 +8192,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, /* If we have something other than a SUBREG, we might have done an expansion, so rerun ourselves. */ if (GET_CODE (newer) != SUBREG) - newer = make_compound_operation (newer, in_code); + newer = make_compound_operation_1 (newer, in_code, + allow_zero_ext); /* force_to_mode can expand compounds. If it just re-expanded the compound, use gen_lowpart to convert to the desired mode. */ @@ -8204,6 +8230,9 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, equivalent to ZERO_EXTRACT, SIGN_EXTRACT, ZERO_EXTEND, SIGN_EXTEND. Form these expressions. + ZERO_EXTRACT and ZERO_EXTEND are only handled if ALLOW_ZERO_EXT + is true. + Return the new rtx, usually just X. Also, for machines like the VAX that don't have logical shift insns, @@ -8218,8 +8247,8 @@ make_compound_operation_int (machine_mode mode, rtx *x_ptr, a comparison or a COMPARE against zero, it is COMPARE, or EQ if more precisely it is an equality comparison against zero. */ -rtx -make_compound_operation (rtx x, enum rtx_code in_code) +static rtx +make_compound_operation_1 (rtx x, enum rtx_code in_code, bool allow_zero_ext) { enum rtx_code code = GET_CODE (x); const char *fmt; @@ -8239,7 +8268,8 @@ make_compound_operation (rtx x, enum rtx_code in_code) if (SCALAR_INT_MODE_P (GET_MODE (x))) { rtx new_rtx = make_compound_operation_int (GET_MODE (x), &x, - in_code, &next_code); + in_code, &next_code, + allow_zero_ext); if (new_rtx) return new_rtx; code = GET_CODE (x); @@ -8248,9 +8278,9 @@ make_compound_operation (rtx x, enum rtx_code in_code) /* Now recursively process each operand of this operation. We need to handle ZERO_EXTEND specially so that we don't lose track of the inner mode. */ - if (code == ZERO_EXTEND) + if (allow_zero_ext && code == ZERO_EXTEND) { - new_rtx = make_compound_operation (XEXP (x, 0), next_code); + new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code, true); tem = simplify_const_unary_operation (ZERO_EXTEND, GET_MODE (x), new_rtx, GET_MODE (XEXP (x, 0))); if (tem) @@ -8263,19 +8293,35 @@ make_compound_operation (rtx x, enum rtx_code in_code) for (i = 0; i < GET_RTX_LENGTH (code); i++) if (fmt[i] == 'e') { - new_rtx = make_compound_operation (XEXP (x, i), next_code); + new_rtx = make_compound_operation_1 (XEXP (x, i), next_code, + allow_zero_ext); SUBST (XEXP (x, i), new_rtx); } else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) { - new_rtx = make_compound_operation (XVECEXP (x, i, j), next_code); + new_rtx = make_compound_operation_1 (XVECEXP (x, i, j), next_code, + allow_zero_ext); SUBST (XVECEXP (x, i, j), new_rtx); } maybe_swap_commutative_operands (x); return x; } + +rtx +make_compound_operation (rtx x, enum rtx_code in_code) +{ + return make_compound_operation_1 (x, in_code, true); +} + +/* Like make_compound_operation but does not transform to + ZERO_EXTEND and ZERO_EXTRACT. */ +static rtx +make_compound_operation_no_zero_ext (rtx x, enum rtx_code in_code) +{ + return make_compound_operation_1 (x, in_code, false); +} /* Given M see if it is a value that would select a field of bits within an item, but not the entire word. Return -1 if not. @@ -11352,7 +11398,11 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) bool changed = false; if (GET_CODE (pat) == SET) - changed = change_zero_ext (pat); + { + changed = change_zero_ext (pat); + if (changed) + pat = simplify_set (pat, false); + } else if (GET_CODE (pat) == PARALLEL) { int i; @@ -11360,7 +11410,11 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) { rtx set = XVECEXP (pat, 0, i); if (GET_CODE (set) == SET) - changed |= change_zero_ext (set); + if (change_zero_ext (set)) + { + changed = true; + set = simplify_set (set, false); + } } } -- 2.3.0