https://gcc.gnu.org/g:8a6b78ec5796a64a6d311770e06711d19832caf9
commit r16-8459-g8a6b78ec5796a64a6d311770e06711d19832caf9 Author: Takayuki 'January June' Suwa <[email protected]> Date: Fri Apr 3 11:00:32 2026 +0900 xtensa: Change xtensa_legitimize_address() to allow the emission of one more ADDMI instruction Previously, address displacement mitigation measures for exceeding machine instruction limits involved using only one ADDMI machine instruction (adding an immediate value that is a multiple of 256) to cover approxi- mately 32 kilobytes before and after the address. This patch expands the range covered by the mitigation by doubling it by using just one more ADDMI instruction, slightly more advantageous than the result without the mitigation, ie., covering the displacement amount by loading from constant pool or using CONST16 instruction pair. /* example */ int test(int a[]) { return a[4] + a[16032]; } ;; before (-O2 -mconst16) test: entry sp, 32 movi.n a8, 0 ;; 3 instructions const16 a8, 64128 ;; add.n a8, a2, a8 ;; l32i.n a8, a8, 0 l32i.n a2, a2, 16 add.n a2, a2, a8 retw.n ;; after (-O2 -mconst16) test: entry sp, 32 addmi a8, a2, 0x7b00 ;; 2 instructions addmi a8, a8, 0x7f00 ;; l32i.n a2, a2, 16 l32i a8, a8, 128 add.n a2, a2, a8 retw.n gcc/ChangeLog: * config/xtensa/xtensa.cc (xtensa_legitimize_address): Add code to legitimize the displacement of 64 kilobytes before and after using two ADDMI instructions. Diff: --- gcc/config/xtensa/xtensa.cc | 50 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 60de3e7bb088..2c16a197d00b 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -2313,32 +2313,42 @@ xtensa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, machine_mode mode) { + rtx plus0, plus1, temp; + HOST_WIDE_INT offset, mem_offset, addmi_offset; + if (xtensa_tls_symbol_p (x)) return xtensa_legitimize_tls_address (x); - if (GET_CODE (x) == PLUS) - { - rtx plus0 = XEXP (x, 0); - rtx plus1 = XEXP (x, 1); + if (GET_CODE (x) != PLUS) + return x; - if (! REG_P (plus0) && REG_P (plus1)) - { - plus0 = XEXP (x, 1); - plus1 = XEXP (x, 0); - } + plus0 = XEXP (x, 0), plus1 = XEXP (x, 1); + if (! REG_P (plus0) && REG_P (plus1)) + std::swap (plus0, plus1); + + /* Try to split up the offset to use up to two ADDMI instructions. */ + if (REG_P (plus0) && CONST_INT_P (plus1) + && ! xtensa_mem_offset (offset = INTVAL (plus1), mode) + && ! xtensa_simm8 (offset) + && xtensa_mem_offset (mem_offset = offset & 0xff, mode)) + { + /* The two ADDMIs are slightly more efficient than + "L32R w/litpool + ADD" or "CONST16 pair + ADD", if applicable. */ + addmi_offset = offset & ~0xff; + if (addmi_offset > 32512) + offset = 32512, addmi_offset -= 32512; + else if (addmi_offset < -32768) + offset = -32768, addmi_offset += 32768; + else + offset = 0; - /* Try to split up the offset to use an ADDMI instruction. */ - if (REG_P (plus0) && CONST_INT_P (plus1) - && !xtensa_mem_offset (INTVAL (plus1), mode) - && !xtensa_simm8 (INTVAL (plus1)) - && xtensa_mem_offset (INTVAL (plus1) & 0xff, mode) - && xtensa_simm8x256 (INTVAL (plus1) & ~0xff)) + if (xtensa_simm8x256 (addmi_offset)) { - rtx temp = gen_reg_rtx (Pmode); - rtx addmi_offset = GEN_INT (INTVAL (plus1) & ~0xff); - emit_insn (gen_rtx_SET (temp, gen_rtx_PLUS (Pmode, plus0, - addmi_offset))); - return gen_rtx_PLUS (Pmode, temp, GEN_INT (INTVAL (plus1) & 0xff)); + emit_insn (gen_addsi3 (temp = gen_reg_rtx (Pmode), + plus0, GEN_INT (addmi_offset))); + if (offset) + emit_insn (gen_addsi3 (temp, temp, GEN_INT (offset))); + return gen_rtx_PLUS (Pmode, temp, GEN_INT (mem_offset)); } }
