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. */