https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101076
Bug ID: 101076 Summary: RTL Combine pass won't generate sign_extnd RTX in some senario Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: wf831130 at sina dot com Target Milestone: --- I found a little bug in the combine pass. When I use 64bit gcc to compile the below test.c, I found some issue cat test.c int test(int a) { return (a << 16) >> 16; } In the combine pass, the log shows Trying 6 -> 7: 6: r76:SI=r78:DI#0<<0x10 REG_DEAD r78:DI 7: r75:SI=r76:SI>>0x10 REG_DEAD r76:SI Failed to match this instruction: (set (reg:SI 75) (ashiftrt:SI (subreg:SI (ashift:DI (reg:DI 78) (const_int 16 [0x10])) 0) (const_int 16 [0x10]))) Then I debugged and checkd the gcc code and fonud some issue in the function make_compound_operation_int which is in the combine.c, case ASHIFTRT: lhs = XEXP (x, 0); rhs = XEXP (x, 1); /* If we have (ashiftrt (ashift foo C1) C2) with C2 >= C1, this is a SIGN_EXTRACT. */ if (CONST_INT_P (rhs) && GET_CODE (lhs) == ASHIFT && CONST_INT_P (XEXP (lhs, 1)) && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1)) && INTVAL (XEXP (lhs, 1)) >= 0 && INTVAL (rhs) < mode_width) { new_rtx = make_compound_operation (XEXP (lhs, 0), next_code); 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); break; } /* See if we have operations between an ASHIFTRT and an ASHIFT. If so, try to merge the shifts into a SIGN_EXTEND. We could also do this for some cases of SIGN_EXTRACT, but it doesn't seem worth the effort; the case checked for occurs on Alpha. */ if (!OBJECT_P (lhs) && ! (GET_CODE (lhs) == SUBREG && (OBJECT_P (SUBREG_REG (lhs)))) && CONST_INT_P (rhs) && INTVAL (rhs) >= 0 && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT && INTVAL (rhs) < mode_width && (new_rtx = extract_left_shift (mode, lhs, INTVAL (rhs))) != 0) new_rtx = make_extraction (mode, make_compound_operation (new_rtx, next_code), 0, NULL_RTX, mode_width - INTVAL (rhs), code == LSHIFTRT, 0, in_code == COMPARE); break; The issue code is "(new_rtx = extract_left_shift (mode, lhs, INTVAL (rhs))) != 0)", this part wants to extract_left_shift information, but the second input parameter lhs is not right, it's still SUBREG, but it should transmit ashift part into the function. So the second parameter "lhs" should change to "XEXP (lhs, 0)". After change this issue, we can get the right combine result(sign_extend): Trying 6 -> 7: 6: r138:SI=r140:DI#0<<0x10 REG_DEAD r140:DI 7: r137:SI=r138:SI>>0x10 REG_DEAD r138:SI Successfully matched this instruction: (set (reg:SI 137) (sign_extend:SI (subreg:HI (reg:DI 140) 0))) allowing combination of insns 6 and 7 original costs 4 + 4 = 8 replacement cost 8 deferring deletion of insn with uid = 6. modifying insn i3 7: r137:SI=sign_extend(r140:DI#0) REG_DEAD r140:DI deferring rescan insn with uid = 7.