aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Makefile3
-rw-r--r--flow.h2
-rw-r--r--linearize.c3
-rw-r--r--linearize.h2
-rw-r--r--register.c155
5 files changed, 164 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index b8368ab3..71373bc2 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h \
LIB_OBJS= target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \
expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \
- sort.o flow.o cse.o simplify.o compat-$(OS).o
+ sort.o flow.o cse.o simplify.o register.o compat-$(OS).o
LIB_FILE= sparse.a
LIBS=$(LIB_FILE)
@@ -77,6 +77,7 @@ linearize.o: $(LIB_H)
flow.o: $(LIB_H)
cse.o: $(LIB_H)
simplify.o: $(LIB_H)
+register.o: $(LIB_H)
sort.o: $(LIB_H)
inline.o: $(LIB_H)
target.o: $(LIB_H)
diff --git a/flow.h b/flow.h
index 18ccbd4c..2fb3c088 100644
--- a/flow.h
+++ b/flow.h
@@ -18,4 +18,6 @@ extern void kill_bb(struct basic_block *);
extern void kill_use(pseudo_t *);
extern void kill_instruction(struct instruction *);
+extern void track_pseudo_usage(struct entrypoint *ep);
+
#endif
diff --git a/linearize.c b/linearize.c
index 9fe911d8..62ae8f35 100644
--- a/linearize.c
+++ b/linearize.c
@@ -1770,6 +1770,9 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
/* Cleanup */
clear_symbol_pseudos(ep);
+ /* And track pseudo register usage */
+ track_pseudo_usage(ep);
+
return ep;
}
diff --git a/linearize.h b/linearize.h
index 524c2099..13733963 100644
--- a/linearize.h
+++ b/linearize.h
@@ -23,6 +23,7 @@ struct pseudo {
unsigned int usage:24,
type:8;
struct pseudo_ptr_list *users;
+ struct instruction_list *insns;
union {
struct symbol *sym;
struct instruction *def;
@@ -244,6 +245,7 @@ struct entrypoint {
struct basic_block_list *bbs;
struct basic_block *active;
struct basic_block *entry;
+ struct pseudo_list *pseudos;
};
extern void insert_select(struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t true, pseudo_t false);
diff --git a/register.c b/register.c
new file mode 100644
index 00000000..de902713
--- /dev/null
+++ b/register.c
@@ -0,0 +1,155 @@
+/*
+ * Register - track pseudo usage, maybe eventually try to do register
+ * allocation.
+ *
+ * Copyright (C) 2004 Linus Torvalds
+ */
+
+#include <assert.h>
+
+#include "parse.h"
+#include "expression.h"
+#include "linearize.h"
+#include "flow.h"
+
+static inline int trackable_pseudo(pseudo_t pseudo)
+{
+ return pseudo && (pseudo->type == PSEUDO_REG || pseudo->type == PSEUDO_PHI);
+}
+
+static void insn_uses(struct entrypoint *ep, struct instruction *insn, pseudo_t pseudo)
+{
+ if (trackable_pseudo(pseudo)) {
+ struct instruction *def = pseudo->def;
+#if 1
+ /*
+ * This assert is wrong, since this actually _can_ happen for
+ * truly undefined programs, but it's good for finding bugs.
+ */
+ assert(def && def->bb);
+#else
+ if (!def || !def->bb)
+ warning(insn->bb->pos, "undef pseudo ;(");
+#endif
+ add_instruction(&pseudo->insns, insn);
+ }
+}
+
+static void insn_defines(struct entrypoint *ep, struct instruction *insn, pseudo_t pseudo)
+{
+ assert(trackable_pseudo(pseudo));
+ add_pseudo(&ep->pseudos, pseudo);
+}
+
+static void track_instruction_usage(struct entrypoint *ep, struct instruction *insn)
+{
+ pseudo_t pseudo;
+
+ #define USES(x) insn_uses(ep, insn, insn->x)
+ #define DEFINES(x) insn_defines(ep, insn, insn->x)
+
+ switch (insn->opcode) {
+ case OP_RET:
+ USES(src);
+ break;
+
+ case OP_BR: case OP_SWITCH:
+ USES(cond);
+ break;
+
+ case OP_COMPUTEDGOTO:
+ USES(target);
+
+ /* Binary */
+ case OP_BINARY ... OP_BINARY_END:
+ case OP_BINCMP ... OP_BINCMP_END:
+ USES(src1); USES(src2); DEFINES(target);
+ break;
+
+ /* Uni */
+ case OP_NOT: case OP_NEG:
+ USES(src1); DEFINES(target);
+ break;
+
+ /* Setcc - always in combination with a select or conditional branch */
+ case OP_SETCC:
+ USES(src);
+ break;
+
+ case OP_SEL:
+ USES(src1); USES(src2); DEFINES(target);
+ break;
+
+ /* Memory */
+ case OP_LOAD:
+ USES(src); DEFINES(target);
+ break;
+
+ case OP_STORE:
+ USES(src); USES(target);
+ break;
+
+ case OP_SETVAL:
+ USES(symbol); DEFINES(target);
+ break;
+
+ /* Other */
+ case OP_PHI:
+ DEFINES(target);
+ FOR_EACH_PTR(insn->phi_list, pseudo) {
+ insn_uses(ep, insn, pseudo);
+ } END_FOR_EACH_PTR(pseudo);
+ break;
+
+ case OP_PHISOURCE:
+ USES(src1); DEFINES(target);
+ break;
+
+ case OP_CAST:
+ USES(src); DEFINES(target);
+ break;
+
+ case OP_CALL:
+ USES(func);
+ if (insn->target != VOID)
+ DEFINES(target);
+ FOR_EACH_PTR(insn->arguments, pseudo) {
+ insn_uses(ep, insn, pseudo);
+ } END_FOR_EACH_PTR(pseudo);
+ break;
+
+ case OP_SLICE:
+ USES(base); DEFINES(target);
+ break;
+
+ case OP_BADOP:
+ case OP_INVOKE:
+ case OP_UNWIND:
+ case OP_MALLOC:
+ case OP_FREE:
+ case OP_ALLOCA:
+ case OP_GET_ELEMENT_PTR:
+ case OP_VANEXT:
+ case OP_VAARG:
+ case OP_SNOP:
+ case OP_LNOP:
+ case OP_NOP:
+ case OP_CONTEXT:
+ break;
+ }
+}
+
+void track_pseudo_usage(struct entrypoint *ep)
+{
+ struct basic_block *bb;
+
+ FOR_EACH_PTR(ep->bbs, bb) {
+ struct instruction *insn;
+ FOR_EACH_PTR(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
+ assert(insn->bb == bb);
+ track_instruction_usage(ep, insn);
+ } END_FOR_EACH_PTR(insn);
+ } END_FOR_EACH_PTR(bb);
+}