#undef RELEASE_DATE
#undef VERSION
#define VERSION_MAJOR "0"
-#define VERSION_MINOR "68"
-#define RELEASE_DATE "15 November 2004"
+#define VERSION_MINOR "71"
+#define RELEASE_DATE "03 April 2009"
#define VERSION VERSION_MAJOR "." VERSION_MINOR
#include <stdarg.h>
#define MAX_CWD_SIZE 4096
#define MAX_ALLOCATION_PASSES 100
+/* NOTE: Before you even start thinking to touch anything
+ * in this code, set DEBUG_ROMCC_WARNINGS to 1 to get an
+ * insight on the original author's thoughts. We introduced
+ * this switch as romcc was about the only thing producing
+ * massive warnings in our code..
+ */
+#define DEBUG_ROMCC_WARNINGS 0
+
#define DEBUG_CONSISTENCY 1
#define DEBUG_SDP_BLOCKS 0
#define DEBUG_TRIPLE_COLOR 0
#define DEBUG_EXPLICIT_CLOSURES 0
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME give clear error messages about unused variables"
#warning "FIXME properly handle multi dimensional arrays"
#warning "FIXME handle multiple register sizes"
+#endif
/* Control flow graph of a loop without goto.
*
static char *slurp_file(const char *dirname, const char *filename, off_t *r_size)
{
char cwd[MAX_CWD_SIZE];
- int fd;
char *buf;
off_t size, progress;
ssize_t result;
- struct stat stats;
+ FILE* file;
if (!filename) {
*r_size = 0;
die("cwd buffer to small");
}
xchdir(dirname);
- fd = open(filename, O_RDONLY);
+ file = fopen(filename, "rb");
xchdir(cwd);
- if (fd < 0) {
+ if (file == NULL) {
die("Cannot open '%s' : %s\n",
filename, strerror(errno));
}
- result = fstat(fd, &stats);
- if (result < 0) {
- die("Cannot stat: %s: %s\n",
- filename, strerror(errno));
- }
- size = stats.st_size;
+ fseek(file, 0, SEEK_END);
+ size = ftell(file);
+ fseek(file, 0, SEEK_SET);
*r_size = size +1;
buf = xmalloc(size +2, filename);
buf[size] = '\n'; /* Make certain the file is newline terminated */
buf[size+1] = '\0'; /* Null terminate the file for good measure */
progress = 0;
while(progress < size) {
- result = read(fd, buf + progress, size - progress);
+ result = fread(buf + progress, 1, size - progress, file);
if (result < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
}
progress += result;
}
- result = close(fd);
- if (result < 0) {
- die("Close of %s failed: %s\n",
- filename, strerror(errno));
- }
+ fclose(file);
return buf;
}
/* Types on the destination platform */
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME this assumes 32bit x86 is the destination"
+#endif
typedef int8_t schar_t;
typedef uint8_t uchar_t;
typedef int8_t char_t;
typedef int32_t int_t;
typedef uint32_t uint_t;
typedef int32_t long_t;
-typedef uint32_t ulong_t;
+#define ulong_t uint32_t
#define SCHAR_T_MIN (-128)
#define SCHAR_T_MAX 127
[OP_ADDRCONST ] = OP( 0, 0, 1, 0, PURE | DEF, "addrconst"),
[OP_UNKNOWNVAL ] = OP( 0, 0, 0, 0, PURE | DEF, "unknown"),
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME is it correct for OP_WRITE to be a def? I currently use it as one..."
+#endif
[OP_WRITE ] = OP( 0, 1, 1, 0, PURE | DEF | BLOCK, "write"),
[OP_READ ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "read"),
[OP_COPY ] = OP( 0, 1, 0, 0, PURE | DEF | BLOCK, "copy"),
state->file->report_name, state->file->report_line, col);
}
-static void internal_error(struct compile_state *state, struct triple *ptr,
+static void __attribute__ ((noreturn)) internal_error(struct compile_state *state, struct triple *ptr,
const char *fmt, ...)
{
FILE *fp = state->errout;
-static void error(struct compile_state *state, struct triple *ptr,
+static void __attribute__ ((noreturn)) error(struct compile_state *state, struct triple *ptr,
const char *fmt, ...)
{
FILE *fp = state->errout;
valid_op(state, ptr->op);
}
+#if DEBUG_ROMCC_WARNING
static void valid_param_count(struct compile_state *state, struct triple *ins)
{
int lhs, rhs, misc, targ;
internal_error(state, ins, "Bad targ count");
}
}
+#endif
static struct type void_type;
static struct type unknown_type;
/* Is this triple a return instruction? */
return triple_is_branch_type(state, ins, RETBRANCH);
}
-
+
+#if DEBUG_ROMCC_WARNING
static int triple_is_simple_ubranch(struct compile_state *state, struct triple *ins)
{
/* Is this triple an unconditional branch and not a call or a
* return? */
return triple_is_branch_type(state, ins, UBRANCH);
}
+#endif
static int triple_is_end(struct compile_state *state, struct triple *ins)
{
struct triple **param;
int size, i;
verify_use(state, user, used);
+
+#if DEBUG_ROMCC_WARNINGS
#warning "AUDIT ME ->rhs"
+#endif
size = user->rhs;
param = &RHS(user, 0);
for(i = 0; i < size; i++) {
tm = localtime(&now);
register_builtin_macro(state, "__ROMCC__", VERSION_MAJOR);
+ register_builtin_macro(state, "__PRE_RAM__", VERSION_MAJOR);
register_builtin_macro(state, "__ROMCC_MINOR__", VERSION_MINOR);
register_builtin_macro(state, "__FILE__", "\"This should be the filename\"");
register_builtin_macro(state, "__LINE__", "54321");
}
/* Is this an escaped newline? */
if (file->join_lines &&
- (c == '\\') && (pos + size < end) && (pos[1] == '\n'))
+ (c == '\\') && (pos + size < end) && ((pos[1] == '\n') || ((pos[1] == '\r') && (pos[2] == '\n'))))
{
+ int cr_offset = ((pos[1] == '\r') && (pos[2] == '\n'))?1:0;
/* At the start of a line just eat it */
if (pos == file->pos) {
file->line++;
file->report_line++;
- file->line_start = pos + size + 1;
+ file->line_start = pos + size + 1 + cr_offset;
}
- pos += size + 1;
+ pos += size + 1 + cr_offset;
}
/* Do I need to ga any farther? */
else if (index == 0) {
tok = TOK_SPACE;
tokp = next_char(file, tokp, 1);
while((c = get_char(file, tokp)) != -1) {
- tokp = next_char(file, tokp, 1);
+ /* Advance to the next character only after we verify
+ * the current character is not a newline.
+ * EOL is special to the preprocessor so we don't
+ * want to loose any.
+ */
if (c == '\n') {
break;
}
+ tokp = next_char(file, tokp, 1);
}
}
/* Comments */
struct macro_arg_value {
struct hash_entry *ident;
- unsigned char *value;
+ char *value;
size_t len;
};
static struct macro_arg_value *read_macro_args(
len = char_strlen(file, start, file->pos);
argv[i].value = xrealloc(
argv[i].value, argv[i].len + len, "macro args");
- char_strcpy(argv[i].value + argv[i].len, file, start, file->pos);
+ char_strcpy((char *)argv[i].value + argv[i].len, file, start, file->pos);
argv[i].len += len;
}
if (i != macro->argc -1) {
fmacro.prev = 0;
fmacro.basename = argv[i].ident->name;
fmacro.dirname = "";
- fmacro.buf = argv[i].value;
+ fmacro.buf = (char *)argv[i].value;
fmacro.size = argv[i].len;
fmacro.pos = fmacro.buf;
fmacro.line = 1;
if (getcwd(cwd, sizeof(cwd)) == 0) {
die("cwd buffer to small");
}
- if (subdir[0] == '/') {
+ if ((subdir[0] == '/') || ((subdir[1] == ':') && ((subdir[2] == '/') || (subdir[2] == '\\')))) {
file->dirname = xmalloc(subdir_len + 1, "dirname");
memcpy(file->dirname, subdir, subdir_len);
file->dirname[subdir_len] = '\0';
name = 0;
pp_eat(state, TOK_MINCLUDE);
+ if (if_eat(state)) {
+ /* Find the end of the line */
+ while((tok = raw_peek(state)) != TOK_EOL) {
+ raw_eat(state, tok);
+ }
+ break;
+ }
tok = peek(state);
if (tok == TOK_LIT_STRING) {
struct token *tk;
static inline ulong_t mask_uint(ulong_t x)
{
if (SIZEOF_INT < SIZEOF_LONG) {
- ulong_t mask = (((ulong_t)1) << ((ulong_t)(SIZEOF_INT))) -1;
+ ulong_t mask = (1ULL << ((ulong_t)(SIZEOF_INT))) -1;
x &= mask;
}
return x;
static struct type void_type = { .type = TYPE_VOID };
static struct type char_type = { .type = TYPE_CHAR };
static struct type uchar_type = { .type = TYPE_UCHAR };
+#if DEBUG_ROMCC_WARNING
static struct type short_type = { .type = TYPE_SHORT };
+#endif
static struct type ushort_type = { .type = TYPE_USHORT };
static struct type int_type = { .type = TYPE_INT };
static struct type uint_type = { .type = TYPE_UINT };
.left = &void_type,
};
+#if DEBUG_ROMCC_WARNING
static struct type void_func_type = {
.type = TYPE_FUNCTION,
.left = &void_type,
.right = &void_type,
};
+#endif
static size_t bits_to_bytes(size_t size)
{
if (!def) {
return 0;
}
+#if DEBUG_ROMCC_WARNINGS
#warning "CHECK_ME is this the only place I need to do lvalue conversions?"
+#endif
/* Transform lvalues into something we can read */
def = lvalue_conversion(state, def);
if (!is_lvalue(state, def)) {
static int expr_depth(struct compile_state *state, struct triple *ins)
{
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME move optimal ordering of subexpressions into the optimizer"
+#endif
int count;
count = 0;
if (!ins || (ins->id & TRIPLE_FLAG_FLATTENED)) {
return is_simple_const(ins) && (ins->u.cval == 1);
}
+#if DEBUG_ROMCC_WARNING
static long_t bit_count(ulong_t value)
{
int count;
return count;
}
+#endif
+
static long_t bsr(ulong_t value)
{
int i;
}
}
+#if DEBUG_ROMCC_WARNING
static void unuse_misc(struct compile_state *state, struct triple *ins)
{
struct triple **expr;
}
}
+#endif
static void check_misc(struct compile_state *state, struct triple *ins)
{
ins->targ = 0;
}
+#if DEBUG_ROMCC_WARNING
static void wipe_branch(struct compile_state *state, struct triple *ins)
{
/* Becareful which instructions you replace the wiped
ins->misc = 0;
ins->targ = 0;
}
+#endif
static void mkcopy(struct compile_state *state,
struct triple *ins, struct triple *rhs)
struct hash_entry **ident, int need_ident);
static void decl(struct compile_state *state, struct triple *first);
static struct type *specifier_qualifier_list(struct compile_state *state);
+#if DEBUG_ROMCC_WARNING
static int isdecl_specifier(int tok);
+#endif
static struct type *decl_specifiers(struct compile_state *state);
static int istype(int tok);
static struct triple *expr(struct compile_state *state);
int c;
int str_len;
tk = eat(state, TOK_LIT_CHAR);
- str = tk->val.str + 1;
+ str = (signed char *)tk->val.str + 1;
str_len = tk->str_len - 2;
if (str_len <= 0) {
error(state, 0, "empty character constant");
/* The while loop handles string concatenation */
do {
tk = eat(state, TOK_LIT_STRING);
- str = tk->val.str + 1;
+ str = (signed char *)tk->val.str + 1;
str_len = tk->str_len - 2;
if (str_len < 0) {
error(state, 0, "negative string constant length");
static struct triple *relational_expr(struct compile_state *state)
{
+#if DEBUG_ROMCC_WARNINGS
#warning "Extend relational exprs to work on more than arithmetic types"
+#endif
struct triple *def;
int done;
def = shift_expr(state);
static struct triple *equality_expr(struct compile_state *state)
{
+#if DEBUG_ROMCC_WARNINGS
#warning "Extend equality exprs to work on more than arithmetic types"
+#endif
struct triple *def;
int done;
def = relational_expr(state);
int last;
eat(state, TOK_RETURN);
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME implement a more general excess branch elimination"
+#endif
val = 0;
/* If we have a return value do some more work */
if (peek(state) != TOK_SEMI) {
return type;
}
+#if DEBUG_ROMCC_WARNING
static int isdecl_specifier(int tok)
{
switch(tok) {
return 0;
}
}
+#endif
static struct type *decl_specifiers(struct compile_state *state)
{
struct compile_state *state, struct type *type)
{
struct triple *result;
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME more consistent initializer handling (where should eval_const_expr go?"
+#endif
if (peek(state) != TOK_LBRACE) {
result = assignment_expr(state);
if (((type->type & TYPE_MASK) == TYPE_ARRAY) &&
struct compile_state *state, struct basic_blocks *bb);
static void free_variable_lifetimes(struct compile_state *state,
struct basic_blocks *bb, struct reg_block *blocks);
+#if DEBUG_EXPLICIT_CLOSURES
static void print_live_variables(struct compile_state *state,
struct basic_blocks *bb, struct reg_block *rb, FILE *fp);
+#endif
static struct triple *call(struct compile_state *state,
}
}
memset(block, -1, sizeof(*block));
+#ifndef WIN32
xfree(block);
+#endif
}
static void free_basic_blocks(struct compile_state *state,
{
return do_triple_set(&rb->in, in, 0);
}
+
+#if DEBUG_ROMCC_WARNING
static void unin_triple(struct reg_block *rb, struct triple *unin)
{
do_triple_unset(&rb->in, unin);
}
+#endif
static int out_triple(struct reg_block *rb, struct triple *out)
{
return do_triple_set(&rb->out, out, 0);
}
+#if DEBUG_ROMCC_WARNING
static void unout_triple(struct reg_block *rb, struct triple *unout)
{
do_triple_unset(&rb->out, unout);
}
+#endif
static int initialize_regblock(struct reg_block *blocks,
struct block *block, int vertex)
/* Find the variables we use but don't define and add
* it to the current blocks input set.
*/
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME is this O(N^2) algorithm bad?"
+#endif
struct block *block;
struct triple *ptr;
int done;
struct reg_block *rb;
FILE *fp;
};
+#if DEBUG_EXPLICIT_CLOSURES
static void print_live_variables_block(
struct compile_state *state, struct block *block, void *arg)
walk_blocks(state, bb, print_live_variables_block, &info);
}
-
+#endif
static int count_triples(struct compile_state *state)
{
struct triple *last;
last = user->member->last;
while((last->op == OP_NOOP) && (last != user->member->first)) {
- internal_warning(state, last, "awakening noop?");
+#if DEBUG_ROMCC_WARNINGS
+#warning "Should we bring the awakening noops back?"
+#endif
+ // internal_warning(state, last, "awakening noop?");
last = last->prev;
}
awaken(state, dtriple, &last, &work_list_tail);
*
*/
+#if DEBUG_ROMCC_WARNING
static void different_colored(
struct compile_state *state, struct reg_state *rstate,
struct triple *parent, struct triple *ins)
}
}
}
-
+#endif
static struct live_range *coalesce_ranges(
struct compile_state *state, struct reg_state *rstate,
#endif
/* Append lr2 onto lr1 */
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME should this be a merge instead of a splice?"
+#endif
/* This FIXME item applies to the correctness of live_range_end
* and to the necessity of making multiple passes of coalesce_live_ranges.
* A failure to find some coalesce opportunities in coaleace_live_ranges
return;
}
+#if DEBUG_CONSISTENCY > 1
static struct live_range *get_verify_live_range(
struct compile_state *state, struct reg_state *rstate, struct triple *ins)
{
}
return;
}
-
+#endif
static void print_interference_ins(
struct compile_state *state,
struct reg_block *blocks, struct triple *orig, struct triple *new)
{
int i;
+#if DEBUG_ROMCC_WARNINGS
#warning "WISHLIST visit just those blocks that need it *"
+#endif
for(i = 1; i <= state->bb.last_vertex; i++) {
struct reg_block *rb;
rb = &blocks[i];
struct triple_set *set, *next;
struct triple *copy;
+#if DEBUG_ROMCC_WARNINGS
#warning "WISHLIST recalculate all affected instructions colors"
+#endif
info = find_lhs_color(state, tangle, 0);
for(set = tangle->use; set; set = next) {
struct triple *user;
* Then a triple is not constrained.
* FIXME handle this case!
*/
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME ignore cases that cannot be fixed (a definition followed by a use)"
+#endif
/* Of the constrained live ranges deal with the
for(edge = range->edges; edge; edge = edge->next) {
constrained = find_constrained_def(state, edge->node, constrained);
}
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME should I call find_constrained_def here only if no previous constrained def was found?"
+#endif
if (!constrained) {
constrained = find_constrained_def(state, range, constrained);
}
* it would be useful to have.
*
*/
+#if DEBUG_ROMCC_WARNINGS
#warning "WISHLIST implement live range splitting..."
+#endif
if (!split && (state->compiler->debug & DEBUG_RANGE_CONFLICTS2)) {
FILE *fp = state->errout;
struct ssa_edge *sedge)
{
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(state->errout, "adding sedge: %5d (%4d -> %5d)\n",
- sedge - scc->ssa_edges,
+ fprintf(state->errout, "adding sedge: %5ld (%4d -> %5d)\n",
+ (long)(sedge - scc->ssa_edges),
sedge->src->def->id,
sedge->dst->def->id);
}
(sedge->work_prev != sedge)) {
if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
- fprintf(state->errout, "dupped sedge: %5d\n",
- sedge - scc->ssa_edges);
+ fprintf(state->errout, "dupped sedge: %5ld\n",
+ (long)(sedge - scc->ssa_edges));
}
return;
}
scratch->next = lnode->def->next;
}
/* Recompute the value */
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME see if simplify does anything bad"
+#endif
/* So far it looks like only the strength reduction
* optimization are things I need to worry about.
*/
(( !triple_is_def(state, lnode->def) &&
!triple_is_cbranch(state, lnode->def)) ||
(lnode->def->op == OP_PIECE))) {
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME constant propogate through expressions with multiple left hand sides"
+#endif
if (changed) {
internal_warning(state, lnode->def, "non def changes value?");
}
fblock = lnode->fblock;
if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
- fprintf(state->errout, "sedge: %5d (%5d -> %5d)\n",
+ fprintf(state->errout, "sedge: %5ld (%5d -> %5d)\n",
sedge - scc.ssa_edges,
sedge->src->def->id,
sedge->dst->def->id);
/* Propogate constants throughout the code */
scc_transform(state);
verify_consistency(state);
+#if DEBUG_ROMCC_WARNINGS
#warning "WISHLIST implement single use constants (least possible register pressure)"
#warning "WISHLIST implement induction variable elimination"
+#endif
/* Select architecture instructions and an initial partial
* coloring based on architecture constraints.
*/
#define REG_XMM7 44
#define REGC_XMM_FIRST REG_XMM0
#define REGC_XMM_LAST REG_XMM7
+
+#if DEBUG_ROMCC_WARNINGS
#warning "WISHLIST figure out how to use pinsrw and pextrw to better use extended regs"
+#endif
+
#define LAST_REG REG_XMM7
#define REGC_GPR32_8_FIRST REG_EAX
static unsigned arch_type_to_regcm(struct compile_state *state, struct type *type)
{
+
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME force types smaller (if legal) before I get here"
+#endif
unsigned mask;
mask = 0;
switch(type->type & TYPE_MASK) {
long ref;
ref = next_label(state);
fprintf(fp, ".section \"" DATA_SECTION "\"\n");
- fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
+ fprintf(fp, ".balign %ld\n", (long int)align_of_in_bytes(state, ins->type));
fprintf(fp, "L%s%lu:\n", state->compiler->label_prefix, ref);
print_const(state, ins, fp);
fill_bytes = bits_to_bytes(size - size_of(state, ins->type));
if (fill_bytes) {
- fprintf(fp, ".fill %d, 1, 0\n", fill_bytes);
+ fprintf(fp, ".fill %ld, 1, 0\n", (long int)fill_bytes);
}
fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
return ref;
(RHS(branch, 0)->op != OP_TEST)) {
internal_error(state, branch, "bad branch test");
}
+#if DEBUG_ROMCC_WARNINGS
#warning "FIXME I have observed instructions between the test and branch instructions"
+#endif
ptr = RHS(branch, 0);
for(ptr = RHS(branch, 0)->next; ptr != branch; ptr = ptr->next) {
if (ptr->op != OP_COPY) {
struct triple *ins, FILE *fp)
{
fprintf(fp, ".section \"" DATA_SECTION "\"\n");
- fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
+ fprintf(fp, ".balign %ld\n", (long int)align_of_in_bytes(state, ins->type));
fprintf(fp, "L%s%lu:\n",
state->compiler->label_prefix, (unsigned long)(ins->u.cval));
print_const(state, MISC(ins, 0), fp);
last_occurance != ins->occurance) {
if (!ins->occurance->parent) {
fprintf(fp, "\t/* %s,%s:%d.%d */\n",
- ins->occurance->function,
- ins->occurance->filename,
+ ins->occurance->function?ins->occurance->function:"(null)",
+ ins->occurance->filename?ins->occurance->filename:"(null)",
ins->occurance->line,
ins->occurance->col);
}
}
}
-static void compile(const char *filename,
+static void compile(const char *filename, const char *includefile,
struct compiler_state *compiler, struct arch_state *arch)
{
int i;
/* Enter the globl definition scope */
start_scope(&state);
register_builtins(&state);
+
compile_file(&state, filename, 1);
+ if (includefile)
+ compile_file(&state, includefile, 1);
/* Stop if all we want is preprocessor output */
if (state.compiler->flags & COMPILER_PP_ONLY) {
int main(int argc, char **argv)
{
const char *filename;
+ const char *includefile = NULL;
struct compiler_state compiler;
struct arch_state arch;
int all_opts;
else if (strncmp(argv[1], "-m", 2) == 0) {
result = arch_encode_flag(&arch, argv[1]+2);
}
+ else if (strncmp(argv[1], "-include", 10) == 0) {
+ if (includefile) {
+ arg_error("Only one -include option may be specified.\n");
+ } else {
+ argv++;
+ argc--;
+ includefile = argv[1];
+ result = 0;
+ }
+ }
if (result < 0) {
arg_error("Invalid option specified: %s\n",
argv[1]);
if (!filename) {
arg_error("No filename specified\n");
}
- compile(filename, &compiler, &arch);
+ compile(filename, includefile, &compiler, &arch);
return 0;
}