[PATCH] Support APX PUSHP/POPP

Jan Beulich jbeulich@suse.com
Wed Nov 29 08:29:56 GMT 2023


On 29.11.2023 04:08, Cui, Lili wrote:
>> On 28.11.2023 14:14, Cui, Lili wrote:
>>>>
>>>>>>>>> @@ -10621,6 +10621,19 @@ putop (instr_info *ins, const char
>>>>>>>> *in_template, int sizeflag)
>>>>>>>>>  	case 'P':
>>>>>>>>>  	  if (l == 0)
>>>>>>>>>  	    {
>>>>>>>>> +	      /* For pushp and popp, do not print {rex2} for them.  */
>>>>>>>>> +	      if (ins->address_mode == mode_64bit && !cond
>>>>>>>>
>>>>>>>> I don't think the mode_64bit check is needed here, as without
>>>>>>>> that REX.W cannot possibly be set (nor can a REX2 prefix be present).
>>>>>>>
>>>>>>> Done.
>>>>>>>
>>>>>>>>
>>>>>>>>> +		  && ins->last_rex2_prefix >= 0 && (ins->rex &
>> REX_W))
>>>>>>>>> +		{
>>>>>>>>> +		  *ins->obufp++ = 'p';
>>>>>>>>> +		  ins->rex2 |= 16;
>>>>>>>>
>>>>>>>> Please no new use of magic constants. Have a #define with a
>>>>>>>> suitable name, and use that here. Also I think the comment you
>>>>>>>> have ahead of the if() actually belongs here?
>>>>>>>>
>>>>>>>
>>>>>>> How about " #define IMPLICIT_REX2 16",  PUSHP/POPP can share it
>>>>>>> with
>>>>>> JMPABS.
>>>>>>
>>>>>> But what's implicit about the REX2 prefix here?
>>>>>
>>>>> PUSHP/POPP requires rex2.w ==1 and we don't want to print {rex2} for it.
>>>> JMPABS has the same need, so I want to define a common macro for
>>>> them, or NO_NEED_PRINT_REX2?
>>>>
>>>> Yes, we want a shared constant here (as much as we want a shared way
>>>> of dealing with the need to emit REX2 in the assembler). Still, the
>>>> naming wants to fit not only the goal (to suppress the printing of
>>>> {rex2}), but also where the bit is actually stored (in ->rex2).
>>>> Therefore its name wants to fit with the other names used for bits in
>>>> that field. Which (to me) first of all means it wants to start with REX_ (or
>> REX2_).
>>>> REX_SPECIAL or REX2_SPECIAL might be an option, but might also be too
>>>> generic (i.e. becoming an issue down the road). But I think this
>>>> should give you an idea ...
>>>
>>> How about REX2_ IGNORED ?
>>
>> Perhaps. It's no better or worse than REX2_SPECIAL. Just make sure you add a
>> comment explaining what it's to be used for.
>>
> 
> Done.
> 
>>>> Then again, why is this constant needed for PUSHP/POPP, which have
>>>> REX2.W set anyway, and hence that bit alone (when properly marked as
>>>> consumed) should already allow to omit {rex2}. The question of adding
>>>> a new constant (and how to suitably name it) would then be fully
>>>> constrained to the JMPABS patch (for now, i.e. until such time that a
>>>> 2nd insn appears which requires an otherwise empty REX2 prefix).
>>>>
>>>
>>> The current implementation is that no matter whether rex.w is consumed or
>> not, {rex2} will be printed as long as there is no Egpr. Of course, this place may
>> be changed as discussed later.
>>
>> That's a bug then. If there is a REX2 prefix with just REX2.W set, and if that bit
>> is properly consumed, no {rex2} should be printed imo. That's despite the
>> same thing being expressable (in the common case; not here) with REX.W.
>> Anything beyond that depends on the wider question of how to deal with
>> _unused_ REX2 payload bits.
>>
> 
> For the last two instructions, although rex.w is consumed, we still need to print {rex2} to distinguish them.
> 
> 0000000000000000 <_start>:
>    0:   48 50                                 rex.W push %rax
>    2:   d5 08 50                           pushp  %rax
>    5:   48 6a 01                           rex.W push $0x1
>    8:   d5 08 6a 01                     {rex2} push $0x1
>    c:   48 c7 00 12 00 00 00                 movq   $0x12,(%rax)
>   13:   d5 08 c7 00 12 00 00 00         {rex2} movq $0x12,(%rax)

Well, no, I don't really agree (especially not for the last one). But
that goes back to the more general question on the printing of {rex2}
without also indicating unconsumed bits.

>>>>>>>> The new Rex2 attribute is not only wasteful (it can easily be a
>>>>>>>> new enumerator used with OperandConstraint), but also misleading.
>>>>>>>> We don't just need REX2 here, but we need it with REX2.W set.
>>>>>>>> Even if from the tc-i386.c changes it looks as if that was
>>>>>>>> happening implicitly (presumably due to the absence of NoRex64),
>>>>>>>> naming still needs
>>>>>> to properly reflect the purpose.
>>>>>>>>
>>>>>>>
>>>>>>> You are right, rex2.w is set in process_suffix, since there is no NoRex64.
>>>>>>>
>>>>>>> How about Rex2W?
>>>>>>> if (i.tm.opcode_modifier.rex2w)
>>>>>>> {
>>>>>>>     i.rex2_encoding = true;
>>>>>>>     i.rex |= REX_W;   // add NoRex64 back, and set REX_W here.
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> Or just add a special judgment?
>>>>>>>
>>>>>>> if (t->mnem_off == MN_pushp || t->mnem_off == MN_popp) {
>>>>>>>     i.rex2_encoding = true;
>>>>>>>     i.rex |= REX_W;   // add NoRex64 back, and set REX_W here.
>>>>>>> }
>>>>>>
>>>>>> I'd prefer the latter over a new attribute (albeit once again with
>>>>>> the comment actually matching code), and perhaps I view the latter
>>>>>> equal to my earlier suggestion.
>>>>>>
>>>>>
>>>>> Ok, put them in process_operands, there's already a special handler
>>>>> here to
>>>> change the prefix.
>>>>>
>>>>> diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index
>>>>> 0dde2a9ad44..2f2b1b04d10 100644
>>>>> --- a/gas/config/tc-i386.c
>>>>> +++ b/gas/config/tc-i386.c
>>>>> @@ -8715,6 +8715,13 @@ process_operands (void)
>>>>>        i.tm.operands++;
>>>>>      }
>>>>>
>>>>> +  /* PUSHP/POPP requires rex2.w == 1.  */  if (i.tm.mnem_off ==
>>>>> + MN_pushp || i.tm.mnem_off == MN_popp)
>>>>> +    {
>>>>> +      i.rex2_encoding = true;
>>>>> +      i.rex |= REX_W;
>>>>> +    }
>>>>
>>>> Well, I'm sorry for not considering JMPABS earlier on, but with that
>>>> also needing dealing with, I think I view my alternative suggestion as
>> preferable.
>>>> That'll scale better when also considering that down the road further
>>>> such insns may appear. Whether it's actually OperandConstraint that
>>>> we leverage here is secondary (it's not ideal because there's nothing
>> operand related here).
>>>> I'd be perfectly okay with some other attribute being suitably
>>>> overloaded, whereas I continue to think that introducing new
>>>> attributes should preferably be limited to either cases where more
>>>> than just two or three templates use them or cases where otherwise
>>>> it's impossible to avoid ambiguities. From earlier changes of mine
>>>> the underlying reason ought to be pretty clear: Each new attribute
>>>> consumes storage, and with thousands of templates growth of storage
>>>> requirements should be balanced with how frequently an attribute is
>>>> actually going to have a non-zero value. For example, with
>>>> is_evex_encoding() gone a brief inspection suggests that it might be
>>>> possible to overload Masking (or maybe Broadcast): They're applicable
>>>> to EVEX templates only, and the class of insns we're discussing here
>>>> is never going to be EVEX (or VEX). IOW not much different from the
>>>> overloading of StaticRounding. Such an overload may then well be
>>>> named Rex2 (as you had it, and considering its intended use also for
>> JMPABS, plus taking into consideration that REX2.W will be set simply because
>> of the absence of NoRex64).
>>>>
>>>
>>> Haha, StaticRounding is really special, I tried "#define Rex2Req Masking" and
>> found that it will be used in i386-gen.c to identify EVEX (Broadcast...), then I
>> tried VexW and SIB found that they are all used without precheck whether it
>> was an vex instruction. Finally I wanted to re-use StaticRounding and found
>> out that hulin already uses it for legacy insns.
>>
>> Hmm, I'm sorry for the trouble. I'm inclined to say OperandConstraint with a
>> new #define it is then. Once everything's in I could then still see whether I can
>> (reasonably) make e.g. Masking work here.
>>
> 
> Then I will create a new attribute Rex2 for it.

???

Jan


More information about the Binutils mailing list