[PATCH v2 1/8] x86/APX: optimize {nf} forms of ADD/SUB with specific immediates

Cui, Lili lili.cui@intel.com
Fri Jun 28 08:28:41 GMT 2024


> Unlike for the legacy forms, where there's a difference in the resulting
> EFLAGS, for the NF variants we can safely replace ones using 0x80 by the
> respectively other insn while negating the immediate, saving 3 immediate
> bytes (just 1 though for 16-bit operand size). Similarly we can replace
> ones using 1 / -1 by INC/DEC (eliminating the immediate).
> ---
> v2: Also convert immediates of $1 / $-1 to INC/DEC. Move logic to
>     separate function.
> 
> --- a/gas/config/tc-i386.c
> +++ b/gas/config/tc-i386.c
> @@ -5327,6 +5327,84 @@ optimize_encoding (void)
>      }
>  }
> 
> +/* Try to shorten {nf} encodings, by shortening operand size or switching to
> +   functionally identical encodings.  */
> +
> +static void
> +optimize_nf_encoding (void)
> +{
> +  if (i.tm.base_opcode == 0x80
> +      && (i.tm.extension_opcode == 0 || i.tm.extension_opcode == 5)
> +      && i.suffix != BYTE_MNEM_SUFFIX
> +      && !i.types[1].bitfield.byte
> +      && !i.types[2].bitfield.byte
> +      && i.op[0].imms->X_op == O_constant
> +      && i.op[0].imms->X_add_number == 0x80)
> +    {
> +      /* Optimize: -O:
> +	   {nf} addw $0x80, ...  -> {nf} subw $-0x80, ...
> +	   {nf} addl $0x80, ...  -> {nf} subl $-0x80, ...
> +	   {nf} addq $0x80, ...  -> {nf} subq $-0x80, ...
> +
> +	   {nf} subw $0x80, ...  -> {nf} addw $-0x80, ...
> +	   {nf} subl $0x80, ...  -> {nf} addl $-0x80, ...
> +	   {nf} subq $0x80, ...  -> {nf} addq $-0x80, ...
> +       */
> +      i.tm.base_opcode |= 3;
> +      i.tm.extension_opcode ^= 5;
> +      i.tm.opcode_modifier.w = 0;
> +      i.op[0].imms->X_add_number = -i.op[0].imms->X_add_number;
> +
> +      i.tm.operand_types[0].bitfield.imm8 = 0;
> +      i.tm.operand_types[0].bitfield.imm8s = 1;
> +      i.tm.operand_types[0].bitfield.imm16 = 0;
> +      i.tm.operand_types[0].bitfield.imm32 = 0;
> +      i.tm.operand_types[0].bitfield.imm32s = 0;
> +
> +      i.types[0] = i.tm.operand_types[0];
> +    }
> +  else if ((i.tm.base_opcode | 3) == 0x83
> +      && (i.tm.extension_opcode == 0 || i.tm.extension_opcode == 5)
> +      && i.op[0].imms->X_op == O_constant
> +      && (i.op[0].imms->X_add_number == 1
> +	  || i.op[0].imms->X_add_number == -1
> +	  /* While for wider than byte operations immediates were suitably
> +	     adjusted earlier on, 0xff in the byte case needs covering
> +	     explicitly.  */
> +	  || (i.op[0].imms->X_add_number == 0xff
> +	      && (i.suffix == BYTE_MNEM_SUFFIX
> +		  || i.types[i.operands - 1].bitfield.byte))))
> +    {
> +      /* Optimize: -O:
> +	   {nf} add $1, ...        -> {nf} inc ...
> +	   {nf} add $-1, ...       -> {nf} dec ...
> +	   {nf} add $0xf...f, ...  -> {nf} dec ...
> +
> +	   {nf} sub $1, ...        -> {nf} dec ...
> +	   {nf} sub $-1, ...       -> {nf} inc ...
> +	   {nf} sub $0xf...f, ...  -> {nf} inc ...
> +       */
> +      i.tm.base_opcode = 0xfe;
> +      i.tm.extension_opcode
> +	= (i.op[0].imms->X_add_number == 1) != (i.tm.extension_opcode ==
> 0);
> +      i.tm.opcode_modifier.w = 1;
> +
> +      i.types[0] = i.types[1];
> +      i.types[1] = i.types[2];
> +      i.tm.operand_types[0] = i.tm.operand_types[1];
> +      i.tm.operand_types[1] = i.tm.operand_types[2];
> +      i.op[0] = i.op[1];
> +      i.op[1] = i.op[2];
> +      i.flags[0] = i.flags[1];
> +      i.flags[1] = i.flags[2];
> +      i.reloc[0] = i.reloc[1];
> +      i.reloc[1] = NO_RELOC;
> +
> +      i.imm_operands = 0;
> +      --i.operands;
> +    }
> +}
> +
>  static void
>  s_noopt (int dummy ATTRIBUTE_UNUSED)
>  {
> @@ -7206,7 +7284,11 @@ md_assemble (char *line)
>      }
> 
>    if (optimize && !i.no_optimize && i.tm.opcode_modifier.optimize)
> -    optimize_encoding ();
> +    {
> +      if (i.has_nf)
> +	optimize_nf_encoding ();
> +      optimize_encoding ();
> +    }
> 

I spent some time to understand these optimizations and found that the conversion between them is very clever. This patch is very interesting.

By the way, I think from the name, optimize_encoding includes optimize_nf_encoding, how about moving optimize_nf_encoding into the function optimize_encoding?

Lili.



More information about the Binutils mailing list