[PATCH 2/2 v2] Support Intel MSR_IMM

Jan Beulich jbeulich@suse.com
Tue Nov 12 14:43:03 GMT 2024


On 11.11.2024 09:27, Hu, Lin1 wrote:
> --- a/gas/NEWS
> +++ b/gas/NEWS
> @@ -1,5 +1,7 @@
>  -*- text -*-
>  
> +* Add support for Intel MSR_IMM instructions.

Intel supported other architectures in the past, and it may support
others in the future. I think it is always a good idea to disambiguate
things here, like is done e.g. ...

>  * Add support for Intel AVX10.2 instructions.
>  
>  * Add support for the x86 Zhaoxin GMI instructions.

... here by naming x86.

> @@ -6990,18 +6993,19 @@ i386_assemble (char *line)
>       because of the swapping above) in the incoming set of operands.  */
>    if ((i.imm_operands == 2
>         && (t->mnem_off == MN_extrq || t->mnem_off == MN_insertq))
> -      || (t->mnem_off == MN_uwrmsr && i.imm_operands
> -	  && i.operands > i.imm_operands))
> +      || ((t->mnem_off == MN_uwrmsr || t->mnem_off == MN_wrmsrns)
> +	  && i.imm_operands && i.operands > i.imm_operands))
>        swap_2_operands (0, 1);
>  
>    if (i.imm_operands)
>      {
> -      /* For USER_MSR instructions, imm32 stands for the name of an model specific
> -	 register (MSR). That's an unsigned quantity, whereas all other insns with
> -	 32-bit immediate and 64-bit operand size use sign-extended
> -	 immediates (imm32s). Therefore these insns are special-cased, bypassing
> -	 the normal handling of immediates here.  */
> -      if (is_cpu(current_templates.start, CpuUSER_MSR))
> +      /* For USER_MSR and MSR_IMM instructions, imm32 stands for the name of an

While touching this comment, would you mind correcting "an" to "a", seeing
that ...

> +	 model specific register (MSR). That's an unsigned quantity, whereas all

... it's not the acronym that directly follows?

> --- a/gas/doc/c-i386.texi
> +++ b/gas/doc/c-i386.texi
> @@ -223,6 +223,7 @@ accept various extension mnemonics.  For example,
>  @code{avx10.2/512},
>  @code{avx10.2/256},
>  @code{avx10.2/128},
> +@code{msr_imm},
>  @code{amx_int8},
>  @code{amx_bf16},
>  @code{amx_fp16},
> @@ -1694,7 +1695,7 @@ supported on the CPU specified.  The choices for @var{cpu_type} are:
>  @item @samp{.cmpccxadd} @tab @samp{.wrmsrns} @tab @samp{.msrlist}
>  @item @samp{.avx_ne_convert} @tab @samp{.rao_int} @tab @samp{.fred} @tab @samp{.lkgs}
>  @item @samp{.avx_vnni_int16} @tab @samp{.sha512} @tab @samp{.sm3} @tab @samp{.sm4}
> -@item @samp{.pbndkb} @tab @samp{.user_msr} @tab @samp{.avx10.2}
> +@item @samp{.pbndkb} @tab @samp{.user_msr} @tab @samp{.avx10.2} @tab @samp{.msr_imm}
>  @item @samp{.wbnoinvd} @tab @samp{.pconfig} @tab @samp{.waitpkg} @tab @samp{.cldemote}
>  @item @samp{.shstk} @tab @samp{.gfni} @tab @samp{.vaes} @tab @samp{.vpclmulqdq}
>  @item @samp{.movdiri} @tab @samp{.movdir64b} @tab @samp{.enqcmd} @tab @samp{.tsxldtrk}

As indicated before - imo it would be nice if msr_imm was adjacent to
user_msr everywhere.

> @@ -8691,6 +8723,8 @@ static const struct dis386 bad_opcode = { "(bad)", { XX }, 0 };
>  /* Fetch error indicator.  */
>  static const struct dis386 err_opcode = { NULL, { XX }, 0 };
>  
> +static const struct dis386 map7_f6_opcode = { VEX_LEN_TABLE (VEX_LEN_MAP7_F6) };
> +
>  static const struct dis386 map7_f8_opcode = { VEX_LEN_TABLE (VEX_LEN_MAP7_F8) };

As asked for before, please omit the blank line between the two closely
related (for being hand-crafted rather than having full tables) entries.

> --- a/opcodes/i386-opc.tbl
> +++ b/opcodes/i386-opc.tbl
> @@ -965,6 +965,10 @@ cpuid, 0xfa2, i486, NoSuf, {}
>  // Pentium extensions.
>  wrmsr, 0xf30, i586, NoSuf, {}
>  rdtsc, 0xf31, i586, NoSuf, {}
> +// MSR_IMM instructions' imm32 stands for the name of an model specific
> +// register (MSR). The imm32 needs a special handler in tc-i386.c, hence put
> +// rdmsr of MSR_IMM firsty, since the logic is determined by is_cpu (...).
> +rdmsr, 0xf2f6/0, APX_F(MSR_IMM), Modrm|Vex128|xVexMap7|EVex128|VexW0|NoSuf, { Imm32, Reg64 }
>  rdmsr, 0xf32, i586, NoSuf, {}
>  cmpxchg8b, 0xfc7/1, i586, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|NoRex64|HLEPrefixLock, { Qword|Unspecified|BaseIndex }
>  
> @@ -3374,6 +3378,12 @@ cmp<cc>xadd, 0x66e<cc:opc>, APX_F(CMPCCXADD), Modrm|Vex|EVex128|Space0F38|Src2VV
>  
>  // WRMSRNS instruction.
>  
> +// MSR_IMM instructions' imm32 stands for the name of an model specific
> +// register (MSR). The imm32 needs a special handler in tc-i386.c, hence put
> +// wrmsrns of MSR_IMM firsty, since the logic is determined by is_cpu (...).
> +// Immediates want to be first; md_assemble() takes care of swapping operands
> +// accordingly.
> +wrmsrns, 0xf3f6/0, APX_F(MSR_IMM), Modrm|Vex128|xVexMap7|EVex128|VexW0|NoSuf, { Imm32, Reg64 }
>  wrmsrns, 0x0f01c6, WRMSRNS, NoSuf, {}
>  
>  // WRMSRNS instruction end.

Following on to my v1 comment here: I continue to disagree with this placement.
I now further disagree with the same verbose comment living in two places. If
the new insns need to come first, place them in a MSR_IMM section living ahead
of the similarly named further insns, allowing to have the comment just once.
(Also nit: s/firsty/first/ and perhaps also "needs special handling".) However,
there's absolutely no requirement that in tc-i386.c:i386_assemble() you use
is_cpu() just because that's used for the USER_MSR insns. There it's simply
easier / cheaper than comparing against MN_urdmsr and MN_uwrmsr. Whereas here
it may be better to indeed check the mnemonics, allowing the new entries to
live (once again) adjacent to the USER_MSR ones. Once put there, the WRMSRNS
comment regarding the imm placement can also simply reference UWRMSR's,
instead of fully reproducing it.

Jan


More information about the Binutils mailing list