From 45f1fed76d90cdb62bce1c1feb6b93c1116a5278 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Sun, 3 May 2026 03:14:43 +0900 Subject: [PATCH] xtensa: Implement "-mforce-l32" target-specific option In the previous patches, both the named address space "__force_l32" and the target-specific attribute "force_l32" were introduced for reading sub-words from the instruction memory area. This patch introduces a new target-specific option "-mforce-l32", which allows sub-word reading from the instruction memory area even in the generic address spaces (ie., the default memory references) or without the "force_l32" attribute. /* example */ int test(unsigned int i) { static const char string[] __attribute__((section(".irom.text"))) = "The quick brown fox jumps over the lazy dog."; return i < __builtin_strlen(string) ? string[i] : -1; } ;; result (-O2 -mforce-l32) .literal_position .literal .LC0, string$0 test: entry sp, 32 movi.n a8, 0x2b bltu a8, a2, .L3 l32r a9, .LC0 ;; If -mno-force-l32, movi.n a8, -4 ;; add.n a9, a9, a2 ;; l32r a8, .LC0 and a8, a9, a8 ;; add.n a8, a8, a2 l32i.n a8, a8, 0 ;; l8ui a2, a8, 0 ssa8l a9 ;; srl a8, a8 ;; extui a2, a8, 0, 8 ;; retw.n .L3: movi.n a2, -1 retw.n .section .irom.text,"a" string$0: .string "The quick brown fox jumps over the lazy dog." gcc/ChangeLog: * config/xtensa/xtensa.cc (xtensa_expand_load_force_l32_2): New sub-function for inspecting pseudos that clearly point to the function's stack frame. (xtensa_expand_load_force_l32): Add handling for loading from the generic address space when the "-mforce-l32" option is enabled, however, obvious references to function stack frames are excluded. * config/xtensa/xtensa.opt (mforce-l32): New target-specific option definition. --- gcc/config/xtensa/xtensa.cc | 36 ++++++++++++++++++++++++++++++++---- gcc/config/xtensa/xtensa.opt | 4 ++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 1b4aa8934ff..5a9b18de1ce 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -2628,7 +2628,7 @@ xtensa_emit_add_imm (rtx dst, rtx src, HOST_WIDE_INT imm, rtx scratch, load with bit-extraction of the required bytes. */ static bool -xtensa_expand_load_force_l32_1 (rtx mem) +xtensa_expand_load_force_l32_1 (const_rtx mem) { tree expr = MEM_EXPR (mem), type; @@ -2639,6 +2639,29 @@ xtensa_expand_load_force_l32_1 (rtx mem) && lookup_attribute ("force_l32", TYPE_ATTRIBUTES (type)); } +static bool +xtensa_expand_load_force_l32_2 (const_rtx reg) +{ + unsigned int regno; + + /* These pseudos are unlikely to be passed during the RTL generation, + but just in case. */ + switch (regno = REGNO (reg)) + { + case STACK_POINTER_REGNUM: + case FRAME_POINTER_REGNUM: + case ARG_POINTER_REGNUM: + return true; + } + + /* gccint explicitly states that these pseudos indicate the location of + the stack frame. In addition, the static chain pointers also clearly + refer to the stack frame. */ + return IN_RANGE (regno, FIRST_VIRTUAL_REGISTER, LAST_VIRTUAL_REGISTER) + || (cfun && cfun->static_chain_decl + && cfun->static_chain_decl == REG_EXPR (regno_reg_rtx[regno])); +} + bool xtensa_expand_load_force_l32 (rtx *operands, machine_mode dest_mode, machine_mode src_mode, int unsignedp) @@ -2670,13 +2693,17 @@ xtensa_expand_load_force_l32 (rtx *operands, machine_mode dest_mode, /* Exclude insns that do not perform memory loading with "force_l32". */ if (MEM_ADDR_SPACE (src) != ADDR_SPACE_FORCE_L32 - && ! xtensa_expand_load_force_l32_1 (src)) + && ! xtensa_expand_load_force_l32_1 (src) + && (!TARGET_FORCE_L32 || MEM_ADDR_SPACE (src) != ADDR_SPACE_GENERIC)) return false; /* As a preprocessing, handle cases where addr is (PLUS (REG, OFFSET)) form. */ if (REG_P (addr = XEXP (src, 0))) - ; + { + if (xtensa_expand_load_force_l32_2 (addr)) + return false; + } else if (GET_CODE (addr) == PLUS) { rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); @@ -2684,7 +2711,8 @@ xtensa_expand_load_force_l32 (rtx *operands, machine_mode dest_mode, if (! CONST_INT_P (op1)) std::swap (op0, op1); - if (! REG_P (op0) || ! CONST_INT_P (op1)) + if (! REG_P (op0) || ! CONST_INT_P (op1) + || xtensa_expand_load_force_l32_2 (op0)) return false; if ((v = INTVAL (op1)) == 0) addr = op0; diff --git a/gcc/config/xtensa/xtensa.opt b/gcc/config/xtensa/xtensa.opt index aee776f124e..90665ba180c 100644 --- a/gcc/config/xtensa/xtensa.opt +++ b/gcc/config/xtensa/xtensa.opt @@ -71,3 +71,7 @@ Use windowed registers ABI. mstrict-align Target Var(xtensa_strict_alignment) Init(XTENSA_STRICT_ALIGNMENT_UNDEFINED) Do not use unaligned memory references. + +mforce-l32 +Target Mask(FORCE_L32) +Use L32I instruction to access 1- and 2-byte quantities in memory instead of L8UI/L16UI/L16SI.