syn68k/syngen/byteorder.c

870 lines
24 KiB
C

#include "common.h"
#include "list.h"
#include "byteorder.h"
#include "uniquestring.h"
#include "error.h"
#include "bitstring.h"
#include "syn68k_private.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef enum {
BO_UNKNOWN, BO_DONT_CARE, BO_NATIVE, BO_BIG_ENDIAN, BO_UNKNOWABLE
} ByteOrder;
typedef enum {
BS_UNKNOWN, BS_BYTE, BS_WORD, BS_LONG=4, BS_LONG_LONG=8
} ByteSize;
typedef struct {
ByteOrder order;
ByteSize size;
BOOL sgnd;
} ExprInfo;
static ExprInfo expr_info (const List *expr, ByteOrder hint,
ExprInfo *field_info);
static ByteSize expr_list_max_size (List *ls, ByteSize hint,
ExprInfo *field_info);
static BOOL expr_list_any_are_unsigned (List *ls, ByteSize hint,
ExprInfo *field_info);
static void endianness (List *code, ByteSize desired_size, ByteOrder hint,
BOOL strong_hint, ExprInfo *field_info);
static Token *has_tok_dollar (List *ls, TokenType type, int number);
static BOOL has_tok_dollar_reg (List *ls, int number);
/*
* NOTE: the code for sorting operands has been "#if 0"'d out for a long time.
* I only changed the #if 0 to if defined (SORT_OPERANDS) to make it so
* we don't get complaints about compare_bitfields being defined but not
* used. It's not clear that SORT_OPERANDS should ever be defined.
* Certainly it shouldn't be turned on by anyone who isn't up to speed
* on the workings of Syn68k, and at this date (2003-12-15) nobody fits
* that description.
*/
#if defined (SORT_OPERANDS)
static int compare_bitfields (const void *bp1, const void *bp2);
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/* This function computes information about all unexpanded operands, placing
* information needed to extract them into op. It also determines appropriate
* byte ordering information and modifies v's code to swap bytes when
* appropriate. Returns the number of words of operands.
*/
int
compute_operand_info (OperandInfo *op, const ParsedOpcodeInfo *p,
const CCVariant *v)
{
PatternRange range;
ExprInfo field_info[16];
char decls[2048];
int words_in = p->operand_words_to_skip;
int i;
/* Zero out everything by default. */
memset (op, 0, sizeof *op);
/* Start out with the endianness/size of all operands unknown. */
memset (field_info, 0, sizeof field_info);
/* Figure out whatever we can about various fields. */
for (i = 1; pattern_range (p->opcode_bits, i, &range); i++)
{
/* Was this field expanded? */
if (field_expanded (i, p->opcode_bits, v->bits_to_expand))
{
/* Yep; it's going to expand to a constant number,
* so specify the byte order as NATIVE.
*/
field_info[i].order = BO_NATIVE;
break;
}
}
/* Loop through unexpanded fields and nail down their size + signedness. */
for (i = 1; pattern_range (p->opcode_bits, i, &range); i++)
{
Token *dollartok;
/* If this field was expanded, no need to save it as an operand. */
if (field_expanded (i, p->opcode_bits, v->bits_to_expand))
continue;
/* See if this field was actually used as a numeric constant. */
if ((dollartok = has_tok_dollar (v->code, TOK_DOLLAR_NUMBER, i)) != NULL)
{
field_info[i].sgnd = dollartok->u.dollarinfo.sgnd;
field_info[i].size = dollartok->u.dollarinfo.size;
}
else if (has_tok_dollar_reg (v->code, i))
{
/* Make register numbers be 32 bit uints, since this seems to
* make most compilers the happiest when doing array references.
*/
field_info[i].sgnd = FALSE;
field_info[i].size = BS_LONG;
field_info[i].order = BO_NATIVE;
}
}
/* Recursively set/determine the endianness of all expressions and
* add in swap's where appropriate.
*/
endianness (v->code, BO_UNKNOWN, BO_NATIVE, FALSE, field_info);
/* For all of the fields that weren't expanded, create bitfield
* information for them and create a declaration.
*/
for (i = 1; pattern_range (p->opcode_bits, i, &range); i++)
{
BitfieldInfo *b;
/* If this field was expanded, no need to save it as an operand. */
if (field_expanded (i, p->opcode_bits, v->bits_to_expand))
continue;
/* See if this field was actually used as a numeric constant,
* or as a register number...
*/
if (has_tok_dollar (v->code, TOK_DOLLAR_NUMBER, i) == NULL
&& !has_tok_dollar_reg (v->code, i))
continue;
/* If we just don't care about byte order for a numeric constant,
* make it default to BO_NATIVE.
*/
if (field_info[i].order == BO_UNKNOWN
&& has_tok_dollar (v->code, TOK_DOLLAR_NUMBER, i) != NULL)
field_info[i].order = BO_NATIVE;
/* It wasn't expanded, so create a bitfield for it. */
if (field_info[i].order == BO_UNKNOWN
|| field_info[i].size == BS_UNKNOWN)
{
parse_error (v->code, "Error: Unable to determine best byte order "
"or size of operand field %d. "
"(order == %d, size == %d)\n", i, field_info[i].order,
field_info[i].size);
print_list (stderr, v->code);
putc ('\n', stderr);
}
else
{
b = &op->bitfield[op->num_bitfields++];
b->rev_amode = (has_tok_dollar (v->code, TOK_DOLLAR_REVERSED_AMODE,i)
!= NULL);
b->index = range.index;
b->length = range.length - 1;
b->sign_extend = field_info[i].sgnd;
b->make_native_endian = (field_info[i].order == BO_NATIVE
|| field_info[i].size == BS_BYTE);
#if 0
/* We prefer to translate 16 bit operands to the synthetic
* instruction stream as 16 bit operands. However, if the operand
* is to be sign- or zero-extended to 32 bits, and it is not to be
* native endian, we extend it at translation time. The logic
* behind this is that extending a 16 bit number is a free
* operation on the 386 (movesx/movezx) and a cheap operation on
* other CPU's, but this will only work for operands in native
* format. Also, since 32 bit operands force operand alignment for
* QUADALIGN machines, using 16 bit operands can avoid alignment
* NOPs.
*/
if (b->make_native_endian && range.length <= 16)
b->words = 1 - 1; /* 1 word. */
else
b->words = ((field_info[i].size == BS_LONG) ? 2 : 1) - 1;
#else
/* We now prefer to use BS_LONG operands. These are generally
* faster on RISC chips, and on the Pentium movswl, etc. are
* apparently not pairable.
*/
if (b->make_native_endian)
field_info[i].size = BS_LONG;
b->words = ((field_info[i].size == BS_LONG) ? 2 : 1) - 1;
#endif
if (b->index == MAGIC_END_INDEX && b->length == MAGIC_END_LENGTH)
fatal_error ("Illegal bitfield index/length (%d/%d). This "
"combination is used as a magic value and shouldn't "
"show up in real code!", MAGIC_END_INDEX,
MAGIC_END_LENGTH);
}
}
if (op->num_bitfields > MAX_BITFIELDS)
fatal_error ("Too many operand bitfields (%d) for OpcodeMappingInfo "
"struct.\n", op->num_bitfields);
#if defined (SORT_OPERANDS)
/* Sort operands by size and then by field number. */
{
#ifdef GENERATE_NATIVE_CODE
BitfieldInfo *save;
int size = op->num_bitfields * sizeof op->bitfield[0];
save = (BitfieldInfo *) alloca (size);
memcpy (save, op->bitfield, size);
#endif
qsort (op->bitfield, op->num_bitfields, sizeof op->bitfield[0],
compare_bitfields);
#ifdef GENERATE_NATIVE_CODE
if (v->native_code_info != NULL && memcmp (save, op->bitfield, size))
parse_error (v->code, "byteorder.c insists on reordering your operands!"
" This is incompatible with native code generation.");
#endif
}
#endif /* defined (SORT_OPERANDS) */
/* Create decls string. */
decls[0] = '\0';
for (i = 0; i < op->num_bitfields; i++)
{
int field = field_with_index (p->opcode_bits, op->bitfield[i].index);
/* Output declaration. */
#if 1 || !defined(TEMPS_AT_TOP)
sprintf (decls + strlen (decls), " %sint%d operand_%d = ",
op->bitfield[i].sign_extend ? "" : "u",
field_info[field].size * 8, field);
#else /* defined(TEMPS_AT_TOP) */
sprintf (decls + strlen (decls), " operand_%s%d_%d = ",
op->bitfield[i].sign_extend ? "" : "u",
field_info[field].size * 8, field);
#endif /* defined(TEMPS_AT_TOP) */
/* Fetch initial value. */
if (op->bitfield[i].words == 1 - 1 /* One 16 bit word. */ )
{
if (op->bitfield[i].sign_extend)
strcat (decls, "(int16) ");
sprintf (decls + strlen (decls), "code[%d];", words_in);
/* We leave a gap here. We used to pack all the 16 bit
* operands together, but they have largely been abandoned
* in favor of 32 bit operands. They only crop up occasionally
* when we're doing byte swapping of immediate constants.
* We leave a gap here so everything stays aligned.
*/
words_in += 2;
}
else /* Two 16 bit words. */
{
strcat (decls, "*((");
if (!op->bitfield[i].sign_extend)
strcat (decls, "u");
if (words_in != 0)
sprintf (decls + strlen (decls), "int32 *) (code + %d));",
words_in);
else
sprintf (decls + strlen (decls), "int32 *) code);");
words_in += 2;
}
/* Add comment indicating swappedness. */
if (op->bitfield[i].make_native_endian)
strcat (decls, " /* Native endian */\n");
else
strcat (decls, " /* Big endian */\n");
}
op->operand_decls = unique_string (decls);
return words_in;
}
static void
swap (List *ls, ByteSize size, BOOL sgnd)
{
List *swap, *new;
/* Pointless to swap bytes, assuming they aren't trying to use
* swapsb or swapub as a cast!
*/
if (size == BS_BYTE)
return;
/* Verify that we have a legal size. */
if (size == BS_UNKNOWN)
{
parse_error (ls, "Internal error, byteorder.c: Attempting to swap with "
"size == BS_UNKNOWN!\n");
return;
}
swap = alloc_list ();
new = alloc_list ();
/* Copy the specified list. */
*new = *ls;
new->cdr = NULL;
/* Create swap expr. */
swap->token.type = TOK_SWAP;
assert (size == 1 || size == 2 || size == 4);
swap->token.u.swapinfo.size = size;
swap->token.u.swapinfo.sgnd = sgnd;
swap->cdr = new;
/* Make the specified list be a real list that contains (swap expr). */
ls->token.type = TOK_LIST;
ls->car = swap;
propagate_fileinfo (&ls->token, ls);
}
/* This magic function marches through a list of code and makes everything
* a workable endianness by either inserting swaps or requesting that
* operands be translated with a certain endianness. If strong_hint
* is TRUE, the expression is forced to assume the endianness specified
* by hint.
*/
static void
endianness (List *code, ByteSize desired_size, ByteOrder hint,
BOOL strong_hint, ExprInfo *field_info)
{
ExprInfo info = expr_info (code, hint, field_info);
Token *t = &code->token;
char buf[256];
if (code == NULL)
return;
#if 0
printf ("Endianness: desired_size = %d, hint = %d, strong_hint = %d\n",
desired_size, hint, strong_hint);
print_list (stdout, code);
putchar ('\n');
#endif
if (strong_hint && t->type == TOK_DOLLAR_NUMBER)
{
field_info[t->u.dollarinfo.which].order = hint;
return;
}
if (t->type == TOK_LIST)
{
List *l2;
t = &code->car->token;
switch (t->type) {
case TOK_SHIFT_RIGHT:
case TOK_SHIFT_LEFT:
case TOK_PLUS:
case TOK_MINUS:
case TOK_MULTIPLY:
case TOK_DIVIDE:
case TOK_MOD:
case TOK_BITWISE_AND:
case TOK_BITWISE_OR:
case TOK_BITWISE_XOR:
case TOK_BITWISE_NOT:
/* Force all operands to be the same endianness... */
for (l2 = CDAR (code); l2 != NULL; l2 = l2->cdr)
{
endianness (l2, ((info.size == BS_UNKNOWN)
? desired_size : info.size),
info.order, TRUE, field_info);
}
break;
case TOK_EXPLICIT_LIST:
for (l2 = CDAR (code); l2 != NULL; l2 = l2->cdr)
{
/* Just process everything else. */
endianness (l2, desired_size, hint, strong_hint, field_info);
}
break;
case TOK_LIST:
endianness (code->car, desired_size, hint, strong_hint, field_info);
break;
case TOK_ASSIGN:
if (IS_CCBIT_TOKEN (CDAR (code)->token.type))
{
#ifdef CCR_ELEMENT_8_BITS
endianness (CDDAR (code), BS_UNKNOWN, BO_NATIVE, TRUE,
field_info);
#else /* !CCR_ELEMENT_8_BITS */
endianness (CDDAR (code), desired_size, hint, strong_hint,
field_info);
#endif /* !CCR_ELEMENT_8_BITS */
}
else
{
if (info.size == BS_UNKNOWN)
{
parse_error (CDAR (code), "Attempting to assign to object "
"of unknown size!\n");
print_list (stderr, code);
putc ('\n', stderr);
}
/* Process LHS. */
endianness (CDAR (code), info.size, hint, FALSE, field_info);
/* Force RHS to have same type as LHS. */
endianness (CDDAR (code), info.size, info.order, TRUE, field_info);
}
break;
case TOK_SWAP:
/* Process operand. */
endianness (CDAR (code), t->u.swapinfo.size,
(hint == BO_NATIVE) ? BO_BIG_ENDIAN : BO_NATIVE,
strong_hint, field_info);
break;
case TOK_DEREF:
/* Force address to be native. */
if (t->u.derefinfo.size != 0)
endianness (CDAR (code), BS_LONG, BO_NATIVE, TRUE, field_info);
else
endianness (CDDAR (code), BS_LONG, BO_NATIVE, TRUE, field_info);
break;
case TOK_EQUAL:
case TOK_NOT_EQUAL:
{
/* Force both operands to be the same endianness (don't
* care which since we are testing equality).
*/
ExprInfo info2 = expr_info (CDAR (code), BO_NATIVE, field_info);
endianness (CDAR (code), expr_list_max_size (CDAR (code),
BO_NATIVE,
field_info),
info2.order, TRUE, field_info);
}
break;
case TOK_GREATER_THAN:
case TOK_GREATER_OR_EQUAL:
case TOK_LESS_THAN:
case TOK_LESS_OR_EQUAL:
/* Force all operands to be BO_NATIVE. */
for (l2 = CDAR (code); l2 != NULL; l2 = l2->cdr)
{
endianness (l2, expr_list_max_size (CDAR (code), BO_NATIVE,
field_info),
BO_NATIVE, TRUE, field_info);
}
break;
case TOK_AND:
case TOK_OR:
case TOK_XOR:
case TOK_NOT:
/* Process all of the boolean things. Don't care about endianness. */
for (l2 = CDAR (code); l2 != NULL; l2 = l2->cdr)
{
endianness (l2, BO_UNKNOWN, BO_NATIVE, FALSE, field_info);
}
break;
case TOK_IF:
for (l2 = CDAR (code); l2 != NULL; l2 = l2->cdr)
{
/* Just process everything. */
endianness (l2, BS_UNKNOWN, BO_NATIVE, FALSE, field_info);
}
break;
case TOK_SWITCH:
/* Force switch value to be native. */
endianness (CDAR (code), BS_WORD, BO_NATIVE, TRUE, field_info);
for (l2 = CDDAR (code); l2 != NULL; l2 = l2->cdr)
{
/* Force case value to be native. */
endianness (l2->car, BS_WORD, BO_NATIVE, TRUE, field_info);
/* Process case code. */
endianness (CDAR (l2), BS_UNKNOWN, BO_NATIVE, FALSE, field_info);
}
break;
case TOK_FUNC_CALL:
for (l2 = CDDAR (code); l2 != NULL; l2 = l2->cdr)
{
/* Force everything to be native */
endianness (l2, BS_UNKNOWN, BO_NATIVE, TRUE, field_info);
}
break;
case TOK_CAST:
for (l2 = CDDAR (code); l2 != NULL; l2 = l2->cdr)
{
/* Just process everything. */
endianness (l2, BS_UNKNOWN, BO_NATIVE, TRUE, field_info);
}
break;
default:
parse_error (code->car, "Unhandled operator %s in endianness().\n",
unparse_token (t, buf));
break;
}
}
/* If we are backwards and this upsets someone, swap! */
info = expr_info (code, hint, field_info);
if (strong_hint && info.order != hint)
{
ByteSize s;
if (desired_size == BS_UNKNOWN)
s = info.size;
else if (info.size == BS_UNKNOWN)
s = desired_size;
else
s = MIN (desired_size, info.size);
swap (code, s, info.sgnd);
}
}
static ExprInfo
expr_info (const List *expr, ByteOrder hint, ExprInfo *field_info)
{
ExprInfo info = { BO_UNKNOWN, BS_UNKNOWN, FALSE }; /* Defaults. */
const Token *t;
char buf[256];
if (expr == NULL)
return info;
t = &expr->token;
switch (t->type) {
case TOK_DATA_REGISTER:
case TOK_ADDRESS_REGISTER:
case TOK_TEMP_REGISTER:
info.order = BO_NATIVE;
info.size = t->u.reginfo.size;
info.sgnd = t->u.reginfo.sgnd;
break;
case TOK_DOLLAR_DATA_REGISTER:
case TOK_DOLLAR_ADDRESS_REGISTER:
case TOK_DOLLAR_GENERAL_REGISTER:
info.order = BO_NATIVE;
info.size = t->u.dollarinfo.size;
info.sgnd = t->u.dollarinfo.sgnd;
break;
case TOK_DOLLAR_AMODE: /* We assume that by the time we reach */
case TOK_DOLLAR_REVERSED_AMODE: /* here, all reg amodes have been */
info.order = BO_BIG_ENDIAN; /* converted to dollar_reg's. */
info.size = t->u.dollarinfo.size;
info.sgnd = t->u.dollarinfo.sgnd;
break;
case TOK_DOLLAR_AMODE_PTR:
case TOK_DOLLAR_REVERSED_AMODE_PTR:
info.order = BO_NATIVE;
info.size = sizeof (void *);
info.sgnd = TRUE;
break;
case TOK_AMODE: /* We assume that by the time we reach */
case TOK_REVERSED_AMODE: /* here, all reg amodes have been */
info.order = BO_BIG_ENDIAN; /* converted to dollar_reg's. */
info.size = t->u.amodeinfo.size;
info.sgnd = t->u.amodeinfo.sgnd;
break;
case TOK_CODE:
info.order = BO_NATIVE;
info.size = sizeof (void *);
info.sgnd = FALSE;
break;
case TOK_NUMBER:
info.order = BO_NATIVE;
info.size = BO_UNKNOWN;
info.sgnd = TRUE;
break;
case TOK_DEFAULT:
info.order = BO_NATIVE; /* So it's a legal case number. */
info.size = BS_LONG;
info.sgnd = FALSE;
break;
case TOK_CCC:
case TOK_CCN:
case TOK_CCV:
case TOK_CCX:
case TOK_CCNZ:
info.order = BO_NATIVE;
#ifdef CCR_ELEMENT_8_BITS
info.size = BS_BYTE;
#else
info.size = BS_UNKNOWN;
#endif
info.sgnd = FALSE;
break;
case TOK_DOLLAR_NUMBER:
info.order = field_info[t->u.dollarinfo.which].order;
info.size = t->u.dollarinfo.size;
info.sgnd = t->u.dollarinfo.sgnd;
if (field_info[t->u.dollarinfo.which].size != BS_UNKNOWN
&& field_info[t->u.dollarinfo.which].size != info.size)
parse_error (expr, "Operand field %s defined with more than one "
"different size! (%d/%d)\n",
unparse_token (t, buf),
field_info[t->u.dollarinfo.which].size,
t->u.dollarinfo.size);
break;
case TOK_FALSE:
case TOK_TRUE:
info.order = BO_NATIVE;
info.size = BS_UNKNOWN;
info.sgnd = NO;
break;
case TOK_QUOTED_STRING:
info.order = BO_NATIVE;
info.size = BS_LONG; /* Who knows what is appropriate here. */
info.sgnd = TRUE; /* Sure, why not. */
break;
case TOK_LIST:
expr = expr->car;
t = &expr->token;
switch (t->type) {
case TOK_PLUS:
case TOK_MINUS:
case TOK_MULTIPLY:
case TOK_DIVIDE:
case TOK_MOD:
info.order = BO_NATIVE;
info.size = expr_list_max_size (expr->cdr, hint, field_info);
info.sgnd = !expr_list_any_are_unsigned (expr->cdr, hint, field_info);
break;
case TOK_SHIFT_LEFT:
case TOK_SHIFT_RIGHT:
info = expr_info (expr->cdr, hint, field_info); /* Get defaults. */
info.order = BO_NATIVE;
break;
case TOK_BITWISE_AND:
case TOK_BITWISE_OR:
case TOK_BITWISE_XOR:
case TOK_BITWISE_NOT:
{
List *l2;
int big = 0, native = 0;
info.sgnd = TRUE;
for (l2 = expr->cdr; l2 != NULL; l2 = l2->cdr)
{
if (l2->token.type != TOK_NUMBER)
{
ExprInfo info2 = expr_info (l2, hint, field_info);
if (info2.order == BO_BIG_ENDIAN)
big++;
else if (info2.order == BO_NATIVE)
native++;
if (!info2.sgnd)
info.sgnd = FALSE;
}
}
if (big == native) /* Tie? Then stick with the hint. */
info.order = hint;
else info.order = (big > native) ? BO_BIG_ENDIAN : BO_NATIVE;
info.size = expr_list_max_size (expr->cdr, hint, field_info);
}
break;
case TOK_SWAP:
info = expr_info (expr->cdr, hint, field_info);
if (info.order == BO_BIG_ENDIAN)
info.order = BO_NATIVE;
else if (info.order == BO_NATIVE)
info.order = BO_BIG_ENDIAN;
info.size = t->u.swapinfo.size;
info.sgnd = t->u.swapinfo.sgnd;
break;
case TOK_LIST:
/* Stick with "unknown" default. */
break;
case TOK_ASSIGN:
#ifndef CCR_ELEMENT_8_BITS
if (IS_CCBIT_TOKEN (expr->cdr->token.type))
{
info = expr_info (CDDR (expr), hint, field_info); /* rhs */
}
else
#endif
{
info = expr_info (expr->cdr, hint, field_info); /* lhs */
}
break;
case TOK_CAST:
info.order = BO_NATIVE;
info.size = BS_UNKNOWN;
info.sgnd = FALSE; /* Who knows? */
break;
case TOK_DEREF:
if (t->u.derefinfo.size == 0)
{
info.order = BO_NATIVE;
info.size = BS_UNKNOWN;
info.sgnd = FALSE; /* Who knows? */
}
else
{
info.order = BO_BIG_ENDIAN;
info.size = t->u.derefinfo.size;
info.sgnd = t->u.derefinfo.sgnd;
}
break;
case TOK_EQUAL:
case TOK_NOT_EQUAL:
case TOK_GREATER_THAN:
case TOK_LESS_THAN:
case TOK_GREATER_OR_EQUAL:
case TOK_LESS_OR_EQUAL:
case TOK_AND:
case TOK_OR:
case TOK_XOR:
case TOK_NOT:
info.order = BO_NATIVE;
info.size = BS_BYTE;
info.sgnd = FALSE;
break;
case TOK_SWITCH:
case TOK_IF:
break;
case TOK_DEFAULT:
info.order = BO_NATIVE; /* So it's a legal case number. */
info.size = BS_LONG;
info.sgnd = FALSE;
break;
case TOK_EXPLICIT_LIST: /* Unknown everything. */
break;
case TOK_FUNC_CALL:
info.order = BO_NATIVE;
info.size = BS_LONG;
info.sgnd = TRUE; /* Who knows? */
break;
default:
parse_error (expr, "byteorder.c: Don't know how to process "
"endianness/byte size for operator %s.\n",
unparse_token (t, buf));
break;
}
break;
default:
parse_error (expr, "byteorder.c: Don't know how to process "
"endianness/byte size for %s.\n", unparse_token (t, buf));
break;
}
return info;
}
static ByteSize
expr_list_max_size (List *ls, ByteSize hint, ExprInfo *field_info)
{
ByteSize s = BO_UNKNOWN;
for (; ls != NULL; ls = ls->cdr)
{
ExprInfo info = expr_info (ls, hint, field_info);
if (info.size > s)
s = info.size;
}
return s;
}
static BOOL
expr_list_any_are_unsigned (List *ls, ByteSize hint, ExprInfo *field_info)
{
for (; ls != NULL; ls = ls->cdr)
{
ExprInfo info = expr_info (ls, hint, field_info);
if (!info.sgnd)
return TRUE;
}
return FALSE;
}
static Token *
has_tok_dollar (List *ls, TokenType type, int number)
{
Token *t;
if (ls == NULL)
return NULL;
if (ls->token.type == type
&& ls->token.u.dollarinfo.which == number)
return &ls->token;
t = has_tok_dollar (ls->car, type, number);
if (t != NULL)
return t;
return has_tok_dollar (ls->cdr, type, number);
}
static BOOL
has_tok_dollar_reg (List *ls, int number)
{
if (ls == NULL)
return FALSE;
if ((ls->token.type == TOK_DOLLAR_DATA_REGISTER
|| ls->token.type == TOK_DOLLAR_ADDRESS_REGISTER
|| ls->token.type == TOK_DOLLAR_GENERAL_REGISTER)
&& ls->token.u.dollarinfo.which == number)
return TRUE;
return (has_tok_dollar_reg (ls->car, number)
|| has_tok_dollar_reg (ls->cdr, number));
}
#if defined (SORT_OPERANDS)
/* qsort helper function. Places longs before words, breaks ties by
* whichever bitfield has the lowest bit index into the 68k instruction
* stream (ie the lowest field number).
*/
static int
compare_bitfields (const void *bp1, const void *bp2)
{
const BitfieldInfo *b1 = (const BitfieldInfo *)bp1;
const BitfieldInfo *b2 = (const BitfieldInfo *)bp2;
if (b2->words - b1->words != 0)
return ((int) b2->words) - ((int) b1->words);
return ((int) b1->index) - ((int) b2->index);
}
#endif /* defined (SORT_OPERANDS) */