Questions on PROMOTE_MODE, function_promote_mode

Vineet Gupta vineet.gupta@linux.dev
Fri Mar 13 00:29:34 GMT 2026


On 3/12/26 1:45 PM, H.J. Lu wrote:
> On Thu, Mar 12, 2026 at 10:46 AM Vineet Gupta <vineet.gupta@linux.dev> 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.

Awesome, it does work perfectly for the tripping tests before. I'll give 
it more extensive testing but this looks promising already.

FWIW, the newly wired up default_promote_function_mode_sign_extend () 
has the same semantics as updated PROMOTE_MODE so in theory we could get 
away with keeping bpf tgt hook to 
default_promote_function_mode_always_promote () but former conveys the 
semantics better.

Thx,
-Vineet


More information about the bpf mailing list