FreeBSD/contrib/binutils/gas/config/tc-i386.c
/* Try to ensure constant immediates are represented in the smallest
   opcode possible.  */
Try to ensure constant immediates are represented in the smallest
opcode possible.
Try to ensure constant immediates are represented in the smallest opcode possible .
static void
optimize_imm (void)
{
  char guess_suffix = 0;
  int op;
  if (i.suffix)
    guess_suffix = i.suffix;
  else if (i.reg_operands)
    {
      for (op = i.operands; --op >= 0;)
	if (i.types[op] & Reg)
	  {
	    if (i.types[op] & Reg8)
	      guess_suffix = BYTE_MNEM_SUFFIX;
	    else if (i.types[op] & Reg16)
	      guess_suffix = WORD_MNEM_SUFFIX;
	    else if (i.types[op] & Reg32)
	      guess_suffix = LONG_MNEM_SUFFIX;
	    else if (i.types[op] & Reg64)
	      guess_suffix = QWORD_MNEM_SUFFIX;
	    break;
	  }
    }
  else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
    guess_suffix = WORD_MNEM_SUFFIX;
  for (op = i.operands; --op >= 0;)
    if (i.types[op] & Imm)
      {
	switch (i.op[op].imms->X_op)
	  {
	  case O_constant:
	    switch (guess_suffix)
	      {
	      case LONG_MNEM_SUFFIX:
		i.types[op] |= Imm32 | Imm64;
		break;
	      case WORD_MNEM_SUFFIX:
		i.types[op] |= Imm16 | Imm32S | Imm32 | Imm64;
		break;
	      case BYTE_MNEM_SUFFIX:
		i.types[op] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64;
		break;
	      }
	    if ((i.types[op] & Imm16)
		&& (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
	      {
		i.op[op].imms->X_add_number =
		  (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
	      }
	    if ((i.types[op] & Imm32)
		&& ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
		    == 0))
	      {
		i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
						^ ((offsetT) 1 << 31))
					       - ((offsetT) 1 << 31));
	      }
	    i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number);
	    if (guess_suffix == QWORD_MNEM_SUFFIX)
	      i.types[op] &= ~Imm32;
	    break;
	  case O_absent:
	  case O_register:
	    abort ();
	  default:
	    {
	      unsigned int mask, allowed = 0;
	      const template *t;
	      for (t = current_templates->start;
		   t < current_templates->end;
		   ++t)
		allowed |= t->operand_types[op];
	      switch (guess_suffix)
		{
		case QWORD_MNEM_SUFFIX:
		  mask = Imm64 | Imm32S;
		  break;
		case LONG_MNEM_SUFFIX:
		  mask = Imm32;
		  break;
		case WORD_MNEM_SUFFIX:
		  mask = Imm16;
		  break;
		case BYTE_MNEM_SUFFIX:
		  mask = Imm8;
		  break;
		default:
		  mask = 0;
		  break;
		}
	      if (mask & allowed)
		i.types[op] &= mask;
	    }
	    break;
	  }
      }
}
static void optimize_imm ( void ) { char guess_suffix = 0 ; int op ; if ( i . suffix ) guess_suffix = i . suffix ; else if ( i . reg_operands ) { for ( op = i . operands ; -- op >= 0 ; ) if ( i . types [ op ] & Reg ) { if ( i . types [ op ] & Reg8 ) guess_suffix = BYTE_MNEM_SUFFIX ; else if ( i . types [ op ] & Reg16 ) guess_suffix = WORD_MNEM_SUFFIX ; else if ( i . types [ op ] & Reg32 ) guess_suffix = LONG_MNEM_SUFFIX ; else if ( i . types [ op ] & Reg64 ) guess_suffix = QWORD_MNEM_SUFFIX ; break ; } } else if ( ( flag_code == CODE_16BIT ) ^ ( i . prefix [ DATA_PREFIX ] != 0 ) ) guess_suffix = WORD_MNEM_SUFFIX ; for ( op = i . operands ; -- op >= 0 ; ) if ( i . types [ op ] & Imm ) { switch ( i . op [ op ] . imms -> X_op ) { case O_constant : switch ( guess_suffix ) { case LONG_MNEM_SUFFIX : i . types [ op ] |= Imm32 | Imm64 ; break ; case WORD_MNEM_SUFFIX : i . types [ op ] |= Imm16 | Imm32S | Imm32 | Imm64 ; break ; case BYTE_MNEM_SUFFIX : i . types [ op ] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64 ; break ; } if ( ( i . types [ op ] & Imm16 ) && ( i . op [ op ] . imms -> X_add_number & ~ ( offsetT ) 0xffff ) == 0 ) { i . op [ op ] . imms -> X_add_number = ( ( ( i . op [ op ] . imms -> X_add_number & 0xffff ) ^ 0x8000 ) - 0x8000 ) ; } if ( ( i . types [ op ] & Imm32 ) && ( ( i . op [ op ] . imms -> X_add_number & ~ ( ( ( offsetT ) 2 << 31 ) - 1 ) ) == 0 ) ) { i . op [ op ] . imms -> X_add_number = ( ( i . op [ op ] . imms -> X_add_number ^ ( ( offsetT ) 1 << 31 ) ) - ( ( offsetT ) 1 << 31 ) ) ; } i . types [ op ] |= smallest_imm_type ( i . op [ op ] . imms -> X_add_number ) ; if ( guess_suffix == QWORD_MNEM_SUFFIX ) i . types [ op ] &= ~ Imm32 ; break ; case O_absent : case O_register : abort ( ) ; default : { unsigned int mask , allowed = 0 ; const template * t ; for ( t = current_templates -> start ; t < current_templates -> end ; ++ t ) allowed |= t -> operand_types [ op ] ; switch ( guess_suffix ) { case QWORD_MNEM_SUFFIX : mask = Imm64 | Imm32S ; break ; case LONG_MNEM_SUFFIX : mask = Imm32 ; break ; case WORD_MNEM_SUFFIX : mask = Imm16 ; break ; case BYTE_MNEM_SUFFIX : mask = Imm8 ; break ; default : mask = 0 ; break ; } if ( mask & allowed ) i . types [ op ] &= mask ; } break ; } } }
Try to ensure constant immediates are represented in the smallest
opcode possible.
Try to ensure constant immediates are represented in the smallest opcode possible .
/* Figure out a suffix from the last register operand specified.
	 We can't do this properly yet, ie. excluding InOutPortReg,
	 but the following works for instructions with immediates.
	 In any case, we can't set i.suffix yet.  */ /* If a suffix is given, this operand may be shortened.  */ /* If this operand is at most 16 bits, convert it
	       to a signed 16 bit number before trying to see
	       whether it will fit in an even smaller size.
	       This allows a 16-bit operand such as $0xffe0 to
	       be recognised as within Imm8S range.  */ /* We must avoid matching of Imm32 templates when 64bit
	       only immediate is available.  */ /* Symbols and expressions.  */ /* Convert symbolic operand to proper sizes for matching, but don't
	       prevent matching a set of insns that only supports sizes other
	       than those matching the insn suffix.  */