The attached patch is a result of discussing an S/390 issue with "and with complement" in some cases.
https://gcc.gnu.org/ml/gcc/2016-03/msg00163.html https://gcc.gnu.org/ml/gcc-patches/2016-04/msg01586.html Combine would merge a ZERO_EXTEND and a SET taking the known zero bits into account, resulting in an AND. Later on, make_compound_operation() fails to replace that with a ZERO_EXTEND which we get for free on S/390 but leaves the AND, eventually resulting in two consecutive AND instructions. The current code in make_compound_operation() that detects opportunities for ZERO_EXTEND does not work here because it does not take the known zero bits into account: /* If the constant is one less than a power of two, this might be representable by an extraction even if no shift is present. If it doesn't end up being a ZERO_EXTEND, we will ignore it unless 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); An attempt to use the zero bits in the above conditions resulted in many situations that generated worse code, so the patch tries to fix this in a more conservative way. While the effect is completely positive on S/390, this will very likely have unforeseeable consequences on other targets. Bootstrapped and regression tested on s390 and s390x only at the moment. Ciao Dominik ^_^ ^_^ -- Dominik Vogt IBM Germany
gcc/ChangeLog * combine.c (make_compound_operation): Take known zero bits into account when checking for possible zero_extend.
>From e70e6e469200b53b3f4ae52a766cdd322a4d365d Mon Sep 17 00:00:00 2001 From: Dominik Vogt <v...@linux.vnet.ibm.com> Date: Tue, 12 Apr 2016 09:53:46 +0100 Subject: [PATCH] Take known zero bits into account when checking extraction. Allows AND Insns with a const_int operand to be expressed as ZERO_EXTEND if the operand ist a power of 2 - 1 even with the known zero bits masked out. --- gcc/combine.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/gcc/combine.c b/gcc/combine.c index 1d0e8be..44bb1b3 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -7988,6 +7988,39 @@ make_compound_operation (rtx x, enum rtx_code in_code) next_code), i, NULL_RTX, 1, 1, 0, 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 + the sub expression has known zero bits, this can be expressed as + a zero_extend. */ + else if (GET_CODE (XEXP (x, 0)) == SUBREG) + { + rtx sub; + + sub = XEXP (XEXP (x, 0), 0); + machine_mode sub_mode = GET_MODE (sub); + if ((REG_P (sub) || MEM_P (sub)) + && GET_MODE_PRECISION (sub_mode) < mode_width + && (UINTVAL (XEXP (x, 1)) + | (~nonzero_bits (sub, sub_mode) & GET_MODE_MASK (sub_mode)) + ) == GET_MODE_MASK (sub_mode)) + { + bool speed_p = optimize_insn_for_speed_p (); + rtx temp = gen_rtx_ZERO_EXTEND (mode, sub); + int cost_of_and; + int cost_of_zero_extend; + + cost_of_and = rtx_cost (x, mode, in_code, 1, speed_p); + cost_of_zero_extend = rtx_cost (temp, mode, in_code, 1, speed_p); + if (cost_of_zero_extend <= cost_of_and) + { + new_rtx = make_compound_operation (sub, next_code); + new_rtx = make_extraction (mode, new_rtx, 0, 0, + GET_MODE_PRECISION (sub_mode), + 1, 0, in_code == COMPARE); + } + } + } + break; case LSHIFTRT: -- 2.3.0