@ -124,6 +124,13 @@ enum dynreg_type
DYNREG_NUM_TYPES
} ;
enum operand_match_result
{
OPERAND_MATCH ,
OPERAND_OUT_OF_RANGE ,
OPERAND_MISMATCH
} ;
/* On the ia64, we can't know the address of a text label until the
instructions are packed into a bundle . To handle this , we keep
track of the list of labels that appear in front of each
@ -690,8 +697,9 @@ static void add_unwind_entry PARAMS((unw_rec_list *ptr));
static symbolS * declare_register PARAMS ( ( const char * name , int regnum ) ) ;
static void declare_register_set PARAMS ( ( const char * , int , int ) ) ;
static unsigned int operand_width PARAMS ( ( enum ia64_opnd ) ) ;
static int operand_match PARAMS ( ( const struct ia64_opcode * idesc ,
int index , expressionS * e ) ) ;
static enum operand_match_result operand_match PARAMS ( ( const struct ia64_opcode * idesc ,
int index ,
expressionS * e ) ) ;
static int parse_operand PARAMS ( ( expressionS * e ) ) ;
static struct ia64_opcode * parse_operands PARAMS ( ( struct ia64_opcode * ) ) ;
static void build_insn PARAMS ( ( struct slot * , bfd_vma * ) ) ;
@ -4740,7 +4748,7 @@ operand_width (opnd)
return bits ;
}
static in t
static enum operand_match_resul t
operand_match ( idesc , index , e )
const struct ia64_opcode * idesc ;
int index ;
@ -4757,62 +4765,77 @@ operand_match (idesc, index, e)
case IA64_OPND_AR_CCV :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_AR + 32 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_AR_PFS :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_AR + 64 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_GR0 :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_GR + 0 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_IP :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_IP )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_PR :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_PR )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_PR_ROT :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_PR_ROT )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_PSR :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_PSR )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_PSR_L :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_PSR_L )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_PSR_UM :
if ( e - > X_op = = O_register & & e - > X_add_number = = REG_PSR_UM )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_C1 :
if ( e - > X_op = = O_constant & & e - > X_add_number = = 1 )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( e - > X_add_number = = 1 )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_C8 :
if ( e - > X_op = = O_constant & & e - > X_add_number = = 8 )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( e - > X_add_number = = 8 )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_C16 :
if ( e - > X_op = = O_constant & & e - > X_add_number = = 16 )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( e - > X_add_number = = 16 )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
/* register operands: */
@ -4820,20 +4843,20 @@ operand_match (idesc, index, e)
case IA64_OPND_AR3 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_AR
& & e - > X_add_number < REG_AR + 128 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_B1 :
case IA64_OPND_B2 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_BR
& & e - > X_add_number < REG_BR + 8 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_CR3 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_CR
& & e - > X_add_number < REG_CR + 128 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_F1 :
@ -4842,14 +4865,14 @@ operand_match (idesc, index, e)
case IA64_OPND_F4 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_FR
& & e - > X_add_number < REG_FR + 128 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_P1 :
case IA64_OPND_P2 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_P
& & e - > X_add_number < REG_P + 64 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_R1 :
@ -4857,13 +4880,17 @@ operand_match (idesc, index, e)
case IA64_OPND_R3 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_GR
& & e - > X_add_number < REG_GR + 128 )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_R3_2 :
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_GR
& & e - > X_add_number < REG_GR + 4 )
return 1 ;
if ( e - > X_op = = O_register & & e - > X_add_number > = REG_GR )
{
if ( e - > X_add_number < REG_GR + 4 )
return OPERAND_MATCH ;
else if ( e - > X_add_number < REG_GR + 128 )
return OPERAND_OUT_OF_RANGE ;
}
break ;
/* indirect operands: */
@ -4880,12 +4907,12 @@ operand_match (idesc, index, e)
if ( e - > X_op = = O_index & & e - > X_op_symbol
& & ( S_GET_VALUE ( e - > X_op_symbol ) - IND_CPUID
= = opnd - IA64_OPND_CPUID_R3 ) )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_MR3 :
if ( e - > X_op = = O_index & & ! e - > X_op_symbol )
return 1 ;
return OPERAND_MATCH ;
break ;
/* immediate operands: */
@ -4893,40 +4920,58 @@ operand_match (idesc, index, e)
case IA64_OPND_LEN4 :
case IA64_OPND_LEN6 :
bits = operand_width ( idesc - > operands [ index ] ) ;
if ( e - > X_op = = O_constant
& & ( bfd_vma ) ( e - > X_add_number - 1 ) < ( ( bfd_vma ) 1 < < bits ) )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( bfd_vma ) ( e - > X_add_number - 1 ) < ( ( bfd_vma ) 1 < < bits ) )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_CNT2b :
if ( e - > X_op = = O_constant
& & ( bfd_vma ) ( e - > X_add_number - 1 ) < 3 )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( bfd_vma ) ( e - > X_add_number - 1 ) < 3 )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_CNT2c :
val = e - > X_add_number ;
if ( e - > X_op = = O_constant
& & ( val = = 0 | | val = = 7 | | val = = 15 | | val = = 16 ) )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( val = = 0 | | val = = 7 | | val = = 15 | | val = = 16 ) )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_SOR :
/* SOR must be an integer multiple of 8 */
if ( e - > X_add_number & 0x7 )
break ;
if ( e - > X_op = = O_constant & & e - > X_ add_number & 0x7 )
return OPERAND_OUT_OF_RANGE ;
case IA64_OPND_SOF :
case IA64_OPND_SOL :
if ( e - > X_op = = O_constant & &
( bfd_vma ) e - > X_add_number < = 96 )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( bfd_vma ) e - > X_add_number < = 96 )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_IMMU62 :
if ( e - > X_op = = O_constant )
{
if ( ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < 62 ) )
return 1 ;
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
else
{
@ -4952,10 +4997,10 @@ operand_match (idesc, index, e)
fix - > expr = * e ;
fix - > is_pcrel = 0 ;
+ + CURR_SLOT . num_fixups ;
return 1 ;
return OPERAND_MATCH ;
}
else if ( e - > X_op = = O_constant )
return 1 ;
return OPERAND_MATCH ;
break ;
case IA64_OPND_CCNT5 :
@ -4973,59 +5018,78 @@ operand_match (idesc, index, e)
case IA64_OPND_MHTYPE8 :
case IA64_OPND_POS6 :
bits = operand_width ( idesc - > operands [ index ] ) ;
if ( e - > X_op = = O_constant
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < bits ) )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < bits ) )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_IMMU9 :
bits = operand_width ( idesc - > operands [ index ] ) ;
if ( e - > X_op = = O_constant
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < bits ) )
if ( e - > X_op = = O_constant )
{
int lobits = e - > X_add_number & 0x3 ;
if ( ( ( bfd_vma ) e - > X_add_number & 0x3C ) ! = 0 & & lobits = = 0 )
e - > X_add_number | = ( bfd_vma ) 0x3 ;
return 1 ;
if ( ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < bits ) )
{
int lobits = e - > X_add_number & 0x3 ;
if ( ( ( bfd_vma ) e - > X_add_number & 0x3C ) ! = 0 & & lobits = = 0 )
e - > X_add_number | = ( bfd_vma ) 0x3 ;
return OPERAND_MATCH ;
}
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_IMM44 :
/* least 16 bits must be zero */
if ( ( e - > X_add_number & 0xffff ) ! = 0 )
/* XXX technically, this is wrong: we should not be issuing warning
messages until we ' re sure this instruction pattern is going to
be used ! */
as_warn ( _ ( " lower 16 bits of mask ignored " ) ) ;
if ( e - > X_op = = O_constant
& & ( ( e - > X_add_number > = 0
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < 44 ) )
| | ( e - > X_add_number < 0
& & ( bfd_vma ) - e - > X_add_number < = ( ( bfd_vma ) 1 < < 44 ) ) ) )
if ( e - > X_op = = O_constant )
{
/* sign-extend */
if ( e - > X_add_number > = 0
& & ( e - > X_add_number & ( ( bfd_vma ) 1 < < 43 ) ) ! = 0 )
if ( ( ( e - > X_add_number > = 0
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < 44 ) )
| | ( e - > X_add_number < 0
& & ( bfd_vma ) - e - > X_add_number < = ( ( bfd_vma ) 1 < < 44 ) ) ) )
{
e - > X_add_number | = ~ ( ( ( bfd_vma ) 1 < < 44 ) - 1 ) ;
/* sign-extend */
if ( e - > X_add_number > = 0
& & ( e - > X_add_number & ( ( bfd_vma ) 1 < < 43 ) ) ! = 0 )
{
e - > X_add_number | = ~ ( ( ( bfd_vma ) 1 < < 44 ) - 1 ) ;
}
return OPERAND_MATCH ;
}
return 1 ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_IMM17 :
/* bit 0 is a don't care (pr0 is hardwired to 1) */
if ( e - > X_op = = O_constant
& & ( ( e - > X_add_number > = 0
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < 17 ) )
| | ( e - > X_add_number < 0
& & ( bfd_vma ) - e - > X_add_number < = ( ( bfd_vma ) 1 < < 17 ) ) ) )
{
/* sign-extend */
if ( e - > X_add_number > = 0
& & ( e - > X_add_number & ( ( bfd_vma ) 1 < < 16 ) ) ! = 0 )
if ( e - > X_op = = O_constant )
{
if ( ( ( e - > X_add_number > = 0
& & ( bfd_vma ) e - > X_add_number < ( ( bfd_vma ) 1 < < 17 ) )
| | ( e - > X_add_number < 0
& & ( bfd_vma ) - e - > X_add_number < = ( ( bfd_vma ) 1 < < 17 ) ) ) )
{
e - > X_add_number | = ~ ( ( ( bfd_vma ) 1 < < 17 ) - 1 ) ;
/* sign-extend */
if ( e - > X_add_number > = 0
& & ( e - > X_add_number & ( ( bfd_vma ) 1 < < 16 ) ) ! = 0 )
{
e - > X_add_number | = ~ ( ( ( bfd_vma ) 1 < < 17 ) - 1 ) ;
}
return OPERAND_MATCH ;
}
return 1 ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
@ -5063,18 +5127,18 @@ operand_match (idesc, index, e)
fix - > expr = * e ;
fix - > is_pcrel = 0 ;
+ + CURR_SLOT . num_fixups ;
return 1 ;
return OPERAND_MATCH ;
}
else if ( e - > X_op ! = O_constant
& & ! ( e - > X_op = = O_big & & opnd = = IA64_OPND_IMM8M1U8 ) )
return 0 ;
return OPERAND_MISMATCH ;
if ( opnd = = IA64_OPND_IMM8M1U4 )
{
/* Zero is not valid for unsigned compares that take an adjusted
constant immediate range . */
if ( e - > X_add_number = = 0 )
return 0 ;
return OPERAND_OUT_OF_RANGE ;
/* Sign-extend 32-bit unsigned numbers, so that the following range
checks will work . */
@ -5086,7 +5150,7 @@ operand_match (idesc, index, e)
/* Check for 0x100000000. This is valid because
0x100000000 - 1 is the same as ( ( uint32_t ) - 1 ) . */
if ( val = = ( ( bfd_signed_vma ) 1 < < 32 ) )
return 1 ;
return OPERAND_MATCH ;
val = val - 1 ;
}
@ -5095,7 +5159,7 @@ operand_match (idesc, index, e)
/* Zero is not valid for unsigned compares that take an adjusted
constant immediate range . */
if ( e - > X_add_number = = 0 )
return 0 ;
return OPERAND_OUT_OF_RANGE ;
/* Check for 0x10000000000000000. */
if ( e - > X_op = = O_big )
@ -5105,9 +5169,9 @@ operand_match (idesc, index, e)
& & generic_bignum [ 2 ] = = 0
& & generic_bignum [ 3 ] = = 0
& & generic_bignum [ 4 ] = = 1 )
return 1 ;
return OPERAND_MATCH ;
else
return 0 ;
return OPERAND_OUT_OF_RANGE ;
}
else
val = e - > X_add_number - 1 ;
@ -5128,17 +5192,22 @@ operand_match (idesc, index, e)
if ( ( val > = 0 & & ( bfd_vma ) val < ( ( bfd_vma ) 1 < < ( bits - 1 ) ) )
| | ( val < 0 & & ( bfd_vma ) - val < = ( ( bfd_vma ) 1 < < ( bits - 1 ) ) ) )
return 1 ;
break ;
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
case IA64_OPND_INC3 :
/* +/- 1, 4, 8, 16 */
val = e - > X_add_number ;
if ( val < 0 )
val = - val ;
if ( e - > X_op = = O_constant
& & ( val = = 1 | | val = = 4 | | val = = 8 | | val = = 16 ) )
return 1 ;
if ( e - > X_op = = O_constant )
{
if ( ( val = = 1 | | val = = 4 | | val = = 8 | | val = = 16 ) )
return OPERAND_MATCH ;
else
return OPERAND_OUT_OF_RANGE ;
}
break ;
case IA64_OPND_TGT25 :
@ -5164,14 +5233,14 @@ operand_match (idesc, index, e)
fix - > expr = * e ;
fix - > is_pcrel = 1 ;
+ + CURR_SLOT . num_fixups ;
return 1 ;
return OPERAND_MATCH ;
}
case IA64_OPND_TAG13 :
case IA64_OPND_TAG13b :
switch ( e - > X_op )
{
case O_constant :
return 1 ;
return OPERAND_MATCH ;
case O_symbol :
fix = CURR_SLOT . fixup + CURR_SLOT . num_fixups ;
@ -5183,7 +5252,7 @@ operand_match (idesc, index, e)
fix - > expr = * e ;
fix - > is_pcrel = 1 ;
+ + CURR_SLOT . num_fixups ;
return 1 ;
return OPERAND_MATCH ;
default :
break ;
@ -5193,7 +5262,7 @@ operand_match (idesc, index, e)
default :
break ;
}
return 0 ;
return OPERAND_MISMATCH ;
}
static int
@ -5241,8 +5310,9 @@ parse_operands (idesc)
struct ia64_opcode * idesc ;
{
int i = 0 , highest_unmatched_operand , num_operands = 0 , num_outputs = 0 ;
int sep = 0 ;
int error_pos , out_of_range_pos , curr_out_of_range_pos , sep = 0 ;
enum ia64_opnd expected_operand = IA64_OPND_NIL ;
enum operand_match_result result ;
char mnemonic [ 129 ] ;
char * first_arg = 0 , * end , * saved_input_pointer ;
unsigned int sof ;
@ -5324,6 +5394,8 @@ parse_operands (idesc)
}
highest_unmatched_operand = 0 ;
curr_out_of_range_pos = - 1 ;
error_pos = 0 ;
expected_operand = idesc - > operands [ 0 ] ;
for ( ; idesc ; idesc = get_next_opcode ( idesc ) )
{
@ -5331,16 +5403,52 @@ parse_operands (idesc)
continue ; /* mismatch in # of outputs */
CURR_SLOT . num_fixups = 0 ;
/* Try to match all operands. If we see an out-of-range operand,
then continue trying to match the rest of the operands , since if
the rest match , then this idesc will give the best error message . */
out_of_range_pos = - 1 ;
for ( i = 0 ; i < num_operands & & idesc - > operands [ i ] ; + + i )
if ( ! operand_match ( idesc , i , CURR_SLOT . opnd + i ) )
break ;
{
result = operand_match ( idesc , i , CURR_SLOT . opnd + i ) ;
if ( result ! = OPERAND_MATCH )
{
if ( result ! = OPERAND_OUT_OF_RANGE )
break ;
if ( out_of_range_pos < 0 )
/* remember position of the first out-of-range operand: */
out_of_range_pos = i ;
}
}
/* If we did not match all operands, or if at least one operand was
out - of - range , then this idesc does not match . Keep track of which
idesc matched the most operands before failing . If we have two
idescs that failed at the same position , and one had an out - of - range
operand , then prefer the out - of - range operand . Thus if we have
" add r0=0x1000000,r1 " we get an error saying the constant is out
of range instead of an error saying that the constant should have been
a register . */
if ( i ! = num_operands )
if ( i ! = num_operands | | out_of_range_pos > = 0 )
{
if ( i > highest_unmatched_operand )
if ( i > highest_unmatched_operand
| | ( i = = highest_unmatched_operand
& & out_of_range_pos > curr_out_of_range_pos ) )
{
highest_unmatched_operand = i ;
expected_operand = idesc - > operands [ i ] ;
if ( out_of_range_pos > = 0 )
{
expected_operand = idesc - > operands [ out_of_range_pos ] ;
error_pos = out_of_range_pos ;
}
else
{
expected_operand = idesc - > operands [ i ] ;
error_pos = i ;
}
curr_out_of_range_pos = out_of_range_pos ;
}
continue ;
}
@ -5355,7 +5463,7 @@ parse_operands (idesc)
{
if ( expected_operand )
as_bad ( " Operand %u of `%s' should be %s " ,
highest_unmatched_operand + 1 , mnemonic ,
error_pos + 1 , mnemonic ,
elf64_ia64_operands [ expected_operand ] . desc ) ;
else
as_bad ( " Operand mismatch " ) ;