summaryrefslogtreecommitdiff
path: root/util/romcc/romcc.c
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
committerEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
commit83b991afff40e12a8b6756af06a472842edb1a66 (patch)
treea441ff0d88afcb0a07cf22dc3653db3e07a05c98 /util/romcc/romcc.c
parent080038bfbd8fdf08bac12476a3789495e6f705ca (diff)
downloadcoreboot-83b991afff40e12a8b6756af06a472842edb1a66.tar.xz
- O2, enums, and switch statements work in romcc
- Support for compiling romcc on non x86 platforms - new romc options -msse and -mmmx for specifying extra registers to use - Bug fixes to device the device disable/enable framework and an amd8111 implementation - Move the link specification to the chip specification instead of the path - Allow specifying devices with internal bridges. - Initial via epia support - Opteron errata fixes git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1200 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/romcc/romcc.c')
-rw-r--r--util/romcc/romcc.c1671
1 files changed, 1163 insertions, 508 deletions
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index 2b14506c50..db7d61131e 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -19,6 +19,7 @@
#define DEBUG_COALESCING 0
#define DEBUG_SDP_BLOCKS 0
#define DEBUG_TRIPLE_COLOR 0
+#define DEBUG_SIMPLIFY 0
#warning "FIXME boundary cases with small types in larger registers"
#warning "FIXME give clear error messages about unused variables"
@@ -207,14 +208,32 @@ static char *slurp_file(const char *dirname, const char *filename, off_t *r_size
return buf;
}
-/* Long on the destination platform */
-#ifdef __x86_64__
-typedef unsigned int ulong_t;
-typedef int long_t;
-#else
-typedef unsigned long ulong_t;
-typedef long long_t;
-#endif
+/* Types on the destination platform */
+#warning "FIXME this assumes 32bit x86 is the destination"
+typedef int8_t schar_t;
+typedef uint8_t uchar_t;
+typedef int8_t char_t;
+typedef int16_t short_t;
+typedef uint16_t ushort_t;
+typedef int32_t int_t;
+typedef uint32_t uint_t;
+typedef int32_t long_t;
+typedef uint32_t ulong_t;
+
+#define SCHAR_T_MIN (-128)
+#define SCHAR_T_MAX 127
+#define UCHAR_T_MAX 255
+#define CHAR_T_MIN SCHAR_T_MIN
+#define CHAR_T_MAX SCHAR_T_MAX
+#define SHRT_T_MIN (-32768)
+#define SHRT_T_MAX 32767
+#define USHRT_T_MAX 65535
+#define INT_T_MIN (-LONG_T_MAX - 1)
+#define INT_T_MAX 2147483647
+#define UINT_T_MAX 4294967295U
+#define LONG_T_MIN (-LONG_T_MAX - 1)
+#define LONG_T_MAX 2147483647
+#define ULONG_T_MAX 4294967295U
struct file_state {
struct file_state *prev;
@@ -506,11 +525,12 @@ struct token {
struct op_info {
const char *name;
unsigned flags;
-#define PURE 1
-#define IMPURE 2
+#define PURE 1 /* Triple has no side effects */
+#define IMPURE 2 /* Triple has side effects */
#define PURE_BITS(FLAGS) ((FLAGS) & 0x3)
-#define DEF 4
+#define DEF 4 /* Triple is a variable definition */
#define BLOCK 8 /* Triple stores the current block */
+#define STRUCTURAL 16 /* Triple does not generate a machine instruction */
unsigned char lhs, rhs, misc, targ;
};
@@ -559,16 +579,16 @@ static const struct op_info table_ops[] = {
[OP_LOAD ] = OP( 0, 1, 0, 0, IMPURE | DEF | BLOCK, "load"),
[OP_STORE ] = OP( 0, 2, 0, 0, IMPURE | BLOCK , "store"),
-[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK, "noop"),
+[OP_NOOP ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "noop"),
[OP_INTCONST ] = OP( 0, 0, 0, 0, PURE | DEF, "intconst"),
-[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE, "blobconst"),
+[OP_BLOBCONST ] = OP( 0, 0, 0, 0, PURE , "blobconst"),
[OP_ADDRCONST ] = OP( 0, 0, 1, 0, PURE | DEF, "addrconst"),
[OP_WRITE ] = OP( 0, 2, 0, 0, PURE | BLOCK, "write"),
[OP_READ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "read"),
[OP_COPY ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "copy"),
-[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF, "piece"),
+[OP_PIECE ] = OP( 0, 0, 1, 0, PURE | DEF | STRUCTURAL, "piece"),
[OP_ASM ] = OP(-1, -1, 0, 0, IMPURE, "asm"),
[OP_DEREF ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "deref"),
[OP_DOT ] = OP( 0, 1, 0, 0, 0 | DEF | BLOCK, "dot"),
@@ -581,14 +601,14 @@ static const struct op_info table_ops[] = {
/* Call is special most it can stand in for anything so it depends on context */
[OP_CALL ] = OP(-1, -1, 1, 0, 0 | BLOCK, "call"),
/* The sizes of OP_CALL and OP_VAL_VEC depend upon context */
-[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK, "valvec"),
+[OP_VAL_VEC ] = OP( 0, -1, 0, 0, 0 | BLOCK | STRUCTURAL, "valvec"),
-[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF, "list"),
+[OP_LIST ] = OP( 0, 1, 1, 0, 0 | DEF | STRUCTURAL, "list"),
/* The number of targets for OP_BRANCH depends on context */
[OP_BRANCH ] = OP( 0, -1, 0, 1, PURE | BLOCK, "branch"),
-[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "label"),
-[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK, "adecl"),
-[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK, "sdecl"),
+[OP_LABEL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "label"),
+[OP_ADECL ] = OP( 0, 0, 0, 0, PURE | BLOCK | STRUCTURAL, "adecl"),
+[OP_SDECL ] = OP( 0, 0, 1, 0, PURE | BLOCK | STRUCTURAL, "sdecl"),
/* The number of RHS elements of OP_PHI depend upon context */
[OP_PHI ] = OP( 0, -1, 1, 0, PURE | DEF | BLOCK, "phi"),
@@ -697,6 +717,8 @@ struct triple {
#define TRIPLE_FLAG_FLATTENED (1 << 31)
#define TRIPLE_FLAG_PRE_SPLIT (1 << 30)
#define TRIPLE_FLAG_POST_SPLIT (1 << 29)
+#define TRIPLE_FLAG_VOLATILE (1 << 28)
+#define TRIPLE_FLAG_LOCAL (1 << 27)
struct occurance *occurance;
union {
ulong_t cval;
@@ -762,7 +784,7 @@ struct hash_entry {
int tok;
struct macro *sym_define;
struct symbol *sym_label;
- struct symbol *sym_struct;
+ struct symbol *sym_tag;
struct symbol *sym_ident;
};
@@ -777,16 +799,20 @@ struct compile_state {
const char *function;
struct token token[4];
struct hash_entry *hash_table[HASH_TABLE_SIZE];
+ struct hash_entry *i_switch;
+ struct hash_entry *i_case;
struct hash_entry *i_continue;
struct hash_entry *i_break;
+ struct hash_entry *i_default;
int scope_depth;
int if_depth, if_value;
int macro_line;
struct file_state *macro_file;
struct triple *main_function;
+ struct triple *first;
struct block *first_block, *last_block;
int last_vertex;
- int cpu;
+ unsigned long features;
int debug;
int optimize;
};
@@ -817,12 +843,12 @@ struct compile_state {
#define TYPE_SHIFT 8
#define TYPE_MASK 0x1f00
-#define TYPE_INTEGER(TYPE) (((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG))
-#define TYPE_ARITHMETIC(TYPE) (((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE))
+#define TYPE_INTEGER(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_ULLONG)) || ((TYPE) == TYPE_ENUM))
+#define TYPE_ARITHMETIC(TYPE) ((((TYPE) >= TYPE_CHAR) && ((TYPE) <= TYPE_LDOUBLE)) || ((TYPE) == TYPE_ENUM))
#define TYPE_UNSIGNED(TYPE) ((TYPE) & 0x0100)
#define TYPE_SIGNED(TYPE) (!TYPE_UNSIGNED(TYPE))
-#define TYPE_MKUNSIGNED(TYPE) ((TYPE) | 0x0100)
-#define TYPE_RANK(TYPE) ((TYPE) & ~0x0100)
+#define TYPE_MKUNSIGNED(TYPE) (((TYPE) & ~0xF000) | 0x0100)
+#define TYPE_RANK(TYPE) ((TYPE) & ~0xF1FF)
#define TYPE_PTR(TYPE) (((TYPE) & TYPE_MASK) == TYPE_POINTER)
#define TYPE_DEFAULT 0x0000
#define TYPE_VOID 0x0100
@@ -839,8 +865,17 @@ struct compile_state {
#define TYPE_FLOAT 0x0c00
#define TYPE_DOUBLE 0x0d00
#define TYPE_LDOUBLE 0x0e00 /* long double */
+
+/* Note: TYPE_ENUM is chosen very carefully so TYPE_RANK works */
+#define TYPE_ENUM 0x1600
+#define TYPE_LIST 0x1700
+/* TYPE_LIST is a basic building block when defining enumerations
+ * type->field_ident holds the name of this enumeration entry.
+ * type->right holds the entry in the list.
+ */
+
#define TYPE_STRUCT 0x1000
-#define TYPE_ENUM 0x1100
+#define TYPE_UNION 0x1100
#define TYPE_POINTER 0x1200
/* For TYPE_POINTER:
* type->left holds the type pointed to.
@@ -860,17 +895,13 @@ struct compile_state {
* type->left and type->right holds to types that overlap
* each other in memory.
*/
-#define TYPE_ARRAY 0x1600
+#define TYPE_ARRAY 0x1800
/* TYPE_ARRAY is a basic building block when definitng arrays.
* type->left holds the type we are an array of.
* type-> holds the number of elements.
*/
-#ifdef __x86_64__
-#define ELEMENT_COUNT_UNSPECIFIED (~0U)
-#else
-#define ELEMENT_COUNT_UNSPECIFIED (~0UL)
-#endif
+#define ELEMENT_COUNT_UNSPECIFIED ULONG_T_MAX
struct type {
unsigned int type;
@@ -880,13 +911,13 @@ struct type {
struct hash_entry *type_ident;
};
-#define MAX_REGISTERS 75
-#define MAX_REG_EQUIVS 16
-#define REGISTER_BITS 16
-#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
#define TEMPLATE_BITS 7
#define MAX_TEMPLATES (1<<TEMPLATE_BITS)
+#define MAX_REG_EQUIVS 16
#define MAX_REGC 14
+#define MAX_REGISTERS 75
+#define REGISTER_BITS 7
+#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
#define REG_UNSET 0
#define REG_UNNEEDED 1
#define REG_VIRT0 (MAX_REGISTERS + 0)
@@ -895,10 +926,17 @@ struct type {
#define REG_VIRT3 (MAX_REGISTERS + 3)
#define REG_VIRT4 (MAX_REGISTERS + 4)
#define REG_VIRT5 (MAX_REGISTERS + 5)
-#define REG_VIRT6 (MAX_REGISTERS + 5)
-#define REG_VIRT7 (MAX_REGISTERS + 5)
-#define REG_VIRT8 (MAX_REGISTERS + 5)
-#define REG_VIRT9 (MAX_REGISTERS + 5)
+#define REG_VIRT6 (MAX_REGISTERS + 6)
+#define REG_VIRT7 (MAX_REGISTERS + 7)
+#define REG_VIRT8 (MAX_REGISTERS + 8)
+#define REG_VIRT9 (MAX_REGISTERS + 9)
+
+#if (MAX_REGISTERS + 9) > MAX_VIRT_REGISTERS
+#error "MAX_VIRT_REGISTERS to small"
+#endif
+#if (MAX_REGC + REGISTER_BITS) > 27
+#error "Too many id bits used"
+#endif
/* Provision for 8 register classes */
#define REG_SHIFT 0
@@ -999,7 +1037,7 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
state->file->report_name, state->file->report_line, col);
}
-static void __internal_error(struct compile_state *state, struct triple *ptr,
+static void romcc_internal_error(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
@@ -1017,7 +1055,7 @@ static void __internal_error(struct compile_state *state, struct triple *ptr,
}
-static void __internal_warning(struct compile_state *state, struct triple *ptr,
+static void romcc_internal_warning(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
@@ -1034,12 +1072,15 @@ static void __internal_warning(struct compile_state *state, struct triple *ptr,
-static void __error(struct compile_state *state, struct triple *ptr,
+static void romcc_error(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
va_start(args, fmt);
loc(stderr, state, ptr);
+ if (ptr && (state->debug & DEBUG_ABORT_ON_ERROR)) {
+ fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
+ }
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
@@ -1050,7 +1091,7 @@ static void __error(struct compile_state *state, struct triple *ptr,
exit(1);
}
-static void __warning(struct compile_state *state, struct triple *ptr,
+static void romcc_warning(struct compile_state *state, struct triple *ptr,
char *fmt, ...)
{
va_list args;
@@ -1063,15 +1104,15 @@ static void __warning(struct compile_state *state, struct triple *ptr,
}
#if DEBUG_ERROR_MESSAGES
-# define internal_error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__internal_error
-# define internal_warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__internal_warning
-# define error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__error
-# define warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),__warning
+# define internal_error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_internal_error
+# define internal_warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_internal_warning
+# define error fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_error
+# define warning fprintf(stderr, "@ %s.%s:%d \t", __FILE__, __func__, __LINE__),romcc_warning
#else
-# define internal_error __internal_error
-# define internal_warning __internal_warning
-# define error __error
-# define warning __warning
+# define internal_error romcc_internal_error
+# define internal_warning romcc_internal_warning
+# define error romcc_error
+# define warning romcc_warning
#endif
#define FINISHME() warning(state, 0, "FINISHME @ %s.%s:%d", __FILE__, __func__, __LINE__)
@@ -1236,7 +1277,9 @@ static struct occurance *new_occurance(struct compile_state *state)
(last->col == col) &&
(last->line == line) &&
(last->function == function) &&
- (strcmp(last->filename, filename) == 0)) {
+ ((last->filename == filename) ||
+ (strcmp(last->filename, filename) == 0)))
+ {
get_occurance(last);
return last;
}
@@ -1501,7 +1544,10 @@ static struct block *block_of_triple(struct compile_state *state,
struct triple *ins)
{
struct triple *first;
- first = RHS(state->main_function, 0);
+ if (!ins) {
+ return 0;
+ }
+ first = state->first;
while(ins != first && !triple_stores_block(state, ins)) {
if (ins == ins->prev) {
internal_error(state, 0, "ins == ins->prev?");
@@ -1591,12 +1637,12 @@ static void display_triple(FILE *fp, struct triple *ins)
if (ins->op == OP_INTCONST) {
fprintf(fp, "(%p) %c%c %-7s %-2d %-10s <0x%08lx> ",
ins, pre, post, reg, ins->template_id, tops(ins->op),
- ins->u.cval);
+ (unsigned long)(ins->u.cval));
}
else if (ins->op == OP_ADDRCONST) {
fprintf(fp, "(%p) %c%c %-7s %-2d %-10s %-10p <0x%08lx>",
ins, pre, post, reg, ins->template_id, tops(ins->op),
- MISC(ins, 0), ins->u.cval);
+ MISC(ins, 0), (unsigned long)(ins->u.cval));
}
else {
int i, count;
@@ -1630,7 +1676,17 @@ static void display_triple(FILE *fp, struct triple *ins)
fflush(fp);
}
-static int triple_is_pure(struct compile_state *state, struct triple *ins)
+static void display_func(FILE *fp, struct triple *func)
+{
+ struct triple *first, *ins;
+ first = ins = RHS(func, 0);
+ do {
+ display_triple(fp, ins);
+ ins = ins->next;
+ } while(ins != first);
+}
+
+static int triple_is_pure(struct compile_state *state, struct triple *ins, unsigned id)
{
/* Does the triple have no side effects.
* I.e. Rexecuting the triple with the same arguments
@@ -1643,7 +1699,7 @@ static int triple_is_pure(struct compile_state *state, struct triple *ins)
internal_error(state, 0, "Purity of %s not known\n",
tops(ins->op));
}
- return pure == PURE;
+ return (pure == PURE) && !(id & TRIPLE_FLAG_VOLATILE);
}
static int triple_is_branch(struct compile_state *state, struct triple *ins)
@@ -1685,6 +1741,14 @@ static int triple_is_def(struct compile_state *state, struct triple *ins)
return is_def;
}
+static int triple_is_structural(struct compile_state *state, struct triple *ins)
+{
+ int is_structural;
+ valid_ins(state, ins);
+ is_structural = (table_ops[ins->op].flags & STRUCTURAL) == STRUCTURAL;
+ return is_structural;
+}
+
static struct triple **triple_iter(struct compile_state *state,
size_t count, struct triple **vector,
struct triple *ins, struct triple **last)
@@ -1807,11 +1871,16 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
struct block *block;
/* Make certain the we are not the first or last element of a block */
block = block_of_triple(state, ptr);
- if (block && (block->last == ptr)) {
- block->last = ptr->prev;
- }
- if (block && (block->first == ptr)) {
- block->first = ptr->next;
+ if (block) {
+ if ((block->last == ptr) && (block->first == ptr)) {
+ block->last = block->first = 0;
+ }
+ else if (block->last == ptr) {
+ block->last = ptr->prev;
+ }
+ else if (block->first == ptr) {
+ block->first = ptr->next;
+ }
}
/* Remove ptr from use chains where it is the user */
expr = triple_rhs(state, ptr, 0);
@@ -2240,9 +2309,9 @@ static void end_scope(struct compile_state *state)
struct hash_entry *entry;
entry = state->hash_table[i];
while(entry) {
- end_scope_syms(&entry->sym_label, depth);
- end_scope_syms(&entry->sym_struct, depth);
- end_scope_syms(&entry->sym_ident, depth);
+ end_scope_syms(&entry->sym_label, depth);
+ end_scope_syms(&entry->sym_tag, depth);
+ end_scope_syms(&entry->sym_ident, depth);
entry = entry->next;
}
}
@@ -2957,19 +3026,17 @@ static long_t mprimary_expr(struct compile_state *state, int index)
break;
case TOK_LIT_INT:
{
+ long lval;
char *end;
meat(state, index, TOK_LIT_INT);
errno = 0;
- val = strtol(state->token[index].val.str, &end, 0);
-#ifdef __x86_64__
- if (((val == INT_MIN) || (val == INT_MAX)) &&
- (errno == ERANGE)) {
-#else
- if (((val == LONG_MIN) || (val == LONG_MAX)) &&
- (errno == ERANGE)) {
-#endif
+ lval = strtol(state->token[index].val.str, &end, 0);
+ if ((lval > LONG_T_MAX) || (lval < LONG_T_MIN) ||
+ (((lval == LONG_MIN) || (lval == LONG_MAX)) &&
+ (errno == ERANGE))) {
error(state, 0, "Integer constant to large");
}
+ val = lval;
break;
}
default:
@@ -3779,6 +3846,12 @@ static struct type uint_type = { .type = TYPE_UINT };
static struct type long_type = { .type = TYPE_LONG };
static struct type ulong_type = { .type = TYPE_ULONG };
+static struct type void_func = {
+ .type = TYPE_FUNCTION,
+ .left = &void_type,
+ .right = &void_type,
+};
+
static struct triple *variable(struct compile_state *state, struct type *type)
{
struct triple *result;
@@ -3913,7 +3986,7 @@ static void name_of(FILE *fp, struct type *type)
}
case TYPE_ARRAY:
name_of(fp, type->left);
- fprintf(fp, " [%ld]", type->elements);
+ fprintf(fp, " [%ld]", (long)(type->elements));
break;
default:
fprintf(fp, "????: %x", type->type & TYPE_MASK);
@@ -4174,8 +4247,8 @@ static void arrays_complete(struct compile_state *state, struct type *type)
static unsigned int do_integral_promotion(unsigned int type)
{
type &= TYPE_MASK;
- if (TYPE_INTEGER(type) &&
- TYPE_RANK(type) < TYPE_RANK(TYPE_INT)) {
+ if (type == TYPE_ENUM) type = TYPE_INT;
+ if (TYPE_INTEGER(type) && (TYPE_RANK(type) < TYPE_RANK(TYPE_INT))) {
type = TYPE_INT;
}
return type;
@@ -4186,6 +4259,9 @@ static unsigned int do_arithmetic_conversion(
{
left &= TYPE_MASK;
right &= TYPE_MASK;
+ /* Convert enums to ints */
+ if (left == TYPE_ENUM) left = TYPE_INT;
+ if (right == TYPE_ENUM) right = TYPE_INT;
if ((left == TYPE_LDOUBLE) || (right == TYPE_LDOUBLE)) {
return TYPE_LDOUBLE;
}
@@ -4522,6 +4598,8 @@ static struct triple *int_const(
}
+static struct triple *read_expr(struct compile_state *state, struct triple *def);
+
static struct triple *do_mk_addr_expr(struct compile_state *state,
struct triple *expr, struct type *type, ulong_t offset)
{
@@ -4544,6 +4622,9 @@ static struct triple *do_mk_addr_expr(struct compile_state *state,
RHS(expr, 0),
int_const(state, &ulong_type, offset));
}
+ if (!result) {
+ internal_error(state, expr, "cannot take address of expression");
+ }
return result;
}
@@ -4633,6 +4714,10 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def)
if (is_in_reg(state, def)) {
op = OP_READ;
} else {
+ if (def->op == OP_SDECL) {
+ def = mk_addr_expr(state, def, 0);
+ def = mk_deref_expr(state, def);
+ }
op = OP_LOAD;
}
return triple(state, op, def->type, def, 0);
@@ -5040,6 +5125,19 @@ static struct triple *flatten_cond(
return read_expr(state, val);
}
+static int local_triple(struct compile_state *state,
+ struct triple *func, struct triple *ins)
+{
+ int local = (ins->id & TRIPLE_FLAG_LOCAL);
+#if 0
+ if (!local) {
+ fprintf(stderr, "global: ");
+ display_triple(stderr, ins);
+ }
+#endif
+ return local;
+}
+
struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
struct occurance *base_occurance)
{
@@ -5051,7 +5149,7 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
fprintf(stdout, "\n");
loc(stdout, state, 0);
fprintf(stdout, "\n__________ copy_func _________\n");
- print_triple(state, ofunc);
+ display_func(stdout, ofunc);
fprintf(stdout, "__________ copy_func _________ done\n\n");
#endif
@@ -5086,6 +5184,8 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
if (old == MISC(ofunc, 0)) {
MISC(nfunc, 0) = new;
}
+ /* Remember which instructions are local */
+ old->id |= TRIPLE_FLAG_LOCAL;
old = old->next;
} while(old != ofirst);
@@ -5100,8 +5200,13 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
for(i = 0; i < count; i++) {
oexpr = &old->param[i];
nexpr = &new->param[i];
- if (!*nexpr && *oexpr && (*oexpr)->use) {
- *nexpr = (*oexpr)->use->member;
+ if (*oexpr && !*nexpr) {
+ if (!local_triple(state, ofunc, *oexpr)) {
+ *nexpr = *oexpr;
+ }
+ else if ((*oexpr)->use) {
+ *nexpr = (*oexpr)->use->member;
+ }
if (*nexpr == old) {
internal_error(state, 0, "new == old?");
}
@@ -5120,6 +5225,8 @@ struct triple *copy_func(struct compile_state *state, struct triple *ofunc,
new = nfirst;
do {
unuse_triple(old, new);
+ /* Forget which instructions are local */
+ old->id &= ~TRIPLE_FLAG_LOCAL;
old = old->next;
new = new->next;
} while ((old != ofirst) && (new != nfirst));
@@ -5169,7 +5276,7 @@ static struct triple *flatten_call(
fprintf(stdout, "\n");
loc(stdout, state, 0);
fprintf(stdout, "\n__________ flatten_call _________\n");
- print_triple(state, nfunc);
+ display_func(stdout, nfunc);
fprintf(stdout, "__________ flatten_call _________ done\n\n");
#endif
@@ -5238,8 +5345,9 @@ static struct triple *flatten(
}
break;
case OP_BLOBCONST:
- insert_triple(state, first, ptr);
+ insert_triple(state, state->first, ptr);
ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
ptr = triple(state, OP_SDECL, ptr->type, ptr, 0);
use_triple(MISC(ptr, 0), ptr);
break;
@@ -5275,10 +5383,17 @@ static struct triple *flatten(
use_triple(ptr, MISC(ptr, 0));
break;
case OP_ADDRCONST:
- case OP_SDECL:
MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
use_triple(MISC(ptr, 0), ptr);
break;
+ case OP_SDECL:
+ first = state->first;
+ MISC(ptr, 0) = flatten(state, first, MISC(ptr, 0));
+ use_triple(MISC(ptr, 0), ptr);
+ insert_triple(state, first, ptr);
+ ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
+ return ptr;
case OP_ADECL:
break;
default:
@@ -5290,6 +5405,7 @@ static struct triple *flatten(
if (ptr) {
insert_triple(state, first, ptr);
ptr->id |= TRIPLE_FLAG_FLATTENED;
+ ptr->id &= ~TRIPLE_FLAG_LOCAL;
}
return ptr;
}
@@ -5489,6 +5605,11 @@ static int is_const(struct triple *ins)
return IS_CONST_OP(ins->op);
}
+static int is_simple_const(struct triple *ins)
+{
+ return IS_CONST_OP(ins->op) && (ins->op != OP_ADDRCONST);
+}
+
static int constants_equal(struct compile_state *state,
struct triple *left, struct triple *right)
{
@@ -5638,6 +5759,9 @@ static ulong_t read_const(struct compile_state *state,
internal_error(state, rhs, "bad type to read_const\n");
break;
}
+ if (!is_simple_const(rhs)) {
+ internal_error(state, rhs, "bad op to read_const\n");
+ }
return rhs->u.cval;
}
@@ -5702,9 +5826,12 @@ static void wipe_ins(struct compile_state *state, struct triple *ins)
static void mkcopy(struct compile_state *state,
struct triple *ins, struct triple *rhs)
{
+ struct block *block;
+ block = block_of_triple(state, ins);
wipe_ins(state, ins);
ins->op = OP_COPY;
ins->sizes = TRIPLE_SIZES(0, 1, 0, 0);
+ ins->u.block = block;
RHS(ins, 0) = rhs;
use_triple(RHS(ins, 0), ins);
}
@@ -5739,7 +5866,7 @@ static void mkaddr_const(struct compile_state *state,
static void flatten_structures(struct compile_state *state)
{
struct triple *ins, *first;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
/* Pass one expand structure values into valvecs.
*/
@@ -6004,6 +6131,7 @@ static void simplify_smod(struct compile_state *state, struct triple *ins)
RHS(ins, 1) = val;
}
}
+
static void simplify_umod(struct compile_state *state, struct triple *ins)
{
if (is_const(RHS(ins, 0)) && is_const(RHS(ins, 1))) {
@@ -6354,7 +6482,8 @@ static void simplify_lfalse(struct compile_state *state, struct triple *ins)
mkconst(state, ins, left == 0);
}
/* Otherwise if I am the only user... */
- else if ((RHS(ins, 0)->use->member == ins) && (RHS(ins, 0)->use->next == 0)) {
+ else if ((RHS(ins, 0)->use) &&
+ (RHS(ins, 0)->use->member == ins) && (RHS(ins, 0)->use->next == 0)) {
int need_copy = 1;
/* Invert a boolean operation */
switch(RHS(ins, 0)->op) {
@@ -6423,22 +6552,88 @@ static void simplify_copy(struct compile_state *state, struct triple *ins)
}
}
+static int phi_present(struct block *block)
+{
+ struct triple *ptr;
+ if (!block) {
+ return 0;
+ }
+ ptr = block->first;
+ do {
+ if (ptr->op == OP_PHI) {
+ return 1;
+ }
+ ptr = ptr->next;
+ } while(ptr != block->last);
+ return 0;
+}
+
+static int phi_dependency(struct block *block)
+{
+ /* A block has a phi dependency if a phi function
+ * depends on that block to exist, and makes a block
+ * that is otherwise useless unsafe to remove.
+ */
+ if (block && (
+ phi_present(block->left) ||
+ phi_present(block->right))) {
+ return 1;
+ }
+ return 0;
+}
+
+static struct triple *branch_target(struct compile_state *state, struct triple *ins)
+{
+ struct triple *targ;
+ targ = TARG(ins, 0);
+ /* During scc_transform temporary triples are allocated that
+ * loop back onto themselves. If I see one don't advance the
+ * target.
+ */
+ while(triple_is_structural(state, targ) && (targ->next != targ)) {
+ targ = targ->next;
+ }
+ return targ;
+}
+
+
static void simplify_branch(struct compile_state *state, struct triple *ins)
{
- struct block *block;
+ int simplified;
if (ins->op != OP_BRANCH) {
internal_error(state, ins, "not branch");
}
if (ins->use != 0) {
internal_error(state, ins, "branch use");
}
-#warning "FIXME implement simplify branch."
/* The challenge here with simplify branch is that I need to
* make modifications to the control flow graph as well
- * as to the branch instruction itself.
+ * as to the branch instruction itself. That is handled
+ * by rebuilding the basic blocks after simplify all is called.
+ */
+
+ /* If we have a branch to an unconditional branch update
+ * our target. But watch out for dependencies from phi
+ * functions.
+ */
+ do {
+ struct triple *targ;
+ simplified = 0;
+ targ = branch_target(state, ins);
+ if ((targ != ins) && triple_is_uncond_branch(state, targ)) {
+ if (!phi_dependency(targ->u.block))
+ {
+ unuse_triple(TARG(ins, 0), ins);
+ TARG(ins, 0) = TARG(targ, 0);
+ use_triple(TARG(ins, 0), ins);
+ simplified = 1;
+ }
+ }
+ } while(simplified);
+
+ /* If we have a conditional branch with a constant condition
+ * make it an unconditional branch.
*/
- block = ins->u.block;
-
if (TRIPLE_RHS(ins->sizes) && is_const(RHS(ins, 0))) {
struct triple *targ;
ulong_t value;
@@ -6454,8 +6649,11 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
unuse_triple(targ, ins);
TARG(ins, 0) = ins->next;
}
-#warning "FIXME handle the case of making a branch unconditional"
}
+
+ /* If we have an unconditional branch to the next instruction
+ * make it a noop.
+ */
if (TARG(ins, 0) == ins->next) {
unuse_triple(ins->next, ins);
if (TRIPLE_RHS(ins->sizes)) {
@@ -6467,50 +6665,26 @@ static void simplify_branch(struct compile_state *state, struct triple *ins)
if (ins->use) {
internal_error(state, ins, "noop use != 0");
}
-#warning "FIXME handle the case of killing a branch"
}
}
-int phi_present(struct block *block)
-{
- struct triple *ptr;
- if (!block) {
- return 0;
- }
- ptr = block->first;
- do {
- if (ptr->op == OP_PHI) {
- return 1;
- }
- ptr = ptr->next;
- } while(ptr != block->last);
- return 0;
-}
-
static void simplify_label(struct compile_state *state, struct triple *ins)
{
-#warning "FIXME enable simplify_label"
- struct triple *first, *last;
- first = RHS(state->main_function, 0);
- last = first->prev;
- /* Ignore the first and last instructions */
- if ((ins == first) || (ins == last)) {
+ struct triple *first;
+ first = state->first;
+ /* Ignore volatile labels */
+ if (!triple_is_pure(state, ins, ins->id)) {
return;
}
if (ins->use == 0) {
ins->op = OP_NOOP;
}
else if (ins->prev->op == OP_LABEL) {
- struct block *block;
- block = ins->prev->u.block;
/* In general it is not safe to merge one label that
* imediately follows another. The problem is that the empty
* looking block may have phi functions that depend on it.
*/
- if (!block ||
- (!phi_present(block->left) &&
- !phi_present(block->right)))
- {
+ if (!phi_dependency(ins->prev->u.block)) {
struct triple_set *user, *next;
ins->op = OP_NOOP;
for(user = ins->use; user; user = next) {
@@ -6532,22 +6706,43 @@ static void simplify_label(struct compile_state *state, struct triple *ins)
static void simplify_phi(struct compile_state *state, struct triple *ins)
{
- struct triple **expr;
- ulong_t value;
- expr = triple_rhs(state, ins, 0);
- if (!*expr || !is_const(*expr)) {
+ struct triple **slot;
+ struct triple *value;
+ int zrhs, i;
+ ulong_t cvalue;
+ slot = &RHS(ins, 0);
+ zrhs = TRIPLE_RHS(ins->sizes);
+ if (zrhs == 0) {
return;
}
- value = read_const(state, ins, expr);
- for(;expr;expr = triple_rhs(state, ins, expr)) {
- if (!*expr || !is_const(*expr)) {
- return;
+ /* See if all of the rhs members of a phi have the same value */
+ if (slot[0] && is_simple_const(slot[0])) {
+ cvalue = read_const(state, ins, &slot[0]);
+ for(i = 1; i < zrhs; i++) {
+ if ( !slot[i] ||
+ !is_simple_const(slot[i]) ||
+ (cvalue != read_const(state, ins, &slot[i]))) {
+ break;
+ }
}
- if (value != read_const(state, ins, expr)) {
+ if (i == zrhs) {
+ mkconst(state, ins, cvalue);
return;
}
}
- mkconst(state, ins, value);
+
+ /* See if all of rhs members of a phi are the same */
+ value = slot[0];
+ for(i = 1; i < zrhs; i++) {
+ if (slot[i] != value) {
+ break;
+ }
+ }
+ if (i == zrhs) {
+ /* If the phi has a single value just copy it */
+ mkcopy(state, ins, value);
+ return;
+ }
}
@@ -6634,7 +6829,7 @@ static const simplify_t table_simplify[] = {
#if 0
#define simplify_branch simplify_noop
#endif
-#if 1
+#if 0
#define simplify_label simplify_noop
#endif
@@ -6647,6 +6842,10 @@ static const simplify_t table_simplify[] = {
#define simplify_bsr simplify_noop
#endif
+#if 1
+#define simplify_piece simplify_noop
+#endif
+
[OP_SDIVT ] = simplify_sdivt,
[OP_UDIVT ] = simplify_udivt,
[OP_SMUL ] = simplify_smul,
@@ -6692,7 +6891,7 @@ static const simplify_t table_simplify[] = {
[OP_WRITE ] = simplify_noop,
[OP_READ ] = simplify_noop,
[OP_COPY ] = simplify_copy,
-[OP_PIECE ] = simplify_noop,
+[OP_PIECE ] = simplify_piece,
[OP_ASM ] = simplify_noop,
[OP_DOT ] = simplify_noop,
@@ -6736,14 +6935,66 @@ static void simplify(struct compile_state *state, struct triple *ins)
op, tops(op));
return;
}
+#if !DEBUG_SIMPLIFY
do_simplify(state, ins);
+#else
+ {
+ struct triple *dup;
+ int ins_count, dup_count;
+ dup = dup_triple(state, ins);
+ do_simplify(state, ins);
+ ins_count = TRIPLE_SIZE(ins->sizes);
+ dup_count = TRIPLE_SIZE(dup->sizes);
+ if ((dup->op != ins->op) ||
+ (ins_count != dup_count) ||
+ (memcmp(dup->param, ins->param,
+ dup_count * sizeof(dup->param[0])) != 0) ||
+ (memcmp(&dup->u, &ins->u, sizeof(ins->u)) != 0))
+ {
+ int i, min_count;
+ fprintf(stderr, "simplify: %11p", ins);
+ if (dup->op == ins->op) {
+ fprintf(stderr, " %-11s", tops(ins->op));
+ } else {
+ fprintf(stderr, " [%-10s %-10s]",
+ tops(dup->op), tops(ins->op));
+ }
+ min_count = dup_count;
+ if (min_count > ins_count) {
+ min_count = ins_count;
+ }
+ for(i = 0; i < min_count; i++) {
+ if (dup->param[i] == ins->param[i]) {
+ fprintf(stderr, " %-11p", ins->param[i]);
+ } else {
+ fprintf(stderr, " [%-10p %-10p]",
+ dup->param[i], ins->param[i]);
+ }
+ }
+ for(; i < ins_count; i++) {
+ fprintf(stderr, " [%-9p]", ins->param[i]);
+ }
+ for(; i < dup_count; i++) {
+ fprintf(stderr, " [%-9p]", dup->param[i]);
+ }
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ xfree(dup);
+ }
+#endif
} while(ins->op != op);
}
static void simplify_all(struct compile_state *state)
{
struct triple *ins, *first;
- first = RHS(state->main_function, 0);
+ first = state->first;
+ ins = first->prev;
+ do {
+ simplify(state, ins);
+ ins = ins->prev;
+ } while(ins != first->prev);
ins = first;
do {
simplify(state, ins);
@@ -6913,7 +7164,7 @@ static struct type *register_builtin_type(struct compile_state *state,
field = field->right;
}
elements++;
- symbol(state, ident, &ident->sym_struct, 0, type);
+ symbol(state, ident, &ident->sym_tag, 0, type);
type->type_ident = ident;
type->elements = elements;
}
@@ -7115,11 +7366,7 @@ static struct triple *integer_constant(struct compile_state *state)
errno = 0;
decimal = (tk->val.str[0] != '0');
val = strtoul(tk->val.str, &end, 0);
-#ifdef __x86_64__
- if ((val == UINT_MAX) && (errno == ERANGE)) {
-#else
- if ((val == ULONG_MAX) && (errno == ERANGE)) {
-#endif
+ if ((val > ULONG_T_MAX) || ((val == ULONG_MAX) && (errno == ERANGE))) {
error(state, 0, "Integer constant to large");
}
u = l = 0;
@@ -7143,33 +7390,25 @@ static struct triple *integer_constant(struct compile_state *state)
}
else if (l) {
type = &long_type;
-#ifdef __x86_64__
- if (!decimal && (val > INT_MAX)) {
-#else
- if (!decimal && (val > LONG_MAX)) {
-#endif
+ if (!decimal && (val > LONG_T_MAX)) {
type = &ulong_type;
}
}
else if (u) {
type = &uint_type;
- if (val > UINT_MAX) {
+ if (val > UINT_T_MAX) {
type = &ulong_type;
}
}
else {
type = &int_type;
- if (!decimal && (val > INT_MAX) && (val <= UINT_MAX)) {
+ if (!decimal && (val > INT_T_MAX) && (val <= UINT_T_MAX)) {
type = &uint_type;
}
-#ifdef __x86_64__
- else if (!decimal && (val > INT_MAX)) {
-#else
- else if (!decimal && (val > LONG_MAX)) {
-#endif
+ else if (!decimal && (val > LONG_T_MAX)) {
type = &ulong_type;
}
- else if (val > INT_MAX) {
+ else if (val > INT_T_MAX) {
type = &long_type;
}
}
@@ -7189,7 +7428,6 @@ static struct triple *primary_expr(struct compile_state *state)
/* Here ident is either:
* a varable name
* a function name
- * an enumeration constant.
*/
eat(state, TOK_IDENT);
ident = state->token[0].ident;
@@ -7200,11 +7438,17 @@ static struct triple *primary_expr(struct compile_state *state)
break;
}
case TOK_ENUM_CONST:
+ {
+ struct hash_entry *ident;
/* Here ident is an enumeration constant */
eat(state, TOK_ENUM_CONST);
- def = 0;
- FINISHME();
+ ident = state->token[0].ident;
+ if (!ident->sym_ident) {
+ error(state, 0, "%s undeclared", ident->name);
+ }
+ def = ident->sym_ident->def;
break;
+ }
case TOK_LPAREN:
eat(state, TOK_LPAREN);
def = expr(state);
@@ -8106,35 +8350,113 @@ static void labeled_statement(struct compile_state *state, struct triple *first)
static void switch_statement(struct compile_state *state, struct triple *first)
{
- FINISHME();
+ struct triple *value, *top, *end, *dbranch;
+ struct hash_entry *ident;
+
+ /* See if we have a valid switch statement */
eat(state, TOK_SWITCH);
eat(state, TOK_LPAREN);
- expr(state);
+ value = expr(state);
+ integral(state, value);
+ value = read_expr(state, value);
eat(state, TOK_RPAREN);
+ /* Generate the needed pieces */
+ top = label(state);
+ end = label(state);
+ dbranch = branch(state, end, 0);
+ /* Remember where case branches and break goes */
+ start_scope(state);
+ ident = state->i_switch;
+ symbol(state, ident, &ident->sym_ident, value, value->type);
+ ident = state->i_case;
+ symbol(state, ident, &ident->sym_ident, top, top->type);
+ ident = state->i_break;
+ symbol(state, ident, &ident->sym_ident, end, end->type);
+ ident = state->i_default;
+ symbol(state, ident, &ident->sym_ident, dbranch, dbranch->type);
+ /* Thread them together */
+ flatten(state, first, value);
+ flatten(state, first, top);
+ flatten(state, first, dbranch);
statement(state, first);
- error(state, 0, "switch statements are not implemented");
- FINISHME();
+ flatten(state, first, end);
+ /* Cleanup the switch scope */
+ end_scope(state);
}
static void case_statement(struct compile_state *state, struct triple *first)
{
- FINISHME();
+ struct triple *cvalue, *dest, *test, *jmp;
+ struct triple *ptr, *value, *top, *dbranch;
+
+ /* See if w have a valid case statement */
eat(state, TOK_CASE);
- constant_expr(state);
+ cvalue = constant_expr(state);
+ integral(state, cvalue);
+ if (cvalue->op != OP_INTCONST) {
+ error(state, 0, "integer constant expected");
+ }
eat(state, TOK_COLON);
+ if (!state->i_case->sym_ident) {
+ error(state, 0, "case statement not within a switch");
+ }
+
+ /* Lookup the interesting pieces */
+ top = state->i_case->sym_ident->def;
+ value = state->i_switch->sym_ident->def;
+ dbranch = state->i_default->sym_ident->def;
+
+ /* See if this case label has already been used */
+ for(ptr = top; ptr != dbranch; ptr = ptr->next) {
+ if (ptr->op != OP_EQ) {
+ continue;
+ }
+ if (RHS(ptr, 1)->u.cval == cvalue->u.cval) {
+ error(state, 0, "duplicate case %d statement",
+ cvalue->u.cval);
+ }
+ }
+ /* Generate the needed pieces */
+ dest = label(state);
+ test = triple(state, OP_EQ, &int_type, value, cvalue);
+ jmp = branch(state, dest, test);
+ /* Thread the pieces together */
+ flatten(state, dbranch, test);
+ flatten(state, dbranch, jmp);
+ flatten(state, dbranch, label(state));
+ flatten(state, first, dest);
statement(state, first);
- error(state, 0, "case statements are not implemented");
- FINISHME();
}
static void default_statement(struct compile_state *state, struct triple *first)
{
- FINISHME();
+ struct triple *dest;
+ struct triple *dbranch, *end;
+
+ /* See if we have a valid default statement */
eat(state, TOK_DEFAULT);
eat(state, TOK_COLON);
+
+ if (!state->i_case->sym_ident) {
+ error(state, 0, "default statement not within a switch");
+ }
+
+ /* Lookup the interesting pieces */
+ dbranch = state->i_default->sym_ident->def;
+ end = state->i_break->sym_ident->def;
+
+ /* See if a default statement has already happened */
+ if (TARG(dbranch, 0) != end) {
+ error(state, 0, "duplicate default statement");
+ }
+
+ /* Generate the needed pieces */
+ dest = label(state);
+
+ /* Thread the pieces together */
+ TARG(dbranch, 0) = dest;
+ flatten(state, first, dest);
statement(state, first);
- error(state, 0, "default statements are not implemented");
- FINISHME();
}
static void asm_statement(struct compile_state *state, struct triple *first)
@@ -8577,33 +8899,71 @@ static struct type *typedef_name(
}
static struct type *enum_specifier(
- struct compile_state *state, unsigned int specifiers)
+ struct compile_state *state, unsigned int spec)
{
+ struct hash_entry *ident;
+ ulong_t base;
int tok;
- struct type *type;
- type = 0;
- FINISHME();
+ struct type *enum_type;
+ enum_type = 0;
+ ident = 0;
eat(state, TOK_ENUM);
tok = peek(state);
- if (tok == TOK_IDENT) {
- eat(state, TOK_IDENT);
+ if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) {
+ eat(state, tok);
+ ident = state->token[0].ident;
+
}
- if ((tok != TOK_IDENT) || (peek(state) == TOK_LBRACE)) {
+ base = 0;
+ if (!ident || (peek(state) == TOK_LBRACE)) {
+ struct type **next;
eat(state, TOK_LBRACE);
+ enum_type = new_type(TYPE_ENUM | spec, 0, 0);
+ enum_type->type_ident = ident;
+ next = &enum_type->right;
do {
+ struct hash_entry *eident;
+ struct triple *value;
+ struct type *entry;
eat(state, TOK_IDENT);
+ eident = state->token[0].ident;
+ if (eident->sym_ident) {
+ error(state, 0, "%s already declared",
+ eident->name);
+ }
+ eident->tok = TOK_ENUM_CONST;
if (peek(state) == TOK_EQ) {
+ struct triple *val;
eat(state, TOK_EQ);
- constant_expr(state);
- }
+ val = constant_expr(state);
+ integral(state, val);
+ base = val->u.cval;
+ }
+ value = int_const(state, &int_type, base);
+ symbol(state, eident, &eident->sym_ident, value, &int_type);
+ entry = new_type(TYPE_LIST, 0, 0);
+ entry->field_ident = eident;
+ *next = entry;
+ next = &entry->right;
+ base += 1;
if (peek(state) == TOK_COMMA) {
eat(state, TOK_COMMA);
}
} while(peek(state) != TOK_RBRACE);
eat(state, TOK_RBRACE);
+ if (ident) {
+ symbol(state, ident, &ident->sym_tag, 0, enum_type);
+ }
}
- FINISHME();
- return type;
+ if (ident && ident->sym_tag &&
+ ident->sym_tag->type &&
+ ((ident->sym_tag->type->type & TYPE_MASK) == TYPE_ENUM)) {
+ enum_type = clone_type(spec, ident->sym_tag->type);
+ }
+ else if (ident && !enum_type) {
+ error(state, 0, "enum %s undeclared", ident->name);
+ }
+ return enum_type;
}
static struct type *struct_declarator(
@@ -8649,7 +9009,7 @@ static struct type *struct_or_union_specifier(
break;
}
tok = peek(state);
- if ((tok == TOK_IDENT) || (tok == TOK_TYPE_NAME)) {
+ if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) {
eat(state, tok);
ident = state->token[0].ident;
}
@@ -8689,13 +9049,15 @@ static struct type *struct_or_union_specifier(
struct_type->type_ident = ident;
struct_type->elements = elements;
if (ident) {
- symbol(state, ident, &ident->sym_struct, 0, struct_type);
+ symbol(state, ident, &ident->sym_tag, 0, struct_type);
}
}
- if (ident && ident->sym_struct) {
- struct_type = clone_type(spec, ident->sym_struct->type);
+ if (ident && ident->sym_tag &&
+ ident->sym_tag->type &&
+ ((ident->sym_tag->type->type & TYPE_MASK) == TYPE_STRUCT)) {
+ struct_type = clone_type(spec, ident->sym_tag->type);
}
- else if (ident && !ident->sym_struct) {
+ else if (ident && !struct_type) {
error(state, 0, "struct %s undeclared", ident->name);
}
return struct_type;
@@ -9078,7 +9440,6 @@ static struct triple *initializer(
struct compile_state *state, struct type *type)
{
struct triple *result;
-#warning "FIXME handle string pointer initializers "
#warning "FIXME more consistent initializer handling (where should eval_const_expr go?"
if (peek(state) != TOK_LBRACE) {
result = assignment_expr(state);
@@ -9089,6 +9450,12 @@ static struct triple *initializer(
(equiv_types(type->left, result->type->left))) {
type->elements = result->type->elements;
}
+ if (is_stable(state, result) &&
+ ((result->type->type & TYPE_MASK) == TYPE_ARRAY) &&
+ (type->type & TYPE_MASK) != TYPE_ARRAY)
+ {
+ result = array_to_pointer(state, result);
+ }
if (!is_init_compatible(state, type, result->type)) {
error(state, 0, "Incompatible types in initializer");
}
@@ -9423,19 +9790,19 @@ static void decls(struct compile_state *state)
* Data structurs for optimation.
*/
-static void do_use_block(
+static int do_use_block(
struct block *used, struct block_set **head, struct block *user,
int front)
{
struct block_set **ptr, *new;
if (!used)
- return;
+ return 0;
if (!user)
- return;
+ return 0;
ptr = head;
while(*ptr) {
if ((*ptr)->member == user) {
- return;
+ return 0;
}
ptr = &(*ptr)->next;
}
@@ -9449,11 +9816,14 @@ static void do_use_block(
new->next = 0;
*ptr = new;
}
+ return 1;
}
-static void do_unuse_block(
+static int do_unuse_block(
struct block *used, struct block_set **head, struct block *unuser)
{
struct block_set *use, **ptr;
+ int count;
+ count = 0;
ptr = head;
while(*ptr) {
use = *ptr;
@@ -9461,25 +9831,29 @@ static void do_unuse_block(
*ptr = use->next;
memset(use, -1, sizeof(*use));
xfree(use);
+ count += 1;
}
else {
ptr = &use->next;
}
}
+ return count;
}
static void use_block(struct block *used, struct block *user)
{
+ int count;
/* Append new to the head of the list, print_block
* depends on this.
*/
- do_use_block(used, &used->use, user, 1);
- used->users++;
+ count = do_use_block(used, &used->use, user, 1);
+ used->users += count;
}
static void unuse_block(struct block *used, struct block *unuser)
{
- do_unuse_block(used, &used->use, unuser);
- used->users--;
+ int count;
+ count = do_unuse_block(used, &used->use, unuser);
+ used->users -= count;
}
static void idom_block(struct block *idom, struct block *user)
@@ -9522,48 +9896,25 @@ static void unipdomf_block(struct block *block, struct block *unipdomf)
do_unuse_block(block, &block->ipdomfrontier, unipdomf);
}
-
-
-static int do_walk_triple(struct compile_state *state,
- struct triple *ptr, int depth,
- int (*cb)(struct compile_state *state, struct triple *ptr, int depth))
+static int walk_triples(
+ struct compile_state *state,
+ int (*cb)(struct compile_state *state, struct triple *ptr))
{
+ struct triple *ptr;
int result;
- result = cb(state, ptr, depth);
- if ((result == 0) && (ptr->op == OP_LIST)) {
- struct triple *list;
- list = ptr;
- ptr = RHS(list, 0);
- do {
- result = do_walk_triple(state, ptr, depth + 1, cb);
- if (ptr->next->prev != ptr) {
- internal_error(state, ptr->next, "bad prev");
- }
- ptr = ptr->next;
-
- } while((result == 0) && (ptr != RHS(list, 0)));
- }
+ ptr = state->first;
+ do {
+ result = cb(state, ptr);
+ if (ptr->next->prev != ptr) {
+ internal_error(state, ptr->next, "bad prev");
+ }
+ ptr = ptr->next;
+ } while((result == 0) && (ptr != state->first));
return result;
}
-static int walk_triple(
- struct compile_state *state,
- struct triple *ptr,
- int (*cb)(struct compile_state *state, struct triple *ptr, int depth))
-{
- return do_walk_triple(state, ptr, 0, cb);
-}
-
-static void do_print_prefix(int depth)
-{
- int i;
- for(i = 0; i < depth; i++) {
- printf(" ");
- }
-}
-
#define PRINT_LIST 1
-static int do_print_triple(struct compile_state *state, struct triple *ins, int depth)
+static int do_print_triple(struct compile_state *state, struct triple *ins)
{
int op;
op = ins->op;
@@ -9575,7 +9926,6 @@ static int do_print_triple(struct compile_state *state, struct triple *ins, int
if ((op == OP_LABEL) && (ins->use)) {
printf("\n%p:\n", ins);
}
- do_print_prefix(depth);
display_triple(stdout, ins);
if ((ins->op == OP_BRANCH) && ins->use) {
@@ -9587,14 +9937,9 @@ static int do_print_triple(struct compile_state *state, struct triple *ins, int
return 0;
}
-static void print_triple(struct compile_state *state, struct triple *ins)
-{
- walk_triple(state, ins, do_print_triple);
-}
-
static void print_triples(struct compile_state *state)
{
- print_triple(state, state->main_function);
+ walk_triples(state, do_print_triple);
}
struct cf_block {
@@ -9641,8 +9986,7 @@ static struct block *basic_block(struct compile_state *state,
struct triple *first)
{
struct block *block;
- struct triple *ptr, *final;
- int op;
+ struct triple *ptr;
if (first->op != OP_LABEL) {
internal_error(state, 0, "block does not start with a label");
}
@@ -9650,11 +9994,6 @@ static struct block *basic_block(struct compile_state *state,
if (first->u.block != 0) {
return first->u.block;
}
- /* Lookup the final instruction.
- * It is important that the final instruction has it's own
- * basic block.
- */
- final = RHS(state->main_function, 0)->prev;
/* Allocate another basic block structure */
state->last_vertex += 1;
block = xcmalloc(sizeof(*block), "block");
@@ -9662,8 +10001,7 @@ static struct block *basic_block(struct compile_state *state,
block->vertex = state->last_vertex;
ptr = first;
do {
- if ((ptr != first) && (ptr->op == OP_LABEL) &&
- ((ptr->use) || ptr == final)) {
+ if ((ptr != first) && (ptr->op == OP_LABEL) && (ptr->use)) {
break;
}
block->last = ptr;
@@ -9671,20 +10009,20 @@ static struct block *basic_block(struct compile_state *state,
if (triple_stores_block(state, ptr)) {
ptr->u.block = block;
}
- if (ptr->op == OP_BRANCH) {
+ if (triple_is_branch(state, ptr)) {
break;
}
ptr = ptr->next;
- } while (ptr != RHS(state->main_function, 0));
- if (ptr == RHS(state->main_function, 0))
- return block;
- op = ptr->op;
- if (op == OP_LABEL) {
+ } while (ptr != state->first);
+ if (ptr == state->first) {
+ /* The block has no outflowing edges */
+ }
+ else if (ptr->op == OP_LABEL) {
block->left = basic_block(state, ptr);
block->right = 0;
use_block(block->left, block);
}
- else if (op == OP_BRANCH) {
+ else if (triple_is_branch(state, ptr)) {
block->left = 0;
/* Trace the branch target */
block->right = basic_block(state, TARG(ptr, 0));
@@ -9698,6 +10036,15 @@ static struct block *basic_block(struct compile_state *state,
else {
internal_error(state, 0, "Bad basic block split");
}
+#if 0
+ fprintf(stderr, "basic_block: %10p [%2d] ( %10p - %10p ) %10p [%2d] %10p [%2d] \n",
+ block, block->vertex,
+ block->first, block->last,
+ block->left ? block->left->first : 0,
+ block->left ? block->left->vertex : -1,
+ block->left ? block->left->first : 0,
+ block->left ? block->left->vertex : -1);
+#endif
return block;
}
@@ -9709,7 +10056,7 @@ static void walk_blocks(struct compile_state *state,
struct triple *ptr, *first;
struct block *last_block;
last_block = 0;
- first = RHS(state->main_function, 0);
+ first = state->first;
ptr = first;
do {
struct block *block;
@@ -9770,7 +10117,7 @@ static void prune_nonblock_triples(struct compile_state *state)
struct block *block;
struct triple *first, *ins, *next;
/* Delete the triples not in a basic block */
- first = RHS(state->main_function, 0);
+ first = state->first;
block = 0;
ins = first;
do {
@@ -9790,20 +10137,43 @@ static void prune_nonblock_triples(struct compile_state *state)
static void setup_basic_blocks(struct compile_state *state)
{
- if (!triple_stores_block(state, RHS(state->main_function, 0)) ||
- !triple_stores_block(state, RHS(state->main_function,0)->prev)) {
+ if (!triple_stores_block(state, state->first)) {
internal_error(state, 0, "ins will not store block?");
}
/* Find the basic blocks */
state->last_vertex = 0;
- state->first_block = basic_block(state, RHS(state->main_function,0));
+ state->first_block = basic_block(state, state->first);
/* Delete the triples not in a basic block */
prune_nonblock_triples(state);
- /* Find the last basic block */
- state->last_block = RHS(state->main_function, 0)->prev->u.block;
- if (!state->last_block) {
- internal_error(state, 0, "end not used?");
+
+ /* Find the last basic block.
+ *
+ * For purposes of reverse flow computation it is
+ * important that the last basic block is empty.
+ * This allows the control flow graph to be modified to
+ * have one unique starting block and one unique final block.
+ * With the insertion of a few extra edges.
+ *
+ * If the final block contained instructions it could contain
+ * phi functions from edges that would never contribute a
+ * value. Which for now at least I consider a compile error.
+ */
+ state->last_block = block_of_triple(state, state->first->prev);
+ if ((state->last_block->first != state->last_block->last) ||
+ (state->last_block->last->op != OP_LABEL))
+ {
+ struct block *block, *prev_block;
+ struct triple *final;
+ prev_block = state->last_block;
+ final = label(state);
+ flatten(state, state->first, final);
+ use_triple(final, final);
+ block = basic_block(state, final);
+ state->last_block = block;
+ prev_block->left = block;
+ use_block(prev_block->left, prev_block);
}
+
/* If we are debugging print what I have just done */
if (state->debug & DEBUG_BASIC_BLOCKS) {
print_blocks(state, stdout);
@@ -9886,7 +10256,7 @@ static void free_basic_blocks(struct compile_state *state)
free_basic_block(state, state->first_block);
state->last_vertex = 0;
state->first_block = state->last_block = 0;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (triple_stores_block(state, ins)) {
@@ -9955,7 +10325,7 @@ static int initialize_sdblock(struct sdom_block *sd,
return vertex;
}
-static int initialize_sdpblock(
+static int initialize_spdblock(
struct compile_state *state, struct sdom_block *sd,
struct block *parent, struct block *block, int vertex)
{
@@ -9973,24 +10343,24 @@ static int initialize_sdpblock(
sd[vertex].ancestor = 0;
sd[vertex].vertex = vertex;
for(user = block->use; user; user = user->next) {
- vertex = initialize_sdpblock(state, sd, block, user->member, vertex);
+ vertex = initialize_spdblock(state, sd, block, user->member, vertex);
}
return vertex;
}
-static int setup_sdpblocks(struct compile_state *state, struct sdom_block *sd)
+static int setup_spdblocks(struct compile_state *state, struct sdom_block *sd)
{
struct block *block;
int vertex;
/* Setup as many sdpblocks as possible without using fake edges */
- vertex = initialize_sdpblock(state, sd, 0, state->last_block, 0);
+ vertex = initialize_spdblock(state, sd, 0, state->last_block, 0);
/* Walk through the graph and find unconnected blocks. If
* we can, add a fake edge from the unconnected blocks to the
* end of the graph.
*/
block = state->first_block->last->next->u.block;
- for(; block && block != state->first_block; block = block->last->next->u.block) {
+ for(; block && block != state->first_block; block = block->last->next->u.block) {
if (sd[block->vertex].block == block) {
continue;
}
@@ -10004,7 +10374,7 @@ static int setup_sdpblocks(struct compile_state *state, struct sdom_block *sd)
block->left = state->last_block;
use_block(block->left, block);
- vertex = initialize_sdpblock(state, sd, state->last_block, block, vertex);
+ vertex = initialize_spdblock(state, sd, state->last_block, block, vertex);
}
return vertex;
}
@@ -10248,7 +10618,7 @@ static void find_post_dominators(struct compile_state *state)
/* Step 1 initialize the basic block information */
sd = xcmalloc(sizeof(*sd) * (state->last_vertex + 1), "sdom_state");
- vertex = setup_sdpblocks(state, sd);
+ vertex = setup_spdblocks(state, sd);
if (vertex != state->last_vertex) {
internal_error(state, 0, "missing %d blocks\n",
state->last_vertex - vertex);
@@ -10309,13 +10679,12 @@ static void find_block_ipdomf(struct compile_state *state, struct block *block)
}
find_block_ipdomf(state, child);
}
- if (block->left && block->left->ipdom != block) {
- ipdomf_block(block, block->left);
- }
- if (block->right && block->right->ipdom != block) {
- ipdomf_block(block, block->right);
+ for(user = block->use; user; user = user->next) {
+ if (user->member->ipdom != block) {
+ ipdomf_block(block, user->member);
+ }
}
- for(user = block->idominates; user; user = user->next) {
+ for(user = block->ipdominates; user; user = user->next) {
struct block_set *frontier;
child = user->member;
for(frontier = child->ipdomfrontier; frontier; frontier = frontier->next) {
@@ -10485,6 +10854,13 @@ static int tdominates(struct compile_state *state,
return result;
}
+static void analyze_basic_blocks(struct compile_state *state)
+{
+ setup_basic_blocks(state);
+ analyze_idominators(state);
+ analyze_ipdominators(state);
+}
+
static void insert_phi_operations(struct compile_state *state)
{
size_t size;
@@ -10499,7 +10875,7 @@ static void insert_phi_operations(struct compile_state *state)
work = xcmalloc(size, "work");
iter = 0;
- first = RHS(state->main_function, 0);
+ first = state->first;
for(var = first->next; var != first ; var = vnext) {
struct block *block;
struct triple_set *user, *unext;
@@ -10560,6 +10936,7 @@ static void insert_phi_operations(struct compile_state *state)
front->last = front->first->next;
}
has_already[front->vertex] = iter;
+ transform_to_arch_instruction(state, phi);
/* If necessary plan to visit the basic block */
if (work[front->vertex] >= iter) {
@@ -10577,35 +10954,68 @@ static void insert_phi_operations(struct compile_state *state)
}
-static int count_and_number_adecls(struct compile_state *state)
+struct stack {
+ struct triple_set *top;
+ unsigned orig_id;
+};
+
+static int count_adecls(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ int adecls = 0;
+ first = state->first;
+ ins = first;
+ do {
+ if (ins->op == OP_ADECL) {
+ adecls += 1;
+ }
+ ins = ins->next;
+ } while(ins != first);
+ return adecls;
+}
+
+static void number_adecls(struct compile_state *state, struct stack *stacks)
{
struct triple *first, *ins;
int adecls = 0;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (ins->op == OP_ADECL) {
adecls += 1;
+ stacks[adecls].orig_id = ins->id;
ins->id = adecls;
}
ins = ins->next;
} while(ins != first);
- return adecls;
}
-static struct triple *peek_triple(struct triple_set **stacks, struct triple *var)
+static void restore_adecls(struct compile_state *state, struct stack *stacks)
+{
+ struct triple *first, *ins;
+ first = state->first;
+ ins = first;
+ do {
+ if (ins->op == OP_ADECL) {
+ ins->id = stacks[ins->id].orig_id;
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
+static struct triple *peek_triple(struct stack *stacks, struct triple *var)
{
struct triple_set *head;
struct triple *top_val;
top_val = 0;
- head = stacks[var->id];
+ head = stacks[var->id].top;
if (head) {
top_val = head->member;
}
return top_val;
}
-static void push_triple(struct triple_set **stacks, struct triple *var, struct triple *val)
+static void push_triple(struct stack *stacks, struct triple *var, struct triple *val)
{
struct triple_set *new;
/* Append new to the head of the list,
@@ -10613,14 +11023,14 @@ static void push_triple(struct triple_set **stacks, struct triple *var, struct t
*/
new = xcmalloc(sizeof(*new), "triple_set");
new->member = val;
- new->next = stacks[var->id];
- stacks[var->id] = new;
+ new->next = stacks[var->id].top;
+ stacks[var->id].top = new;
}
-static void pop_triple(struct triple_set **stacks, struct triple *var, struct triple *oldval)
+static void pop_triple(struct stack *stacks, struct triple *var, struct triple *oldval)
{
struct triple_set *set, **ptr;
- ptr = &stacks[var->id];
+ ptr = &stacks[var->id].top;
while(*ptr) {
set = *ptr;
if (set->member == oldval) {
@@ -10640,7 +11050,7 @@ static void pop_triple(struct triple_set **stacks, struct triple *var, struct tr
* S(V)
*/
static void fixup_block_phi_variables(
- struct compile_state *state, struct triple_set **stacks, struct block *parent, struct block *block)
+ struct compile_state *state, struct stack *stacks, struct block *parent, struct block *block)
{
struct block_set *set;
struct triple *ptr;
@@ -10687,7 +11097,7 @@ static void fixup_block_phi_variables(
static void rename_block_variables(
- struct compile_state *state, struct triple_set **stacks, struct block *block)
+ struct compile_state *state, struct stack *stacks, struct block *block)
{
struct block_set *user;
struct triple *ptr, *next, *last;
@@ -10736,6 +11146,7 @@ static void rename_block_variables(
tval = pre_triple(state, ptr, OP_COPY, ptr->type, val, 0);
use_triple(val, tval);
}
+ transform_to_arch_instruction(state, tval);
unuse_triple(val, ptr);
RHS(ptr, 1) = tval;
use_triple(tval, ptr);
@@ -10789,6 +11200,26 @@ static void rename_block_variables(
block->last = last;
}
+static void rename_variables(struct compile_state *state)
+{
+ struct stack *stacks;
+ int adecls;
+
+ /* Allocate stacks for the Variables */
+ adecls = count_adecls(state);
+ stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks");
+
+ /* Give each adecl a stack */
+ number_adecls(state, stacks);
+
+ /* Rename the variables */
+ rename_block_variables(state, stacks, state->first_block);
+
+ /* Remove the stacks from the adecls */
+ restore_adecls(state, stacks);
+ xfree(stacks);
+}
+
static void prune_block_variables(struct compile_state *state,
struct block *block)
{
@@ -10859,9 +11290,8 @@ static void prune_unused_phis(struct compile_state *state)
struct phi_triple *live;
int phis, i;
-
/* Find the first instruction */
- first = RHS(state->main_function, 0);
+ first = state->first;
/* Count how many phi functions I need to process */
phis = 0;
@@ -10916,36 +11346,34 @@ static void prune_unused_phis(struct compile_state *state)
xfree(live);
}
-
static void transform_to_ssa_form(struct compile_state *state)
{
- struct triple_set **stacks;
- int adecls;
insert_phi_operations(state);
-#if 0
- printf("@%s:%d\n", __FILE__, __LINE__);
- print_blocks(state, stdout);
-#endif
-
- /* Allocate stacks for the Variables */
- adecls = count_and_number_adecls(state);
- stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks");
- rename_block_variables(state, stacks, state->first_block);
- xfree(stacks);
+ rename_variables(state);
prune_block_variables(state, state->first_block);
-
-#if 1
prune_unused_phis(state);
-#endif
-
}
static void clear_vertex(
struct compile_state *state, struct block *block, void *arg)
{
+ /* Clear the current blocks vertex and the vertex of all
+ * of the current blocks neighbors in case there are malformed
+ * blocks with now instructions at this point.
+ */
+ struct block_set *user;
block->vertex = 0;
+ if (block->left) {
+ block->left->vertex = 0;
+ }
+ if (block->right) {
+ block->right->vertex = 0;
+ }
+ for(user = block->use; user; user = user->next) {
+ user->member->vertex = 0;
+ }
}
static void mark_live_block(
@@ -10970,7 +11398,7 @@ static void mark_live_block(
mark_live_block(state, (*targ)->u.block, next_vertex);
}
}
- else if (block->last->next != RHS(state->main_function, 0)) {
+ else if (block->last->next != state->first) {
struct triple *ins;
ins = block->last->next;
if (!triple_stores_block(state, ins)) {
@@ -10986,7 +11414,7 @@ static void transform_from_ssa_form(struct compile_state *state)
* edges to blocks containting phi functions.
*/
struct triple *first;
- struct triple *phi, *next;
+ struct triple *phi, *var, *next;
int next_vertex;
/* Walk the control flow to see which blocks remain alive */
@@ -10994,22 +11422,34 @@ static void transform_from_ssa_form(struct compile_state *state)
next_vertex = 1;
mark_live_block(state, state->first_block, &next_vertex);
+#if 0
+ fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__);
+ print_blocks(state, stderr);
+#endif
+
/* Walk all of the operations to find the phi functions */
- first = RHS(state->main_function, 0);
+ first = state->first;
for(phi = first->next; phi != first ; phi = next) {
struct block_set *set;
struct block *block;
struct triple **slot;
- struct triple *var, *read;
+ struct triple *var;
struct triple_set *use, *use_next;
int edge, used;
next = phi->next;
if (phi->op != OP_PHI) {
continue;
}
+
block = phi->u.block;
slot = &RHS(phi, 0);
+ /* If this phi is in a dead block just forget it */
+ if (block->vertex == 0) {
+ release_triple(state, phi);
+ continue;
+ }
+
/* Forget uses from code in dead blocks */
for(use = phi->use; use; use = use_next) {
struct block *ublock;
@@ -11027,55 +11467,61 @@ static void transform_from_ssa_form(struct compile_state *state)
}
unuse_triple(phi, use->member);
}
-
-#warning "CHECK_ME does the OP_ADECL need to be placed somewhere that dominates all of the incoming phi edges?"
/* A variable to replace the phi function */
var = post_triple(state, phi, OP_ADECL, phi->type, 0,0);
- /* A read of the single value that is set into the variable */
- read = post_triple(state, var, OP_READ, phi->type, var, 0);
- use_triple(var, read);
- /* Replaces uses of the phi with variable reads */
- propogate_use(state, phi, read);
+ /* Replaces use of phi with var */
+ propogate_use(state, phi, var);
/* Walk all of the incoming edges/blocks and insert moves.
*/
+ used = 0;
for(edge = 0, set = block->use; set; set = set->next, edge++) {
- struct block *eblock;
+ struct block *eblock, *vblock;
struct triple *move;
struct triple *val, *base;
eblock = set->member;
val = slot[edge];
slot[edge] = 0;
unuse_triple(val, phi);
+ vblock = block_of_triple(state, val);
- if (!val || (val == &zero_triple) ||
- (block->vertex == 0) || (eblock->vertex == 0) ||
- (val == phi) || (val == read)) {
+ /* If we don't have a value that belongs in an OP_WRITE
+ * continue on.
+ */
+ if (!val || (val == &zero_triple) || (val == phi) ||
+ (!vblock) || (vblock->vertex == 0)) {
+ continue;
+ }
+
+ /* If the value occurs in a dead block see if a replacement
+ * block can be found.
+ */
+ while(eblock && (eblock->vertex == 0)) {
+ eblock = eblock->idom;
+ }
+ /* If not continue on with the next value. */
+ if (!eblock || (eblock->vertex == 0)) {
continue;
}
+
+ /* If we have an empty incoming block ignore it. */
+ if (!eblock->first) {
+ internal_error(state, 0, "empty block?");
+ }
/* Make certain the write is placed in the edge block... */
base = eblock->first;
if (block_of_triple(state, val) == eblock) {
base = val;
}
- move = post_triple(state, base, OP_WRITE, phi->type, var, val);
+ move = post_triple(state, base, OP_WRITE, var->type, var, val);
use_triple(val, move);
use_triple(var, move);
+ used = 1;
}
- /* See if there are any writers of var */
- used = 0;
- for(use = var->use; use; use = use->next) {
- if ((use->member->op == OP_WRITE) &&
- (RHS(use->member, 0) == var)) {
- used = 1;
- }
- }
/* If var is not used free it */
if (!used) {
- unuse_triple(var, read);
- free_triple(state, read);
free_triple(state, var);
}
@@ -11083,8 +11529,76 @@ static void transform_from_ssa_form(struct compile_state *state)
release_triple(state, phi);
}
+ /* Walk all of the operations to find the adecls */
+ for(var = first->next; var != first ; var = var->next) {
+ struct triple_set *use, *use_next;
+ if (var->op != OP_ADECL) {
+ continue;
+ }
+
+ /* Walk through all of the rhs uses of var and
+ * replace them with read of var.
+ */
+ for(use = var->use; use; use = use_next) {
+ struct triple *read, *user;
+ struct triple **slot;
+ int zrhs, i, used;
+ use_next = use->next;
+ user = use->member;
+
+ /* Generate a read of var */
+ read = pre_triple(state, user, OP_READ, var->type, var, 0);
+ use_triple(var, read);
+
+ /* Find the rhs uses and see if they need to be replaced */
+ used = 0;
+ zrhs = TRIPLE_RHS(user->sizes);
+ slot = &RHS(user, 0);
+ for(i = 0; i < zrhs; i++) {
+ if ((slot[i] == var) &&
+ ((i != 0) || (user->op != OP_WRITE)))
+ {
+ slot[i] = read;
+ used = 1;
+ }
+ }
+ /* If we did use it cleanup the uses */
+ if (used) {
+ unuse_triple(var, user);
+ use_triple(read, user);
+ }
+ /* If we didn't use it release the extra triple */
+ else {
+ release_triple(state, read);
+ }
+ }
+ }
}
+#if 0
+#define HI() do { fprintf(stderr, "@ %s:%d\n", __FILE__, __LINE__); print_blocks(state, stderr); } while (0)
+#else
+#define HI()
+#endif
+static void rebuild_ssa_form(struct compile_state *state)
+{
+HI();
+ transform_from_ssa_form(state);
+HI();
+ free_basic_blocks(state);
+ analyze_basic_blocks(state);
+HI();
+ insert_phi_operations(state);
+HI();
+ rename_variables(state);
+HI();
+
+ prune_block_variables(state, state->first_block);
+HI();
+ prune_unused_phis(state);
+HI();
+}
+#undef HI
/*
* Register conflict resolution
@@ -11376,7 +11890,7 @@ static void insert_copies_to_phi(struct compile_state *state)
struct triple *phi;
/* Walk all of the operations to find the phi functions */
- first = RHS(state->main_function, 0);
+ first = state->first;
for(phi = first->next; phi != first ; phi = phi->next) {
struct block_set *set;
struct block *block;
@@ -11812,7 +12326,7 @@ static int count_triples(struct compile_state *state)
{
struct triple *first, *ins;
int triples = 0;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
triples++;
@@ -11826,7 +12340,7 @@ struct dead_triple {
struct triple *triple;
struct dead_triple *work_next;
struct block *block;
- int color;
+ int old_id;
int flags;
#define TRIPLE_FLAG_ALIVE 1
};
@@ -11851,7 +12365,7 @@ static void awaken(
triple->id);
}
if (triple->op == OP_NOOP) {
- internal_warning(state, triple, "awakening noop?");
+ internal_error(state, triple, "awakening noop?");
return;
}
dt = &dtriple[triple->id];
@@ -11869,13 +12383,14 @@ static void eliminate_inefectual_code(struct compile_state *state)
struct block *block;
struct dead_triple *dtriple, *work_list, **work_list_tail, *dt;
int triples, i;
- struct triple *first, *ins;
+ struct triple *first, *final, *ins;
/* Setup the work list */
work_list = 0;
work_list_tail = &work_list;
- first = RHS(state->main_function, 0);
+ first = state->first;
+ final = state->first->prev;
/* Count how many triples I have */
triples = count_triples(state);
@@ -11887,29 +12402,20 @@ static void eliminate_inefectual_code(struct compile_state *state)
i = 1;
block = 0;
do {
- if (ins->op == OP_LABEL) {
- block = ins->u.block;
- }
dtriple[i].triple = ins;
- dtriple[i].block = block;
+ dtriple[i].block = block_of_triple(state, ins);
dtriple[i].flags = 0;
- dtriple[i].color = ins->id;
+ dtriple[i].old_id = ins->id;
ins->id = i;
/* See if it is an operation we always keep */
-#warning "FIXME handle the case of killing a branch instruction"
- if (!triple_is_pure(state, ins) || triple_is_branch(state, ins)) {
- awaken(state, dtriple, &ins, &work_list_tail);
- }
-#if 1
- /* Unconditionally keep the very last instruction */
- else if (ins->next == first) {
+ if (!triple_is_pure(state, ins, dtriple[i].old_id)) {
awaken(state, dtriple, &ins, &work_list_tail);
}
-#endif
i++;
ins = ins->next;
} while(ins != first);
while(work_list) {
+ struct block *block;
struct dead_triple *dt;
struct block_set *user;
struct triple **expr;
@@ -11918,6 +12424,13 @@ static void eliminate_inefectual_code(struct compile_state *state)
if (!work_list) {
work_list_tail = &work_list;
}
+ /* Make certain the block the current instruction is in lives */
+ block = block_of_triple(state, dt->triple);
+ awaken(state, dtriple, &block->first, &work_list_tail);
+ if (triple_is_branch(state, block->last)) {
+ awaken(state, dtriple, &block->last, &work_list_tail);
+ }
+
/* Wake up the data depencencies of this triple */
expr = 0;
do {
@@ -11940,6 +12453,11 @@ static void eliminate_inefectual_code(struct compile_state *state)
/* Wake up the reverse control dependencies of this triple */
for(user = dt->block->ipdomfrontier; user; user = user->next) {
awaken(state, dtriple, &user->member->last, &work_list_tail);
+ if ((user->member->left != state->last_block) &&
+ !triple_is_cond_branch(state, user->member->last)) {
+ internal_error(state, dt->triple,
+ "conditional branch missing");
+ }
}
}
for(dt = &dtriple[1]; dt <= &dtriple[triples]; dt++) {
@@ -11947,15 +12465,8 @@ static void eliminate_inefectual_code(struct compile_state *state)
(dt->flags & TRIPLE_FLAG_ALIVE)) {
internal_error(state, dt->triple, "noop effective?");
}
- dt->triple->id = dt->color; /* Restore the color */
+ dt->triple->id = dt->old_id; /* Restore the color */
if (!(dt->flags & TRIPLE_FLAG_ALIVE)) {
-#warning "FIXME handle the case of killing a basic block"
- if (dt->block->first == dt->triple) {
- continue;
- }
- if (dt->block->last == dt->triple) {
- dt->block->last = dt->triple->prev;
- }
release_triple(state, dt->triple);
}
}
@@ -11974,7 +12485,7 @@ static void insert_mandatory_copies(struct compile_state *state)
* are inserting copies before instructions but that
* case should be rare.
*/
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
struct triple_set *entry, *next;
@@ -12746,7 +13257,7 @@ static void initialize_live_ranges(
size_t count, size;
int i, j;
- first = RHS(state->main_function, 0);
+ first = state->first;
/* First count how many instructions I have.
*/
count = count_triples(state);
@@ -12978,23 +13489,6 @@ static void verify_graph_ins(
return;
}
-#if DEBUG_CONSISTENCY > 1
-static void verify_interference_graph(
- struct compile_state *state, struct reg_state *rstate)
-{
-#if 0
- fprintf(stderr, "verify_interference_graph...\n");
-#endif
-
- walk_variable_lifetimes(state, rstate->blocks, verify_graph_ins, rstate);
-#if 0
- fprintf(stderr, "verify_interference_graph done\n");
-#endif
-}
-#else
-static inline void verify_interference_graph(
- struct compile_state *state, struct reg_state *rstate) {}
-#endif
static void print_interference_ins(
struct compile_state *state,
@@ -13241,7 +13735,7 @@ static void replace_block_use(struct compile_state *state,
static void color_instructions(struct compile_state *state)
{
struct triple *ins, *first;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (triple_is_def(state, ins)) {
@@ -13808,14 +14302,13 @@ static int color_graph(struct compile_state *state, struct reg_state *rstate)
return colored;
}
-#if DEBUG_CONSISTENCY
static void verify_colors(struct compile_state *state, struct reg_state *rstate)
{
struct live_range *lr;
struct live_range_edge *edge;
struct triple *ins, *first;
char used[MAX_REGISTERS];
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (triple_is_def(state, ins)) {
@@ -13845,15 +14338,12 @@ static void verify_colors(struct compile_state *state, struct reg_state *rstate)
ins = ins->next;
} while(ins != first);
}
-#else
-static inline void verify_colors(struct compile_state *state, struct reg_state *rstate) {}
-#endif
static void color_triples(struct compile_state *state, struct reg_state *rstate)
{
struct live_range *lr;
struct triple *first, *ins;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if ((ins->id < 0) || (ins->id > rstate->defs)) {
@@ -13930,7 +14420,7 @@ static void ids_from_rstate(struct compile_state *state,
print_blocks(state, stdout);
print_control_flow(state);
}
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (ins->id) {
@@ -14052,8 +14542,17 @@ static void allocate_registers(struct compile_state *state)
#endif
} while(coalesced);
+#if DEBUG_CONSISTENCY > 1
+# if 0
+ fprintf(stderr, "verify_graph_ins...\n");
+# endif
/* Verify the interference graph */
- verify_interference_graph(state, &rstate);
+ walk_variable_lifetimes(
+ state, rstate.blocks, verify_graph_ins, &rstate);
+# if 0
+ fprintf(stderr, "verify_graph_ins done\n");
+#endif
+#endif
/* Build the groups low and high. But with the nodes
* first sorted by degree order.
@@ -14169,6 +14668,11 @@ struct scc_state {
static void scc_add_fedge(struct compile_state *state, struct scc_state *scc,
struct flow_edge *fedge)
{
+ if ((fedge == scc->flow_work_list) ||
+ (fedge->work_next != fedge) ||
+ (fedge->work_prev != fedge)) {
+ return;
+ }
if (!scc->flow_work_list) {
scc->flow_work_list = fedge;
fedge->work_next = fedge->work_prev = fedge;
@@ -14196,6 +14700,7 @@ static struct flow_edge *scc_next_fedge(
} else {
scc->flow_work_list = 0;
}
+ fedge->work_next = fedge->work_prev = fedge;
}
return fedge;
}
@@ -14203,6 +14708,21 @@ static struct flow_edge *scc_next_fedge(
static void scc_add_sedge(struct compile_state *state, struct scc_state *scc,
struct ssa_edge *sedge)
{
+#if DEBUG_SCC > 1
+ fprintf(stderr, "adding sedge: %5d (%4d -> %5d)\n",
+ sedge - scc->ssa_edges,
+ sedge->src->def->id,
+ sedge->dst->def->id);
+#endif
+ if ((sedge == scc->ssa_work_list) ||
+ (sedge->work_next != sedge) ||
+ (sedge->work_prev != sedge)) {
+#if DEBUG_SCC > 1
+ fprintf(stderr, "dupped sedge: %5d\n",
+ sedge - scc->ssa_edges);
+#endif
+ return;
+ }
if (!scc->ssa_work_list) {
scc->ssa_work_list = sedge;
sedge->work_next = sedge->work_prev = sedge;
@@ -14230,6 +14750,7 @@ static struct ssa_edge *scc_next_sedge(
} else {
scc->ssa_work_list = 0;
}
+ sedge->work_next = sedge->work_prev = sedge;
}
return sedge;
}
@@ -14246,7 +14767,7 @@ static void initialize_scc_state(
memset(scc, 0, sizeof(*scc));
/* Inialize pass zero find out how much memory we need */
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
ins_count = ssa_edge_count = 0;
do {
@@ -14472,6 +14993,7 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
struct lattice_node *tmp;
struct triple **slot, *old;
struct flow_edge *fedge;
+ int changed;
int index;
if (lnode->def->op != OP_PHI) {
internal_error(state, lnode->def, "not phi");
@@ -14484,6 +15006,13 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
slot = &RHS(lnode->def, 0);
index = 0;
for(fedge = lnode->fblock->in; fedge; index++, fedge = fedge->in_next) {
+#if DEBUG_SCC
+ fprintf(stderr, "Examining edge: %d vertex: %d executable: %d\n",
+ index,
+ fedge->dst->block->vertex,
+ fedge->executable
+ );
+#endif
if (!fedge->executable) {
continue;
}
@@ -14512,13 +15041,17 @@ static void scc_visit_phi(struct compile_state *state, struct scc_state *scc,
break;
}
}
+ changed = lval_changed(state, old, lnode);
#if DEBUG_SCC
- fprintf(stderr, "phi: %d -> %s\n",
+ fprintf(stderr, "%p phi: %d -> %s %s\n",
+ lnode->def,
lnode->def->id,
- (!lnode->val)? "lo": is_const(lnode->val)? "const": "hi");
+ ((!lnode->val)? "lo": is_const(lnode->val)? "const": "hi"),
+ changed? "changed" : ""
+ );
#endif
/* If the lattice value has changed update the work lists. */
- if (lval_changed(state, old, lnode)) {
+ if (changed) {
struct ssa_edge *sedge;
for(sedge = lnode->out; sedge; sedge = sedge->out_next) {
scc_add_sedge(state, scc, sedge);
@@ -14608,16 +15141,23 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
/* Find the cases that are always lattice lo */
if (lnode->val &&
triple_is_def(state, lnode->val) &&
- !triple_is_pure(state, lnode->val)) {
+ !triple_is_pure(state, lnode->val, lnode->old_id)) {
lnode->val = 0;
}
- if (lnode->val &&
- (lnode->val->op == OP_SDECL) &&
- (lnode->val != lnode->def)) {
- internal_error(state, lnode->def, "bad sdecl");
- }
/* See if the lattice value has changed */
changed = lval_changed(state, old, lnode);
+ /* See if this value should not change */
+ if (lnode->val &&
+ (( !triple_is_def(state, lnode->def) &&
+ !triple_is_cond_branch(state, lnode->def)) ||
+ (lnode->def->op == OP_PIECE))) {
+#warning "FIXME constant propogate through expressions with multiple left hand sides"
+ if (changed) {
+ internal_warning(state, lnode->def, "non def changes value?");
+ }
+ lnode->val = 0;
+ }
+ /* See if we need to free the scratch value */
if (lnode->val != scratch) {
xfree(scratch);
}
@@ -14708,19 +15248,35 @@ static void scc_writeback_values(
struct compile_state *state, struct scc_state *scc)
{
struct triple *first, *ins;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
struct lattice_node *lnode;
lnode = triple_to_lattice(state, scc, ins);
- /* Restore id */
- ins->id = lnode->old_id;
#if DEBUG_SCC
- if (lnode->val && !is_const(lnode->val)) {
- warning(state, lnode->def,
- "lattice node still high?");
+ if (lnode->val &&
+ !is_const(lnode->val) &&
+ !triple_is_uncond_branch(state, lnode->val) &&
+ (lnode->val->op != OP_NOOP))
+ {
+ struct flow_edge *fedge;
+ int executable;
+ executable = 0;
+ for(fedge = lnode->fblock->in;
+ !executable && fedge; fedge = fedge->in_next) {
+ executable |= fedge->executable;
+ }
+ if (executable) {
+ internal_warning(state, lnode->val,
+ "lattice node %d %s->%s still high?",
+ ins->id,
+ tops(lnode->def->op),
+ tops(lnode->val->op));
+ }
}
#endif
+ /* Restore id */
+ ins->id = lnode->old_id;
if (lnode->val && (lnode->val != ins)) {
/* See if it something I know how to write back */
switch(lnode->val->op) {
@@ -14764,7 +15320,7 @@ static void scc_transform(struct compile_state *state)
struct block *block;
struct triple *ptr;
struct flow_block *fblock;
- int time;
+ int reps;
int done;
if (fedge->executable) {
continue;
@@ -14778,15 +15334,15 @@ static void scc_transform(struct compile_state *state)
fedge->executable = 1;
fblock = fedge->dst;
block = fblock->block;
- time = 0;
+ reps = 0;
for(fptr = fblock->in; fptr; fptr = fptr->in_next) {
if (fptr->executable) {
- time++;
+ reps++;
}
}
#if DEBUG_SCC
- fprintf(stderr, "vertex: %d time: %d\n",
- block->vertex, time);
+ fprintf(stderr, "vertex: %d reps: %d\n",
+ block->vertex, reps);
#endif
done = 0;
@@ -14797,7 +15353,7 @@ static void scc_transform(struct compile_state *state)
if (ptr->op == OP_PHI) {
scc_visit_phi(state, &scc, lnode);
}
- else if (time == 1) {
+ else if (reps == 1) {
scc_visit_expr(state, &scc, lnode);
}
}
@@ -14840,7 +15396,7 @@ static void scc_transform(struct compile_state *state)
static void transform_to_arch_instructions(struct compile_state *state)
{
struct triple *ins, *first;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
ins = transform_to_arch_instruction(state, ins);
@@ -14852,7 +15408,7 @@ static void verify_uses(struct compile_state *state)
{
struct triple *first, *ins;
struct triple_set *set;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
struct triple **expr;
@@ -14892,7 +15448,7 @@ static void verify_blocks_present(struct compile_state *state)
if (!state->first_block) {
return;
}
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
valid_ins(state, ins);
@@ -14930,6 +15486,9 @@ static void verify_blocks(struct compile_state *state)
users = 0;
for(user = block->use; user; user = user->next) {
users++;
+ if (!user->member->first) {
+ internal_error(state, block->first, "user is empty");
+ }
if ((block == state->last_block) &&
(user->member == state->first_block)) {
continue;
@@ -14961,6 +15520,9 @@ static void verify_blocks(struct compile_state *state)
internal_error(state, block->first,
"block does not use left");
}
+ if (!block->left->first) {
+ internal_error(state, block->first, "left block is empty");
+ }
}
if (block->right) {
for(user = block->right->use; user; user = user->next) {
@@ -14972,12 +15534,22 @@ static void verify_blocks(struct compile_state *state)
internal_error(state, block->first,
"block does not use right");
}
+ if (!block->right->first) {
+ internal_error(state, block->first, "right block is empty");
+ }
}
if (block->users != users) {
internal_error(state, block->first,
"computed users %d != stored users %d\n",
users, block->users);
}
+ for(user = block->ipdomfrontier; user; user = user->next) {
+ if ((user->member->left != state->last_block) &&
+ !triple_is_cond_branch(state, user->member->last)) {
+ internal_error(state, user->member->last,
+ "conditional branch missing");
+ }
+ }
if (!triple_stores_block(state, block->last->next)) {
internal_error(state, block->last->next,
"cannot find next block");
@@ -15002,7 +15574,7 @@ static void verify_domination(struct compile_state *state)
return;
}
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
for(set = ins->use; set; set = set->next) {
@@ -15046,10 +15618,36 @@ static void verify_domination(struct compile_state *state)
} while(ins != first);
}
+static void verify_rhs(struct compile_state *state)
+{
+ struct triple *first, *ins;
+ first = state->first;
+ ins = first;
+ do {
+ struct triple **slot;
+ int zrhs, i;
+ zrhs = TRIPLE_RHS(ins->sizes);
+ slot = &RHS(ins, 0);
+ for(i = 0; i < zrhs; i++) {
+ if (slot[i] == 0) {
+ internal_error(state, ins,
+ "missing rhs %d on %s",
+ i, tops(ins->op));
+ }
+ if ((ins->op != OP_PHI) && (slot[i] == ins)) {
+ internal_error(state, ins,
+ "ins == rhs[%d] on %s",
+ i, tops(ins->op));
+ }
+ }
+ ins = ins->next;
+ } while(ins != first);
+}
+
static void verify_piece(struct compile_state *state)
{
struct triple *first, *ins;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
struct triple *ptr;
@@ -15072,11 +15670,12 @@ static void verify_piece(struct compile_state *state)
ins = ins->next;
} while(ins != first);
}
+
static void verify_ins_colors(struct compile_state *state)
{
struct triple *first, *ins;
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
ins = ins->next;
@@ -15088,12 +15687,13 @@ static void verify_consistency(struct compile_state *state)
verify_blocks_present(state);
verify_blocks(state);
verify_domination(state);
+ verify_rhs(state);
verify_piece(state);
verify_ins_colors(state);
}
#else
static void verify_consistency(struct compile_state *state) {}
-#endif /* DEBUG_USES */
+#endif /* DEBUG_CONSISTENCY */
static void optimize(struct compile_state *state)
{
@@ -15107,9 +15707,7 @@ static void optimize(struct compile_state *state)
}
verify_consistency(state);
/* Analize the intermediate code */
- setup_basic_blocks(state);
- analyze_idominators(state);
- analyze_ipdominators(state);
+ analyze_basic_blocks(state);
/* Transform the code to ssa form. */
/*
@@ -15121,23 +15719,21 @@ static void optimize(struct compile_state *state)
* phi functions early and I kill them often.
*/
transform_to_ssa_form(state);
- eliminate_inefectual_code(state);
verify_consistency(state);
if (state->debug & DEBUG_CODE_ELIMINATION) {
fprintf(stdout, "After transform_to_ssa_form\n");
print_blocks(state, stdout);
}
+ /* Remove dead code */
+ eliminate_inefectual_code(state);
+ rebuild_ssa_form(state);
+ verify_consistency(state);
+
/* Do strength reduction and simple constant optimizations */
if (state->optimize >= 1) {
simplify_all(state);
- transform_from_ssa_form(state);
- free_basic_blocks(state);
- setup_basic_blocks(state);
- analyze_idominators(state);
- analyze_ipdominators(state);
- transform_to_ssa_form(state);
- eliminate_inefectual_code(state);
+ rebuild_ssa_form(state);
}
if (state->debug & DEBUG_CODE_ELIMINATION) {
fprintf(stdout, "After simplify_all\n");
@@ -15147,13 +15743,7 @@ static void optimize(struct compile_state *state)
/* Propogate constants throughout the code */
if (state->optimize >= 2) {
scc_transform(state);
- transform_from_ssa_form(state);
- free_basic_blocks(state);
- setup_basic_blocks(state);
- analyze_idominators(state);
- analyze_ipdominators(state);
- transform_to_ssa_form(state);
- eliminate_inefectual_code(state);
+ rebuild_ssa_form(state);
}
verify_consistency(state);
#warning "WISHLIST implement single use constants (least possible register pressure)"
@@ -15168,7 +15758,9 @@ static void optimize(struct compile_state *state)
print_blocks(state, stdout);
print_control_flow(state);
}
+ /* Remove dead code */
eliminate_inefectual_code(state);
+ rebuild_ssa_form(state);
verify_consistency(state);
if (state->debug & DEBUG_CODE_ELIMINATION) {
printf("After eliminate_inefectual_code\n");
@@ -15258,15 +15850,9 @@ static void print_op_asm(struct compile_state *state,
*/
#define X86_4_8BIT_GPRS 1
-/* Recognized x86 cpu variants */
-#define BAD_CPU 0
-#define CPU_I386 1
-#define CPU_P3 2
-#define CPU_P4 3
-#define CPU_K7 4
-#define CPU_K8 5
-
-#define CPU_DEFAULT CPU_I386
+/* x86 featrues */
+#define X86_MMX_REGS (1<<0)
+#define X86_XMM_REGS (1<<1)
/* The x86 register classes */
#define REGC_FLAGS 0
@@ -15423,26 +16009,48 @@ static const struct {
[REGC_IMM8] = { REGC_IMM8_FIRST, REGC_IMM8_LAST },
};
-static int arch_encode_cpu(const char *cpu)
+static int arch_encode_feature(const char *feature, unsigned long *features)
{
struct cpu {
const char *name;
int cpu;
} cpus[] = {
- { "i386", CPU_I386 },
- { "p3", CPU_P3 },
- { "p4", CPU_P4 },
- { "k7", CPU_K7 },
- { "k8", CPU_K8 },
- { 0, BAD_CPU }
+ { "i386", 0 },
+ { "p2", X86_MMX_REGS },
+ { "p3", X86_MMX_REGS | X86_XMM_REGS },
+ { "p4", X86_MMX_REGS | X86_XMM_REGS },
+ { "k7", X86_MMX_REGS },
+ { "k8", X86_MMX_REGS | X86_XMM_REGS },
+ { "c3", X86_MMX_REGS },
+ { "c3-2", X86_MMX_REGS | X86_XMM_REGS }, /* Nehemiah */
+ { 0, 0 }
};
struct cpu *ptr;
- for(ptr = cpus; ptr->name; ptr++) {
- if (strcmp(ptr->name, cpu) == 0) {
- break;
+ int result = 0;
+ if (strcmp(feature, "mmx") == 0) {
+ *features |= X86_MMX_REGS;
+ }
+ else if (strcmp(feature, "sse") == 0) {
+ *features |= X86_XMM_REGS;
+ }
+ else if (strncmp(feature, "cpu=", 4) == 0) {
+ const char *cpu = feature + 4;
+ for(ptr = cpus; ptr->name; ptr++) {
+ if (strcmp(ptr->name, cpu) == 0) {
+ break;
+ }
+ }
+ if (ptr->name) {
+ *features |= ptr->cpu;
+ }
+ else {
+ result = -1;
}
}
- return ptr->cpu;
+ else {
+ result = -1;
+ }
+ return result;
}
static unsigned arch_regc_size(struct compile_state *state, int class)
@@ -15651,15 +16259,11 @@ static unsigned arch_avail_mask(struct compile_state *state)
REGCM_GPR32 | REGCM_GPR32_8 |
REGCM_DIVIDEND32 | REGCM_DIVIDEND64 |
REGCM_IMM32 | REGCM_IMM16 | REGCM_IMM8 | REGCM_FLAGS;
- switch(state->cpu) {
- case CPU_P3:
- case CPU_K7:
+ if (state->features & X86_MMX_REGS) {
avail_mask |= REGCM_MMX;
- break;
- case CPU_P4:
- case CPU_K8:
- avail_mask |= REGCM_MMX | REGCM_XMM;
- break;
+ }
+ if (state->features & X86_XMM_REGS) {
+ avail_mask |= REGCM_XMM;
}
return avail_mask;
}
@@ -16475,6 +17079,32 @@ static struct ins_template templates[] = {
},
};
+static void fixup_branch(struct compile_state *state,
+ struct triple *branch, int jmp_op, int cmp_op, struct type *cmp_type,
+ struct triple *left, struct triple *right)
+{
+ struct triple *test;
+ if (!left) {
+ internal_error(state, branch, "no branch test?");
+ }
+ test = pre_triple(state, branch,
+ cmp_op, cmp_type, left, right);
+ test->template_id = TEMPLATE_TEST32;
+ if (cmp_op == OP_CMP) {
+ test->template_id = TEMPLATE_CMP32_REG;
+ if (get_imm32(test, &RHS(test, 1))) {
+ test->template_id = TEMPLATE_CMP32_IMM;
+ }
+ }
+ use_triple(RHS(test, 0), test);
+ use_triple(RHS(test, 1), test);
+ unuse_triple(RHS(branch, 0), branch);
+ RHS(branch, 0) = test;
+ branch->op = jmp_op;
+ branch->template_id = TEMPLATE_JMP;
+ use_triple(RHS(branch, 0), branch);
+}
+
static void fixup_branches(struct compile_state *state,
struct triple *cmp, struct triple *use, int jmp_op)
{
@@ -16485,7 +17115,7 @@ static void fixup_branches(struct compile_state *state,
fixup_branches(state, cmp, entry->member, jmp_op);
}
else if (entry->member->op == OP_BRANCH) {
- struct triple *branch, *test;
+ struct triple *branch;
struct triple *left, *right;
left = right = 0;
left = RHS(cmp, 0);
@@ -16493,22 +17123,8 @@ static void fixup_branches(struct compile_state *state,
right = RHS(cmp, 1);
}
branch = entry->member;
- test = pre_triple(state, branch,
+ fixup_branch(state, branch, jmp_op,
cmp->op, cmp->type, left, right);
- test->template_id = TEMPLATE_TEST32;
- if (cmp->op == OP_CMP) {
- test->template_id = TEMPLATE_CMP32_REG;
- if (get_imm32(test, &RHS(test, 1))) {
- test->template_id = TEMPLATE_CMP32_IMM;
- }
- }
- use_triple(RHS(test, 0), test);
- use_triple(RHS(test, 1), test);
- unuse_triple(RHS(branch, 0), branch);
- RHS(branch, 0) = test;
- branch->op = jmp_op;
- branch->template_id = TEMPLATE_JMP;
- use_triple(RHS(branch, 0), branch);
}
}
}
@@ -16875,10 +17491,14 @@ static struct triple *transform_to_arch_instruction(
break;
case OP_BRANCH:
if (TRIPLE_RHS(ins->sizes) > 0) {
- internal_error(state, ins, "bad branch test");
+ struct triple *left = RHS(ins, 0);
+ fixup_branch(state, ins, OP_JMP_NOTEQ, OP_TEST,
+ left->type, left, 0);
+ }
+ else {
+ ins->op = OP_JMP;
+ ins->template_id = TEMPLATE_NOP;
}
- ins->op = OP_JMP;
- ins->template_id = TEMPLATE_NOP;
break;
case OP_INB:
case OP_INW:
@@ -16932,6 +17552,9 @@ static struct triple *transform_to_arch_instruction(
ins->template_id = TEMPLATE_CMP32_IMM;
}
break;
+ case OP_JMP:
+ ins->template_id = TEMPLATE_NOP;
+ break;
case OP_JMP_EQ: case OP_JMP_NOTEQ:
case OP_JMP_SLESS: case OP_JMP_ULESS:
case OP_JMP_SMORE: case OP_JMP_UMORE:
@@ -16964,7 +17587,7 @@ static long next_label(struct compile_state *state)
static void generate_local_labels(struct compile_state *state)
{
struct triple *first, *label;
- first = RHS(state->main_function, 0);
+ first = state->first;
label = first;
do {
if ((label->op == OP_LABEL) ||
@@ -17051,7 +17674,7 @@ static void print_const_val(
switch(ins->op) {
case OP_INTCONST:
fprintf(fp, " $%ld ",
- (long_t)(ins->u.cval));
+ (long)(ins->u.cval));
break;
case OP_ADDRCONST:
if (MISC(ins, 0)->op != OP_SDECL) {
@@ -17062,8 +17685,8 @@ static void print_const_val(
}
fprintf(fp, " $L%s%lu+%lu ",
state->label_prefix,
- MISC(ins, 0)->u.cval,
- ins->u.cval);
+ (unsigned long)(MISC(ins, 0)->u.cval),
+ (unsigned long)(ins->u.cval));
break;
default:
internal_error(state, ins, "unknown constant type");
@@ -17079,17 +17702,20 @@ static void print_const(struct compile_state *state,
switch(ins->type->type & TYPE_MASK) {
case TYPE_CHAR:
case TYPE_UCHAR:
- fprintf(fp, ".byte 0x%02lx\n", ins->u.cval);
+ fprintf(fp, ".byte 0x%02lx\n",
+ (unsigned long)(ins->u.cval));
break;
case TYPE_SHORT:
case TYPE_USHORT:
- fprintf(fp, ".short 0x%04lx\n", ins->u.cval);
+ fprintf(fp, ".short 0x%04lx\n",
+ (unsigned long)(ins->u.cval));
break;
case TYPE_INT:
case TYPE_UINT:
case TYPE_LONG:
case TYPE_ULONG:
- fprintf(fp, ".int %lu\n", ins->u.cval);
+ fprintf(fp, ".int %lu\n",
+ (unsigned long)(ins->u.cval));
break;
default:
internal_error(state, ins, "Unknown constant type");
@@ -17104,8 +17730,8 @@ static void print_const(struct compile_state *state,
}
fprintf(fp, ".int L%s%lu+%lu\n",
state->label_prefix,
- MISC(ins, 0)->u.cval,
- ins->u.cval);
+ (unsigned long)(MISC(ins, 0)->u.cval),
+ (unsigned long)(ins->u.cval));
break;
case OP_BLOBCONST:
{
@@ -17146,7 +17772,7 @@ static void print_binary_op(struct compile_state *state,
{
unsigned mask;
mask = REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO;
- if (RHS(ins, 0)->id != ins->id) {
+ if (ID_REG(RHS(ins, 0)->id) != ID_REG(ins->id)) {
internal_error(state, ins, "invalid register assignment");
}
if (is_const(RHS(ins, 1))) {
@@ -17184,7 +17810,7 @@ static void print_op_shift(struct compile_state *state,
{
unsigned mask;
mask = REGCM_GPR32 | REGCM_GPR16 | REGCM_GPR8_LO;
- if (RHS(ins, 0)->id != ins->id) {
+ if (ID_REG(RHS(ins, 0)->id) != ID_REG(ins->id)) {
internal_error(state, ins, "invalid register assignment");
}
if (is_const(RHS(ins, 1))) {
@@ -17577,14 +18203,14 @@ static void print_op_store(struct compile_state *state,
value = (long_t)(src->u.cval);
fprintf(fp, "\tmov%s $%ld, (%s)\n",
type_suffix(state, src->type),
- value,
+ (long)(value),
reg(state, dst, REGCM_GPR32));
}
else if (is_const(dst) && (dst->op == OP_INTCONST)) {
fprintf(fp, "\tmov%s %s, 0x%08lx\n",
type_suffix(state, src->type),
reg(state, src, REGCM_GPR8_LO | REGCM_GPR16 | REGCM_GPR32),
- dst->u.cval);
+ (unsigned long)(dst->u.cval));
}
else {
if (is_const(src) || is_const(dst)) {
@@ -17700,7 +18326,7 @@ static void print_op_branch(struct compile_state *state,
fprintf(fp, "\t%s L%s%lu\n",
bop,
state->label_prefix,
- TARG(branch, 0)->u.cval);
+ (unsigned long)(TARG(branch, 0)->u.cval));
}
static void print_op_set(struct compile_state *state,
@@ -17766,7 +18392,8 @@ static void print_sdecl(struct compile_state *state,
{
fprintf(fp, ".section \"" DATA_SECTION "\"\n");
fprintf(fp, ".balign %d\n", align_of(state, ins->type));
- fprintf(fp, "L%s%lu:\n", state->label_prefix, ins->u.cval);
+ fprintf(fp, "L%s%lu:\n",
+ state->label_prefix, (unsigned long)(ins->u.cval));
print_const(state, MISC(ins, 0), fp);
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
@@ -17865,7 +18492,8 @@ static void print_instruction(struct compile_state *state,
if (!ins->use) {
return;
}
- fprintf(fp, "L%s%lu:\n", state->label_prefix, ins->u.cval);
+ fprintf(fp, "L%s%lu:\n",
+ state->label_prefix, (unsigned long)(ins->u.cval));
break;
/* Ignore OP_PIECE */
case OP_PIECE:
@@ -17895,7 +18523,7 @@ static void print_instructions(struct compile_state *state)
last_occurance = 0;
fp = state->output;
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
- first = RHS(state->main_function, 0);
+ first = state->first;
ins = first;
do {
if (print_location &&
@@ -17967,11 +18595,21 @@ static void print_tokens(struct compile_state *state)
} while(tk->tok != TOK_EOF);
}
+static void call_main(struct compile_state *state)
+{
+ struct triple *call;
+ call = new_triple(state, OP_CALL, &void_func, -1, -1);
+ call->type = &void_type;
+ MISC(call, 0) = state->main_function;
+ flatten(state, state->first, call);
+}
+
static void compile(const char *filename, const char *ofilename,
- int cpu, int debug, int opt, const char *label_prefix)
+ unsigned long features, int debug, int opt, const char *label_prefix)
{
int i;
struct compile_state state;
+ struct triple *ptr;
memset(&state, 0, sizeof(state));
state.file = 0;
for(i = 0; i < sizeof(state.token)/sizeof(state.token[0]); i++) {
@@ -17979,7 +18617,7 @@ static void compile(const char *filename, const char *ofilename,
state.token[i].tok = -1;
}
/* Remember the debug settings */
- state.cpu = cpu;
+ state.features = features;
state.debug = debug;
state.optimize = opt;
/* Remember the output filename */
@@ -17999,8 +18637,21 @@ static void compile(const char *filename, const char *ofilename,
/* register the keywords the macro preprocessor knows */
register_macro_keywords(&state);
/* Memorize where some special keywords are. */
+ state.i_switch = lookup(&state, "switch", 6);
+ state.i_case = lookup(&state, "case", 4);
state.i_continue = lookup(&state, "continue", 8);
state.i_break = lookup(&state, "break", 5);
+ state.i_default = lookup(&state, "default", 7);
+
+ /* Allocate beginning bounding labels for the function list */
+ state.first = label(&state);
+ state.first->id |= TRIPLE_FLAG_VOLATILE;
+ use_triple(state.first, state.first);
+ ptr = label(&state);
+ ptr->id |= TRIPLE_FLAG_VOLATILE;
+ use_triple(ptr, ptr);
+ flatten(&state, state.first, ptr);
+
/* Enter the globl definition scope */
start_scope(&state);
register_builtins(&state);
@@ -18012,6 +18663,9 @@ static void compile(const char *filename, const char *ofilename,
/* Exit the global definition scope */
end_scope(&state);
+ /* Call the main function */
+ call_main(&state);
+
/* Now that basic compilation has happened
* optimize the intermediate code
*/
@@ -18052,11 +18706,11 @@ int main(int argc, char **argv)
const char *filename;
const char *ofilename;
const char *label_prefix;
- int cpu;
+ unsigned long features;
int last_argc;
int debug;
int optimize;
- cpu = CPU_DEFAULT;
+ features = 0;
label_prefix = "";
ofilename = "auto.inc";
optimize = 0;
@@ -18090,11 +18744,12 @@ int main(int argc, char **argv)
argv += 2;
argc -= 2;
}
- else if (strncmp(argv[1], "-mcpu=", 6) == 0) {
- cpu = arch_encode_cpu(argv[1] + 6);
- if (cpu == BAD_CPU) {
- arg_error("Invalid cpu specified: %s\n",
- argv[1] + 6);
+ else if (strncmp(argv[1], "-m", 2) == 0) {
+ int result;
+ result = arch_encode_feature(argv[1] + 2, &features);
+ if (result < 0) {
+ arg_error("Invalid feature specified: %s\n",
+ argv[1] + 2);
}
argv++;
argc--;
@@ -18104,7 +18759,7 @@ int main(int argc, char **argv)
arg_error("Wrong argument count %d\n", argc);
}
filename = argv[1];
- compile(filename, ofilename, cpu, debug, optimize, label_prefix);
+ compile(filename, ofilename, features, debug, optimize, label_prefix);
return 0;
}