On Thu, Mar 12, 2026 at 10:46 AM Vineet Gupta <[email protected]> wrote:
>
> Hi,
>
> I wanted some insight/clarity on subreg promotion at expand time
> following a promote_function_mode()
> Apologies Roger and HJ for explicit CC but it seems you touched the same
> general area in 2021 and 2026 respectively.
>
> Here's my understand of various pieces and the problem I'm running into.
>
> 1a. PROMOTE_MODE has no direct ABI implications on its own but could do
> so indirectly if TARGET_PROMOTE_FUNCTION_MODE uses the default always
> which in turn uses this macro.
>
> 1b. According to docs [1] PROMOTE_MODE for for ISAs supporting only
> 64-bit registers would define it to word_mode (64) and I'm implying
> further that for ISAs supporting both it should be OK to define either
> 32 or 64 although it might be desirable to have 32, just for codegen
> fiddling with fewer bits if nothing else.
>
>     "On most RISC machines, which only have operations that operate on a
>     full register,
>     define this macro to set m to word_mode if m is an integer mode
>     narrower than
>     BITS_PER_WORD...."
>
> The RISC-V implementation is textbook perfect: for rv64 it would promote
> anything smaller that DI to DI (since that's how wide the container
> itself is) and if SI clear the unsigned bit as well since most ALU
> operations would sign extend the 32-bit result to 64-bits.
>
> BPF currently defines it to promote anything smaller that DI to DI: that
> might be a bit conservative and lead to fewer 32-bit only insns. A
> future/separate change to promote anything smaller than SI to SI can be
> done later and would not be wrong.
>
> 2a. Does setting SUBREG_PROMOTED_VAR_P imply that rest of pass pipeline
> assumes it is already promoted (thus potentially eliding any subsequent
> zero/sign extensions)  or does it ensure that such extensions will
> always be generated on any moves. The documentation [2] seems to suggest
> it is the latter, although usage in the code seems to be more like former.
>
>     "Nonzero in a subreg if it was made when accessing an object that
>     was promoted
>     to a wider mode in accord with the PROMOTED_MODE machine description
>     macro
>     ... . In this case, the mode of the
>     subreg is the declared mode of the object and the mode of SUBREG_REG
>     is the
>     mode of the register that holds the object. *Promoted variables are
>     always either
>     sign- or zero-extended to the wider mode on every assignment*.
>     Stored in the
>     in_struct field and printed as ‘/s’."
>
> FWIW my patch [3] removed code which was clearing SUBREG_PROMOTED_VAR_P
> as it was leading to extraneous sign extensions on RISC-V.So I tend to
> think that keeping subreg promoted prevents subsequent generation of
> extensions,
>
>     2023-10-16 8eb9cdd14218 expr: don't clear SUBREG_PROMOTED_VAR_P flag
>     for a promoted subreg [target/111466]
>
>
> 2b. expand_call () depending on modes of @target and @rettype would call
> ABI promotion for return value, wrap target in a subreg with new mode
> and set SUBREG_PROMOTED_VAR_P eagerly.
>
>     store_expr
>     |- expand_call
>             if  REG_P(target)  && GET_MODE (target) != TYPE_MODE (rettype))
>     ...
>                pmode = promote_function_mode (type, ret_mode,
>     &unsignedp, funtype, 1);
>                target = gen_lowpart_SUBREG (ret_mode, target);
>                SUBREG_PROMOTED_VAR_P (target) = 1;
>                SUBREG_PROMOTED_SET (target, unsignedp);
>
>     The followig convert_move (@from as subreg) just strips off the subreg
>     ...
>     |-  convert_move
>             if (GET_CODE (from) == SUBREG
>                 && SUBREG_PROMOTED_VAR_P (from)
>     ...
>                 from = gen_lowpart (to_int_mode, SUBREG_REG (from));
>
> This supposedly ensures that extensions won't be generated ? but between
> setting the subreg promoted and stripping the outer, an extension was
> not generated for return anyways, what am I missing ?
>
> 3. The reason for the questions above is PR/124171 [4] where we need to
> change gcc BPF function ABI to promote arguments as well as return
> values both in callee. I'm guessing the last part is atypical as args
> promoted in caller would imply return promoted in callee - but BPF code
> could be called from as well as calling into other ABIs, such as x86
> kernel code and thus needs to ensure sanity in either direction.
>
> For implementing this
>
>   * I'm specifying TARGET_PROMOTE_FUNCTION_MODE to default
>     promote_always: so both args and retval will be promoted.
>   * Currently bpf PROMOTE_MODE defaults to promoting anything smaller
>     than DI to DI (although ISA has insn to do SI mode only ops, and it
>     could be changed to that effect later on, separately, but that is
>     not really needed for the ABI change)
>
> This work for most part, except for a single weird test which fails to
> promote a bool return value in caller.
>
>     _Bool bar_bool(void);
>     int foo_bool_ne1(void) {
>            if (bar_bool() != 1) return 0; else return 1;
>     }
>
> On trunk this generates
>
>     foo_bool_ne1:
>          call    bar_bool
>          r0 &= 0xff
>          exit
>
> With TARGET_PROMOTE_FUNCTION_MODE to default always (and unchanged
> PROMOTE_MODE: sub DI to DI), it generates
>
>     foo_bool_ne1:
>          call    bar_bool
>          r0 = (s32) 0xff
>          exit
>
> The s32 truncation doesn't seem right as it needs to clamp it to 8 bits
> (ideally 1 but bool for most targets is implemented as QI).
>

Please try this enclosed patch.

-- 
H.J.
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 4773d789d8e..6f41a9e843c 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -299,13 +299,14 @@ bpf_file_end (void)
 static rtx
 bpf_function_value (const_tree ret_type,
 		    const_tree fntype_or_decl,
-		    bool outgoing ATTRIBUTE_UNUSED)
+		    bool outgoing)
 {
   enum machine_mode mode;
   int unsignedp;
 
   mode = TYPE_MODE (ret_type);
-  if (INTEGRAL_TYPE_P (ret_type))
+  /* NB: Treat the callee's return value as unpromoted.  */
+  if (outgoing && INTEGRAL_TYPE_P (ret_type))
     mode = promote_function_mode (ret_type, mode, &unsignedp,
 				  fntype_or_decl, 1);
 
@@ -1582,6 +1583,10 @@ bpf_expand_setmem (rtx *operands)
   return true;
 }
 
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE \
+  default_promote_function_mode_sign_extend
+
 #undef TARGET_DOCUMENTATION_NAME
 #define TARGET_DOCUMENTATION_NAME "BPF"
 
diff --git a/gcc/config/bpf/bpf.h b/gcc/config/bpf/bpf.h
index c8dad55fd4c..74d07e7f910 100644
--- a/gcc/config/bpf/bpf.h
+++ b/gcc/config/bpf/bpf.h
@@ -49,8 +49,8 @@
   do						\
     {						\
       if (GET_MODE_CLASS (M) == MODE_INT	\
-	  && GET_MODE_SIZE (M) < 8)		\
-	M = DImode;				\
+	  && GET_MODE_SIZE (M) < 4)		\
+	M = SImode;				\
     } while (0)
 
 /* Align argument parameters on the stack to 64-bit, at a minimum.  */

Reply via email to